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

fix(request-transformer) handle Host header correctly #4253

Merged
merged 1 commit into from
Jan 29, 2019

Conversation

hishamhm
Copy link
Contributor

@hishamhm hishamhm commented Jan 28, 2019

Source of the problem: the plugin was getting the full set of headers from kong.request.get_headers, which includes the request Host value, and was setting it (after transformations) to kong.service.request.get_headers. Effectively, this performed the equivalent of the Route attribute's preserve_host = true behavior all the time.

This commit restores the input value of the Host header from the service request to the table prior to the transformations. It also removes special-case handling of the Host header that was present in the plugin, which is now handled by the PDK itself.

A change in this behavior as opposed to 0.14 is that now the
request-transformer plugin is able to modify the value of Host:

  • if preserve_host is false, you can modify it using add;
  • if preserve_host is true, you can modify it using replace.

Fixes #4252.

@hishamhm
Copy link
Contributor Author

@thibaultcha About this last bit:

A change in this behavior as opposed to 0.14 (demonstrated by the added test cases) is that now the request-transformer plugin is able to modify the value of Host, if preserve_host is false. If preserve_host is set, it still takes precedence, and preserves the host from the request.

Do you know of any gotchas that would make this behavior unwanted?

@hishamhm hishamhm added this to the 1.0.3 milestone Jan 28, 2019
@hishamhm hishamhm force-pushed the fix/request-transformer-host-header branch from f17b902 to 326458a Compare January 28, 2019 20:15
assert.equals("replaced", value)
end)

it("preserve_host = false, host change in plugin: upstream host", function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, now to answer this question:

Do you know of any gotchas that would make this behavior unwanted?

Which I was about to do in the previous patch, but then noted that it was because the tests were using add instead of replace.

To answer the question, I believe that it isn't an unreasonable assumption for a user to expect a plugin to override a Route's settings. As of this patch, we only allow replacing the Host header if preserve_host = false (which, arguable is even more confusing that the previous assumed behavior - which was incorrectly described, but that is of no importance).

Additionally, there is a deeper issue at hand here I think, which is that the reason why this test case passes (and why the plugin cannot replace a Host header when preserve_host = false, is because we rely on ngx.var.upstream_host, which itself relies on the router's behavior. So the reason why this does not work (or why this test case succeeds) is because we directly rely on router behavior see upstream_host is nil which causes ngx.var.upstream_host to be nil, which causes this plugin to not act on a replace = { "host:foo" } configuration value, because we guard the replace branch with if headers[name] ~= nil then.

In my opinion, this plugin could safely set the upstream header regardless of whether preserve_host is true or false. In doing so, we would avoid relying on core behavior as we currently do, which isn't regression-safe at all.
We should find another way than the headers.host = ngx.var.upstream_host. In my opinion, we are lacking a thin layer of abstraction between the core and this plugin (we may use existing PDK functions that act as this layer, or we may come up with a new PDK abstraction). This is one of these problems that #3821 is trying to solve, iirc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had a bad feeling about this particular case you highlighted as well. Since the original issue was about corrupting Host when transformations were not being applied on it and the semantics of the behavior of transforming Host were unclear anyway, I pushed on with that original approach.

In my opinion, this plugin could safely set the upstream header regardless of whether preserve_host is true or false.

I like these simpler semantics.

In doing so, we would avoid relying on core behavior as we currently do, which isn't regression-safe at all.

In the latest iteration, I had to special-case the Host header a bit more in the plugin again, but it does not rely on core behavior (only on the assumptions that a Host header must always exist [to forbid add and rename] and cannot be set multiple times [to forbid append] ).

In my opinion, we are lacking a thin layer of abstraction between the core and this plugin (we may use existing PDK functions that act as this layer, or we may come up with a new PDK abstraction). This is one of these problems that #3821 is trying to solve, iirc.

Agreed, because since kong.request represents the incoming request, its value of get_header("host") is correct. Perhaps what we really want is kong.service.request.get_headers, which would represent the state of headers as they are being prepared to be sent to the outgoing request (but of course there are difficulties in crafting such an API and keeping ngx and the PDK interoperable).

I think for now the approach in this PR is sufficient to fix the related issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the latest iteration, I had to special-case the Host header a bit more in the plugin again, but it does not rely on core behavior (only on the assumptions that a Host header must always exist [to forbid add and rename] and cannot be set multiple times [to forbid append] ).

This iteration looks better in its behavior. But it's still somewhat hand-crafted based on deep Core behavior, and a thin abstraction would be nicer. Nonetheless, the patch looks good for now 👍

Perhaps what we really want is kong.service.request.get_headers, which would represent the state of headers as they are being prepared to be sent to the outgoing request

This has been proposed in #3840 already - there has been a few asks around it and it seems like a valuable addition to the PDK.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I take that back; I think the current level of decoupling between the core and this plugin is fine as per this iteration 👍

@hishamhm hishamhm force-pushed the fix/request-transformer-host-header branch 2 times, most recently from 5f52ae1 to 45ef17b Compare January 28, 2019 22:46
Source of the problem: the plugin was getting the full set of headers from
`kong.request.get_headers`, which includes the request Host value, and was
setting it (after transformations) to `kong.service.request.get_headers`.
Effectively, this was the equivalent of the Route's `preserve_host = true`
behavior on all the time.

A change in this behavior as opposed to 0.14 is that now the
`request-transformer` plugin _is_ able to modify the value of `Host`:
you can modify it using `replace` (you cannot `add`, `rename` or
`append` to it).
@hishamhm hishamhm force-pushed the fix/request-transformer-host-header branch from 45ef17b to f4055fb Compare January 29, 2019 16:53
@hishamhm hishamhm merged commit edb38b8 into master Jan 29, 2019
@hishamhm hishamhm deleted the fix/request-transformer-host-header branch January 29, 2019 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants