Akka-http: Clarify client-side behaviour regarding URIs and Host headers

Created on 8 Sep 2016  ยท  3Comments  ยท  Source: akka/akka-http

Issue by 2beaucoup
_Tuesday Jul 21, 2015 at 13:12 GMT_
_Originally opened as https://github.com/akka/akka/issues/18048_


While thinking about #18044 I looked at how we handle things regarding URIs/Host headers on the client side.

IMO this is how things _should_ behave here:

outgoingConnection / hostConnectionPool

| URI | Host | effective URI | effective Host |
| :-: | :-: | --- | --- |
| abs | โœ• | uri | uri.host |
| rel | โœ• | uri | con.host |
| rel | โœ“ | uri | host |
| abs | โœ“ | uri | host |

hostConnectionPool (proxied)

| URI | Host | effective URI | effective Host | Condition |
| :-: | :-: | --- | --- | --- |
| abs | โœ• | uri | proxy.host | |
| rel | โœ• | uri.copy(auth = host) | proxy.host | |
| rel | โœ“ | uri.copy(auth = host) | proxy.host | |
| abs | โœ“ | uri | proxy.host | host == uri.host |

superPool / singleRequest

| URI | Host | effective URI | effective Host | Condition |
| :-: | :-: | --- | --- | --- |
| abs | โœ• | uri | uri.host | |
| rel | โœ• | | | always fail |
| rel | โœ“ | uri | host | |
| abs | โœ“ | uri | host | |

superPool / singleRequest (proxied)

| URI | Host | effective URI | effective Host | Condition |
| :-: | :-: | --- | --- | --- |
| abs | โœ• | uri | proxy.host | |
| rel | โœ• | | | always fail |
| rel | โœ“ | uri.copy(auth = host) | proxy.host | |
| abs | โœ“ | uri | proxy.host | host == uri.auth |

Requests with a protocol of HTTP/1.0 should be required to not have a Host header and therefore only the first two lines of each table and the "effective URI" column apply.

A recommendation for API users could be to never set a Host header explicitly and use absolute URIs for superPool / singleRequest and relative URIs in outgoingConnection / hostConnectionPool for simple requests. Akka would then add the Host header where required.

Implementation wise we could remove RequestRenderingContext and wrap the client APIs with the logic from above. Or the impl currently behaves exactly like described above? Then we have at least this nice summary. ;)

(The proxy cases are just included for completeness as this is currently unimplemented functionality.)

WDYT?

/cc @jrudolph @sirthias

1 - triaged

Most helpful comment

Comment by schmitch
_Saturday Aug 06, 2016 at 09:57 GMT_


actually what about "virtual hosts" one could set a Host header and send a request to a total different domain.

Something like:

curl -H 'Host: demo.com' www.google.com

So the Host header should definitly not be internal nor give a warning.
Currently I'm working on play-ws and try to get a akka-http backend and actually I use it basically like that:

Http().singleRequest(HttpRequest(uri = "http://localhost:8000", headers = Seq(Host("demo.de")))

And get a request like that:

GET / HTTP/1.1
Host: demo.de
User-Agent: akka-http/2.4.9-RC1

which is basically all I want.

All 3 comments

Comment by sirthias
_Wednesday Jul 22, 2015 at 21:02 GMT_


Thanks, @2beaucoup, this is indeed a great description which makes it easy to discuss and implement things properly!

I think I agree with all your table cells. (Maybe things in the "proxied" department are a bit more tricky but, from my current POV, I think you are spot on!)

Comment by 2beaucoup
_Friday Jul 24, 2015 at 13:07 GMT_


My proposal for simplification would be to:

  • treat Host as an internal header and warn if it's set
  • expect absolute URIs for superPool / singleRequest,fail if relative and no Host header
  • expect relative URIs for outgoingConnection / hostConnectionPool, warn if absolute, fail if uri.auth != con.host
  • submit relative URI if con.host == uri.auth
  • add Host header internally if `protocol != HTTP/1.0``

Comment by schmitch
_Saturday Aug 06, 2016 at 09:57 GMT_


actually what about "virtual hosts" one could set a Host header and send a request to a total different domain.

Something like:

curl -H 'Host: demo.com' www.google.com

So the Host header should definitly not be internal nor give a warning.
Currently I'm working on play-ws and try to get a akka-http backend and actually I use it basically like that:

Http().singleRequest(HttpRequest(uri = "http://localhost:8000", headers = Seq(Host("demo.de")))

And get a request like that:

GET / HTTP/1.1
Host: demo.de
User-Agent: akka-http/2.4.9-RC1

which is basically all I want.

Was this page helpful?
0 / 5 - 0 ratings