diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala index 690a81627e..361288c970 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala @@ -55,10 +55,23 @@ private[http] object HttpServerBluePrint { }.withDeploy(Deploy.local) }, errorMsg = "Http.serverLayer is currently not reusable. You need to create a new instance for each materialization.") + def establishAbsoluteUri(requestOutput: RequestOutput): RequestOutput = requestOutput match { + case start: RequestStart ⇒ + try { + val effectiveUri = HttpRequest.effectiveUri(start.uri, start.headers, securedConnection = false, defaultHostHeader) + start.copy(uri = effectiveUri) + } catch { + case e: IllegalUriException ⇒ + MessageStartError(StatusCodes.BadRequest, ErrorInfo("Request is missing required `Host` header", e.getMessage)) + } + case x ⇒ x + } + val requestParsingFlow = Flow[ByteString].transform(() ⇒ // each connection uses a single (private) request parser instance for all its requests // which builds a cache of all header instances seen on that connection rootParser.createShallowCopy(() ⇒ oneHundredContinueRef).stage).named("rootParser") + .map(establishAbsoluteUri) val requestPreparation = Flow[RequestOutput] @@ -66,14 +79,13 @@ private[http] object HttpServerBluePrint { .via(headAndTailFlow) .map { case (RequestStart(method, uri, protocol, hdrs, createEntity, _, _), entityParts) ⇒ - val effectiveUri = HttpRequest.effectiveUri(uri, hdrs, securedConnection = false, defaultHostHeader) val effectiveMethod = if (method == HttpMethods.HEAD && transparentHeadRequests) HttpMethods.GET else method val effectiveHeaders = if (settings.remoteAddressHeader && remoteAddress.isDefined) headers.`Remote-Address`(RemoteAddress(remoteAddress.get)) +: hdrs else hdrs - HttpRequest(effectiveMethod, effectiveUri, effectiveHeaders, createEntity(entityParts), protocol) + HttpRequest(effectiveMethod, uri, effectiveHeaders, createEntity(entityParts), protocol) case (_, src) ⇒ src.runWith(Sink.ignore) }.collect { case r: HttpRequest ⇒ r diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala index 9cae0f8c68..51a08a6323 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala @@ -661,6 +661,32 @@ class HttpServerSpec extends AkkaSpec("akka.loggers = []\n akka.loglevel = OFF") expectRequest shouldEqual HttpRequest(uri = "http://example.com//foo", headers = List(Host("example.com"))) } + "use default-host-header for HTTP/1.0 requests" in new TestSetup { + send("""GET /abc HTTP/1.0 + | + |""".stripMarginWithNewline("\r\n")) + + expectRequest shouldEqual HttpRequest(uri = "http://example.com/abc", protocol = HttpProtocols.`HTTP/1.0`) + + override def settings: ServerSettings = super.settings.copy(defaultHostHeader = Host("example.com")) + } + "fail an HTTP/1.0 request with 400 if no default-host-header is set" in new TestSetup { + send("""GET /abc HTTP/1.0 + | + |""".stripMarginWithNewline("\r\n")) + + netOutSub.request(1) + wipeDate(netOut.expectNext().utf8String) shouldEqual + """|HTTP/1.1 400 Bad Request + |Server: akka-http/test + |Date: XXXX + |Connection: close + |Content-Type: text/plain; charset=UTF-8 + |Content-Length: 41 + | + |Request is missing required `Host` header""".stripMarginWithNewline("\r\n") + } + "support remote-address-header" in new TestSetup { lazy val theAddress = InetAddress.getByName("127.5.2.1")