Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set host header in order to use it in another route lookup #2038

Open
szuecs opened this issue Jul 7, 2022 · 3 comments
Open

Set host header in order to use it in another route lookup #2038

szuecs opened this issue Jul 7, 2022 · 3 comments

Comments

@szuecs
Copy link
Member

szuecs commented Jul 7, 2022

If you add dropRequestHeader("Host") -> setRequestHeader("Host", "bar") -> <loopback> the new host "bar" is not replacing the host header, but appending it. This works differently from the network backend.

Example

./bin/skipper -inline-routes='
r: HostAny("foo") -> logHeader() -> preserveHost("false") -> dropRequestHeader("Host") -> setRequestHeader("Host", "bar") -> <loopback>; 
r1: HostAny("bar") -> status(200) -> inlineContent("bar") -> <shunt>;'
[APP]INFO[0002] GET /foo HTTP/1.1
Host: foo                 <----
User-Agent: curl/7.49.0
Accept: */*

[APP]INFO[0002] GET /foo HTTP/1.1
Host: foo                 <----
Accept: */*
Host: bar                 <----
User-Agent: curl/7.49.0

[APP]INFO[0002] GET /foo HTTP/1.1
Host: foo                 <----
Host: bar                 <----
User-Agent: curl/7.49.0
Accept: */*

...
[APP]ERRO[0002] error while proxying after 5.67122ms, route r with backend loopback ://, status code 500: max loopbacks reached, remote host: ::1, request: "GET /foo HTTP/1.1", user agent: "curl/7.49.0"
::1 - - [07/Jul/2022:15:24:03 +0200] "GET /foo HTTP/1.1" 500 22 "-" "curl/7.49.0" 5 foo - -

network backend:

% ./bin/skipper -inline-routes='
r: HostAny("foo") -> logHeader() -> preserveHost("false") -> setRequestHeader("Host", "bar") -> "http://127.0.0.1:9090"; 
r1: HostAny("bar") -> status(200) -> inlineContent("bar") -> <shunt>;'

[APP]INFO[0001] GET /foo HTTP/1.1
Host: foo
User-Agent: curl/7.49.0
Accept: */*

127.0.0.1 - - [07/Jul/2022:15:29:40 +0200] "GET /foo HTTP/1.1" 200 3 "-" "curl/7.49.0" 1 bar - -
::1 - - [07/Jul/2022:15:29:40 +0200] "GET /foo HTTP/1.1" 200 3 "-" "curl/7.49.0" 3 foo - -
@AlexanderYastrebov
Copy link
Member

AlexanderYastrebov commented Sep 13, 2024

The thing is that go http.Server does not put "Host" into http.Request.Header but sets http.Request.Host, see https://pkg.go.dev/net/http#Request

// For incoming requests, the Host header is promoted to the
// Request.Host field and removed from the Header map.

For setRequestHeader (and friends) we have a special case for "Host" which sets context OutgoingHost field and (rather incorrectly) adds Host to the Headers:

case setRequestHeader:
value, ok := f.template.ApplyContext(ctx)
if ok {
header.Set(f.key, value)
if strings.ToLower(f.key) == "host" {
ctx.SetOutgoingHost(value)
}
}

This is how example ends up logging two Hosts: one is req.Host and another is from Headers:

buf.WriteString(req.Host)
buf.WriteString("\r\n")
for k, v := range req.Header {
if strings.ToLower(k) == "authorization" {
buf.WriteString(k)
buf.WriteString(": ")
buf.WriteString("TRUNCATED\r\n")
} else {
buf.WriteString(k)
buf.WriteString(": ")
buf.WriteString(strings.Join(v, " "))
buf.WriteString("\r\n")
}
}

Loopback routing is based on the ctx.Request().Host and does not use ctx.OutgoingHost field.
I think we can create a new setHost("<string>") filter that sets ctx.Request().Host.

@szuecs
Copy link
Member Author

szuecs commented Sep 13, 2024

Should not we better "fix" the setRequestHeader("Host", ..) part?
I mean it's a bit unexpected if you are skipper user and not a Go/skipper expert. Even if we have to have an if f.header == "Host" {}, it's better for the UX.
One open question of course is, if this result in an incident somewhere, because maybe there are users that expect the current behavior for some unknown reason.

@AlexanderYastrebov
Copy link
Member

AlexanderYastrebov commented Sep 14, 2024

Should not we better "fix" the setRequestHeader("Host", ..) part?

Yeah, I think we can also set ctx.Request().Host.

One open question of course is, if this result in an incident somewhere, because maybe there are users that expect the current behavior for some unknown reason.

Not adding Host to Headers could be a breaking change so I guess we should keep it like it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants