This is an automated email from the ASF dual-hosted git repository.

He-Pin pushed a commit to branch feat/rfc-10008-query-method
in repository https://gitbox.apache.org/repos/asf/pekko-http.git

commit 6df05df77c86ff61b2a08131b430472758f820b1
Author: 虎鸣 <[email protected]>
AuthorDate: Fri Jun 19 12:51:18 2026 +0800

    feat: add RFC 10008 QUERY method and Accept-Query header support
    
    Motivation:
    RFC 10008 defines the HTTP QUERY method as a safe, idempotent method that
    expects a request body, along with the Accept-Query response header for
    signaling supported query media types. pekko-http should provide first-class
    support for this standard HTTP method.
    
    Modification:
    - Add QUERY method constant to HttpMethods (Scala and Java API)
    - Add Accept-Query modeled response header with MediaRange list
    - Add Accept-Query parser supporting RFC 9651 Structured Fields syntax
      (quoted strings like "application/jsonpath") with q-value stripping
    - Add query routing directive (Scala DSL and Java DSL)
    - Add HttpRequest.QUERY factory method (Java API)
    - Add AcceptQuery Java API abstract class
    - Register accept-query in HeaderParser dispatch
    - Add documentation page for query directive with Scala/Java examples
    - Add directional tests: method lookup, header parsing (token, quoted
      string, wildcard, q-value stripping), directive routing
    
    Result:
    Downstream consumers can implement RFC 10008 QUERY method support using
    built-in constants, headers, parsing, and routing directives.
    
    Tests:
    - sbt "http-core / Test / testOnly 
org.apache.pekko.http.scaladsl.model.HttpMethodsSpec" → 6 passed
    - sbt "http-core / Test / testOnly 
org.apache.pekko.http.impl.model.parser.HttpHeaderSpec" → 75 passed
    - sbt "http-core / Test / testOnly 
org.apache.pekko.http.scaladsl.model.headers.HeaderSpec" → 18 passed
    - sbt "http-tests / Test / testOnly 
org.apache.pekko.http.scaladsl.server.directives.MethodDirectivesSpec" → 14 
passed
    - sbt "docs / Test / testOnly 
docs.http.scaladsl.server.directives.MethodDirectivesExamplesSpec 
docs.http.javadsl.server.directives.MethodDirectivesExamplesTest" → 11 passed
    - sbt "http-core / mimaReportBinaryIssues" → success
    - sbt "http / mimaReportBinaryIssues" → success
    
    References:
    Refs https://github.com/netty/netty/pull/16978, 
https://www.rfc-editor.org/rfc/rfc10008
---
 .../directives/method-directives/index.md          |  1 +
 .../directives/method-directives/query.md          | 31 +++++++++++++++++++
 .../directives/MethodDirectivesExamplesTest.java   | 16 ++++++++++
 .../directives/MethodDirectivesExamplesSpec.scala  | 11 +++++++
 .../pekko/http/javadsl/model/HttpMethods.java      |  1 +
 .../pekko/http/javadsl/model/HttpRequest.java      |  5 +++
 .../http/javadsl/model/headers/AcceptQuery.java    | 27 ++++++++++++++++
 .../http/impl/model/parser/AcceptHeader.scala      | 36 ++++++++++++++++++++++
 .../http/impl/model/parser/HeaderParser.scala      |  1 +
 .../pekko/http/scaladsl/model/HttpMethod.scala     |  1 +
 .../http/scaladsl/model/headers/headers.scala      | 16 ++++++++++
 .../http/impl/model/parser/HttpHeaderSpec.scala    | 33 ++++++++++++++++++++
 .../http/scaladsl/model/HttpMethodsSpec.scala      |  3 ++
 .../http/scaladsl/model/headers/HeaderSpec.scala   |  1 +
 .../server/directives/MethodDirectivesSpec.scala   | 13 +++++++-
 .../server/directives/MethodDirectives.scala       |  4 +++
 .../server/directives/MethodDirectives.scala       |  8 +++++
 17 files changed, 207 insertions(+), 1 deletion(-)

diff --git 
a/docs/src/main/paradox/routing-dsl/directives/method-directives/index.md 
b/docs/src/main/paradox/routing-dsl/directives/method-directives/index.md
index 3b12d24ec..a809bb4c1 100644
--- a/docs/src/main/paradox/routing-dsl/directives/method-directives/index.md
+++ b/docs/src/main/paradox/routing-dsl/directives/method-directives/index.md
@@ -14,5 +14,6 @@
 * [patch](patch.md)
 * [post](post.md)
 * [put](put.md)
+* [query](query.md)
 
 @@@
\ No newline at end of file
diff --git 
a/docs/src/main/paradox/routing-dsl/directives/method-directives/query.md 
b/docs/src/main/paradox/routing-dsl/directives/method-directives/query.md
new file mode 100644
index 000000000..839837ca6
--- /dev/null
+++ b/docs/src/main/paradox/routing-dsl/directives/method-directives/query.md
@@ -0,0 +1,31 @@
+# query
+
+Matches requests with HTTP method `QUERY` (RFC 10008).
+
+@@@ div { .group-scala }
+
+## Signature
+
+@@signature 
[MethodDirectives.scala](/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectives.scala)
 { #query }
+
+@@@
+
+## Description
+
+This directive filters the incoming request by its HTTP method. Only requests 
with
+method `QUERY` are passed on to the inner route. All others are rejected with a
+@apidoc[MethodRejection], which is translated into a `405 Method Not Allowed` 
response
+by the default 
@ref[RejectionHandler](../../rejections.md#the-rejectionhandler).
+
+The `QUERY` method is defined in [RFC 
10008](https://www.rfc-editor.org/rfc/rfc10008).
+It is a safe and idempotent method that requests the target resource to 
process the
+enclosed content and respond with the result. Unlike `GET`, the `QUERY` method 
expects
+a request body containing the query payload.
+
+## Example
+
+Scala
+:  @@snip 
[MethodDirectivesExamplesSpec.scala](/docs/src/test/scala/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala)
 { #query-method }
+
+Java
+:  @@snip 
[MethodDirectivesExamplesTest.java](/docs/src/test/java/docs/http/javadsl/server/directives/MethodDirectivesExamplesTest.java)
 { #query }
diff --git 
a/docs/src/test/java/docs/http/javadsl/server/directives/MethodDirectivesExamplesTest.java
 
b/docs/src/test/java/docs/http/javadsl/server/directives/MethodDirectivesExamplesTest.java
index 3c577f34f..5090d2f5a 100644
--- 
a/docs/src/test/java/docs/http/javadsl/server/directives/MethodDirectivesExamplesTest.java
+++ 
b/docs/src/test/java/docs/http/javadsl/server/directives/MethodDirectivesExamplesTest.java
@@ -51,6 +51,11 @@ import static 
org.apache.pekko.http.javadsl.server.Directives.complete;
 import static org.apache.pekko.http.javadsl.server.Directives.put;
 
 // #put
+// #query
+import static org.apache.pekko.http.javadsl.server.Directives.complete;
+import static org.apache.pekko.http.javadsl.server.Directives.query;
+
+// #query
 // #method-example
 import static org.apache.pekko.http.javadsl.server.Directives.complete;
 import static org.apache.pekko.http.javadsl.server.Directives.method;
@@ -140,6 +145,17 @@ public class MethodDirectivesExamplesTest extends 
JUnitJupiterRouteTest {
     // #put
   }
 
+  @Test
+  public void testQuery() {
+    // #query
+    final Route route = query(() -> complete("This is a QUERY request."));
+
+    testRoute(route)
+        .run(HttpRequest.QUERY("/").withEntity("query content"))
+        .assertEntity("This is a QUERY request.");
+    // #query
+  }
+
   @Test
   public void testMethodExample() {
     // #method-example
diff --git 
a/docs/src/test/scala/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala
 
b/docs/src/test/scala/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala
index cb03e4f96..c2a256568 100644
--- 
a/docs/src/test/scala/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala
+++ 
b/docs/src/test/scala/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala
@@ -98,6 +98,17 @@ class MethodDirectivesExamplesSpec extends RoutingSpec with 
CompileOnlySpec {
     // #put-method
   }
 
+  "query-method" in {
+    // #query-method
+    val route = query { complete("This is a QUERY request.") }
+
+    // tests:
+    HttpRequest(method = HttpMethods.QUERY, uri = "/") ~> route ~> check {
+      responseAs[String] shouldEqual "This is a QUERY request."
+    }
+    // #query-method
+  }
+
   "method-example" in {
     // #method-example
     val route = method(HttpMethods.PUT) { complete("This is a PUT request.") }
diff --git 
a/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpMethods.java 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpMethods.java
index b39bdf846..73f898214 100644
--- 
a/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpMethods.java
+++ 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpMethods.java
@@ -31,6 +31,7 @@ public final class HttpMethods {
   public static final HttpMethod PATCH = 
org.apache.pekko.http.scaladsl.model.HttpMethods.PATCH();
   public static final HttpMethod POST = 
org.apache.pekko.http.scaladsl.model.HttpMethods.POST();
   public static final HttpMethod PUT = 
org.apache.pekko.http.scaladsl.model.HttpMethods.PUT();
+  public static final HttpMethod QUERY = 
org.apache.pekko.http.scaladsl.model.HttpMethods.QUERY();
   public static final HttpMethod TRACE = 
org.apache.pekko.http.scaladsl.model.HttpMethods.TRACE();
 
   /**
diff --git 
a/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpRequest.java 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpRequest.java
index 8d82d87c9..b5b3d0f22 100644
--- 
a/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpRequest.java
+++ 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/HttpRequest.java
@@ -83,4 +83,9 @@ public abstract class HttpRequest
   public static HttpRequest OPTIONS(String uri) {
     return create(uri).withMethod(HttpMethods.OPTIONS);
   }
+
+  /** A default QUERY request to be modified using the `withX` methods. */
+  public static HttpRequest QUERY(String uri) {
+    return create(uri).withMethod(HttpMethods.QUERY);
+  }
 }
diff --git 
a/http-core/src/main/java/org/apache/pekko/http/javadsl/model/headers/AcceptQuery.java
 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/headers/AcceptQuery.java
new file mode 100644
index 000000000..50daf185d
--- /dev/null
+++ 
b/http-core/src/main/java/org/apache/pekko/http/javadsl/model/headers/AcceptQuery.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * license agreements; and to You under the Apache License, version 2.0:
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * This file is part of the Apache Pekko project, which was derived from Akka.
+ */
+
+package org.apache.pekko.http.javadsl.model.headers;
+
+import org.apache.pekko.http.impl.util.Util;
+import org.apache.pekko.http.javadsl.model.MediaRange;
+
+/**
+ * Model for the `Accept-Query` header. Specification:
+ * https://www.rfc-editor.org/rfc/rfc10008.html#section-4.1
+ */
+public abstract class AcceptQuery extends 
org.apache.pekko.http.scaladsl.model.HttpHeader {
+  public abstract Iterable<MediaRange> getMediaRanges();
+
+  public static AcceptQuery create(MediaRange... mediaRanges) {
+    return new org.apache.pekko.http.scaladsl.model.headers.Accept$minusQuery(
+        Util.<MediaRange, 
org.apache.pekko.http.scaladsl.model.MediaRange>convertArray(
+            mediaRanges));
+  }
+}
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/AcceptHeader.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/AcceptHeader.scala
index c38f79aa2..03c9ae6cc 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/AcceptHeader.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/AcceptHeader.scala
@@ -29,6 +29,42 @@ private[parser] trait AcceptHeader { this: Parser with 
CommonRules with CommonAc
     zeroOrMore(`media-range-decl`).separatedBy(listSep) ~ EOI ~> (Accept(_))
   }
 
+  // https://www.rfc-editor.org/rfc/rfc10008.html#section-4.1
+  // Accept-Query uses Structured Fields syntax (RFC 9651): media types may 
appear
+  // as tokens (application/json) or quoted strings ("application/jsonpath").
+  // Unlike Accept, q-values are not meaningful and are stripped if present.
+  def `accept-query` = rule {
+    zeroOrMore(`accept-query-media-range-decl`).separatedBy(listSep) ~ EOI ~> 
(`Accept-Query`(_))
+  }
+
+  def `accept-query-media-range-decl` = rule {
+    `accept-query-media-range-def` ~ OWS ~ zeroOrMore(ws(';') ~ parameter) ~> 
{ (main, sub, params) =>
+      val cleanParams = TreeMap(params.filterNot(_._1 == "q"): _*)
+      if (sub == "*") {
+        val mainLower = main.toRootLowerCase
+        MediaRanges.getForKey(mainLower) match {
+          case Some(registered) => if (cleanParams.isEmpty) registered else 
registered.withParams(cleanParams)
+          case None             => MediaRange.custom(mainLower, cleanParams)
+        }
+      } else {
+        MediaRange(getMediaType(main, sub, cleanParams contains "charset", 
cleanParams))
+      }
+    }
+  }
+
+  def `accept-query-media-range-def` = rule {
+    "*/*" ~ push("*") ~ push("*") |
+    '*' ~ push("*") ~ push("*") |
+    `type` ~ '/' ~
+    ('*' ~ !tchar ~ push("*") | subtype) |
+    `quoted-string` ~>
+    ((s: String) => {
+      val slashIdx = s.indexOf('/')
+      if (slashIdx > 0) push(s.substring(0, slashIdx)) ~ 
push(s.substring(slashIdx + 1))
+      else push(s) ~ push("*")
+    })
+  }
+
   def `media-range-decl` = rule {
     `media-range-def` ~ OWS ~ zeroOrMore(ws(';') ~ parameter) ~> { (main, sub, 
params) =>
       if (sub == "*") {
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/HeaderParser.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/HeaderParser.scala
index e82c6aafc..870da7aa7 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/HeaderParser.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/impl/model/parser/HeaderParser.scala
@@ -144,6 +144,7 @@ private[http] object HeaderParser {
     "accept-charset",
     "accept-encoding",
     "accept-language",
+    "accept-query",
     "accept-ranges",
     "access-control-allow-credentials",
     "access-control-allow-headers",
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMethod.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMethod.scala
index a00caae9b..d40798624 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMethod.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMethod.scala
@@ -114,6 +114,7 @@ object HttpMethods extends ObjectRegistry[String, 
HttpMethod] {
   val PATCH   = register(HttpMethod("PATCH"  , isSafe = false, isIdempotent = 
false, requestEntityAcceptance = Expected,   contentLengthAllowed = 
contentLengthAllowedCommon))
   val POST    = register(HttpMethod("POST"   , isSafe = false, isIdempotent = 
false, requestEntityAcceptance = Expected,   contentLengthAllowed = 
contentLengthAllowedCommon))
   val PUT     = register(HttpMethod("PUT"    , isSafe = false, isIdempotent = 
true , requestEntityAcceptance = Expected,   contentLengthAllowed = 
contentLengthAllowedCommon))
+  val QUERY   = register(HttpMethod("QUERY"  , isSafe = true , isIdempotent = 
true , requestEntityAcceptance = Expected,   contentLengthAllowed = 
contentLengthAllowedCommon))
   val TRACE   = register(HttpMethod("TRACE"  , isSafe = true , isIdempotent = 
true , requestEntityAcceptance = Disallowed, contentLengthAllowed = 
contentLengthAllowedCommon))
   // format: ON
 
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/headers/headers.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/headers/headers.scala
index e8c1c716d..b5aa644e3 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/headers/headers.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/headers/headers.scala
@@ -232,6 +232,22 @@ final case class `Accept-Ranges`(rangeUnits: 
immutable.Seq[RangeUnit]) extends j
   def getRangeUnits: Iterable[jm.headers.RangeUnit] = rangeUnits.asJava
 }
 
+// https://www.rfc-editor.org/rfc/rfc10008.html#section-4.1
+object `Accept-Query` extends ModeledCompanion[`Accept-Query`] {
+  def apply(firstMediaRange: MediaRange, otherMediaRanges: MediaRange*): 
`Accept-Query` =
+    apply(firstMediaRange +: otherMediaRanges)
+  implicit val mediaRangesRenderer: Renderer[immutable.Iterable[MediaRange]] = 
Renderer.defaultSeqRenderer[MediaRange] // cache
+}
+final case class `Accept-Query`(mediaRanges: immutable.Seq[MediaRange]) 
extends jm.headers.AcceptQuery
+    with ResponseHeader {
+  import `Accept-Query`.mediaRangesRenderer
+  def renderValue[R <: Rendering](r: R): r.type = r ~~ mediaRanges
+  protected def companion = `Accept-Query`
+
+  /** Java API */
+  def getMediaRanges: Iterable[jm.MediaRange] = mediaRanges.asJava
+}
+
 // https://www.w3.org/TR/cors/#access-control-allow-credentials-response-header
 object `Access-Control-Allow-Credentials` extends 
ModeledCompanion[`Access-Control-Allow-Credentials`]
 final case class `Access-Control-Allow-Credentials`(allow: Boolean)
diff --git 
a/http-core/src/test/scala/org/apache/pekko/http/impl/model/parser/HttpHeaderSpec.scala
 
b/http-core/src/test/scala/org/apache/pekko/http/impl/model/parser/HttpHeaderSpec.scala
index 644d0f075..54caff1c7 100644
--- 
a/http-core/src/test/scala/org/apache/pekko/http/impl/model/parser/HttpHeaderSpec.scala
+++ 
b/http-core/src/test/scala/org/apache/pekko/http/impl/model/parser/HttpHeaderSpec.scala
@@ -120,6 +120,39 @@ class HttpHeaderSpec extends AnyFreeSpec with Matchers {
       "Accept-Ranges: none" =!= `Accept-Ranges`()
     }
 
+    "Accept-Query" in {
+      // basic token form
+      "Accept-Query: application/json" =!= 
`Accept-Query`(MediaTypes.`application/json`)
+      // multiple media ranges
+      "Accept-Query: application/json, text/xml" =!=
+        `Accept-Query`(MediaTypes.`application/json`, MediaTypes.`text/xml`)
+      // full wildcard
+      "Accept-Query: */*" =!= `Accept-Query`(MediaRanges.`*/*`)
+      // type wildcard
+      "Accept-Query: application/*" =!= 
`Accept-Query`(MediaRanges.`application/*`)
+      // RFC 9651 Structured Fields: quoted string form (application/jsonpath 
is not predefined)
+      """Accept-Query: "application/jsonpath"""" =!=
+        `Accept-Query`(MediaType.customBinary("application", "jsonpath", 
MediaType.Compressible,
+          allowArbitrarySubtypes = true))
+          .renderedTo("application/jsonpath")
+      // RFC 10008 Section 3.2 example: mixed token and quoted-string forms 
with parameters
+      """Accept-Query: "application/jsonpath", 
application/sql;charset="UTF-8"""" =!=
+        `Accept-Query`(
+          MediaType.customBinary("application", "jsonpath", 
MediaType.Compressible,
+            allowArbitrarySubtypes = true),
+          MediaType.customBinary("application", "sql", MediaType.Compressible,
+            params = Map("charset" -> "UTF-8"), allowArbitrarySubtypes = true))
+          .renderedTo("application/jsonpath, application/sql; charset=UTF-8")
+      // q-values are not meaningful for Accept-Query (RFC 10008) and must be 
stripped
+      "Accept-Query: application/json;q=0.8" =!=
+        `Accept-Query`(MediaTypes.`application/json`)
+          .renderedTo("application/json")
+      // q-values stripped even with other parameters preserved
+      "Accept-Query: application/json;charset=utf-8;q=0.5" =!=
+        `Accept-Query`(MediaTypes.`application/json`.withParams(Map("charset" 
-> "utf-8")))
+          .renderedTo("application/json; charset=utf-8")
+    }
+
     "Accept-Encoding" in {
       "Accept-Encoding: compress, gzip, fancy" =!=
         `Accept-Encoding`(compress, gzip, HttpEncoding.custom("fancy"))
diff --git 
a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/HttpMethodsSpec.scala
 
b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/HttpMethodsSpec.scala
index 16a198e8d..873860baa 100644
--- 
a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/HttpMethodsSpec.scala
+++ 
b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/HttpMethodsSpec.scala
@@ -32,5 +32,8 @@ class HttpMethodsSpec extends AnyWordSpec {
     "return HttpMethods.OPTIONS" in {
       assert(HttpMethods.getForKeyCaseInsensitive("oPtIoNs") == 
Option(HttpMethods.OPTIONS))
     }
+    "return HttpMethods.QUERY" in {
+      assert(HttpMethods.getForKeyCaseInsensitive("query") == 
Option(HttpMethods.QUERY))
+    }
   }
 }
diff --git 
a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/headers/HeaderSpec.scala
 
b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/headers/HeaderSpec.scala
index 73424fbb7..f5af11aff 100644
--- 
a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/headers/HeaderSpec.scala
+++ 
b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/headers/HeaderSpec.scala
@@ -206,6 +206,7 @@ class HeaderSpec extends AnyFreeSpec with Matchers {
     "render in response" in {
       val responseHeaders = Vector[HttpHeader](
         `Accept-Ranges`(RangeUnits.Bytes),
+        `Accept-Query`(MediaTypes.`application/json`),
         `Access-Control-Allow-Credentials`(true),
         `Access-Control-Allow-Headers`("X-Custom"),
         `Access-Control-Allow-Methods`(HttpMethods.GET),
diff --git 
a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectivesSpec.scala
 
b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectivesSpec.scala
index 3d3d72cae..36956580d 100644
--- 
a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectivesSpec.scala
+++ 
b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectivesSpec.scala
@@ -14,7 +14,7 @@
 package org.apache.pekko.http.scaladsl.server.directives
 
 import org.apache.pekko
-import pekko.http.scaladsl.model.{ ContentTypes, HttpEntity, HttpMethods, 
StatusCodes }
+import pekko.http.scaladsl.model.{ ContentTypes, HttpEntity, HttpMethod, 
HttpMethods, HttpRequest, StatusCodes }
 import pekko.http.scaladsl.server._
 import pekko.stream.scaladsl.Source
 
@@ -53,6 +53,17 @@ class MethodDirectivesSpec extends RoutingSpec {
     }
   }
 
+  "query" should {
+    lazy val queryRoute = query { completeOk }
+
+    "block GET requests" in {
+      Get() ~> queryRoute ~> check { handled shouldEqual false }
+    }
+    "let QUERY requests pass" in {
+      HttpRequest(method = HttpMethods.QUERY) ~> queryRoute ~> check { 
response shouldEqual Ok }
+    }
+  }
+
   "two failed `get` directives" should {
     "only result in a single Rejection" in {
       Put() ~> {
diff --git 
a/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/MethodDirectives.scala
 
b/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/MethodDirectives.scala
index 871d835fa..d5b69f9e3 100644
--- 
a/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/MethodDirectives.scala
+++ 
b/http/src/main/scala/org/apache/pekko/http/javadsl/server/directives/MethodDirectives.scala
@@ -47,6 +47,10 @@ abstract class MethodDirectives extends 
MarshallingDirectives {
     D.put { inner.get.delegate }
   }
 
+  def query(inner: function.Supplier[Route]): Route = RouteAdapter {
+    D.query { inner.get.delegate }
+  }
+
   def extractMethod(inner: function.Function[HttpMethod, Route]) = 
RouteAdapter {
     D.extractMethod { m =>
       inner.apply(m).delegate
diff --git 
a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectives.scala
 
b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectives.scala
index 01ca61ea7..127659ead 100644
--- 
a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectives.scala
+++ 
b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/MethodDirectives.scala
@@ -77,6 +77,13 @@ trait MethodDirectives {
    */
   def put: Directive0 = _put
 
+  /**
+   * Rejects all non-QUERY requests.
+   *
+   * @group method
+   */
+  def query: Directive0 = _query
+
   /**
    * Extracts the request method.
    *
@@ -131,5 +138,6 @@ object MethodDirectives extends MethodDirectives {
   private val _patch  : Directive0 = method(PATCH)
   private val _post   : Directive0 = method(POST)
   private val _put    : Directive0 = method(PUT)
+  private val _query  : Directive0 = method(QUERY)
   // format: ON
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to