akka/akka-http

Clarify client-side behaviour regarding URIs and Host headers

Opened this issue · 3 comments

ktoso commented

Issue by 2beaucoup
Tuesday Jul 21, 2015 at 13:12 GMT
Originally opened as akka/akka#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

ktoso commented

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!)

ktoso commented

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``
ktoso commented

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.