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/routing without Host header #3216

Closed
wants to merge 5 commits into from
Closed

Conversation

rainest
Copy link
Contributor

@rainest rainest commented Feb 12, 2018

Summary

Allows Kong to accept HTTP/1.0 requests that do not contain a Host header

Full changelog

  • If no Host header present, match against APIs defined by method or URI
  • Test that a request with a matching method or URI can be matched without Host

Issues resolved

Fix #3171

Travis Raines added 3 commits February 9, 2018 16:45
If clients do not send a Host header (valid in HTTP/1.0),
ngx.var.http_host is nil. Kong rejects this when routing to an API.
However, only one of uris, hosts, or methods is required when adding
an API. This change allows routing any HTTP/1.0 request with an
appropriate method or URI to the corresponding API.

Fix #3171
Tests that a request without a host header can route to an API if it
matches other criteria.

Fix #3171
Tests that an HTTP/1.0 request without the Host header is accepted and
routes to an API matching its method.

Fix #3171
@rainest rainest requested a review from thibaultcha February 12, 2018 18:21
Copy link
Member

@thibaultcha thibaultcha left a comment

Choose a reason for hiding this comment

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

Thank you for the patch!

Would you mind addressing the few concerns I noted? Mostly: adding a test for NGINX's behavior with HTTP/1.1 and reworking a little bit the internals of the provided test to better follow Lua idioms (already followed by this codebase)

Thanks!

@@ -100,6 +100,13 @@ describe("Router", function()
assert.same(use_case[3], match_t.api)
end)

it("[uri]", function()
Copy link
Member

Choose a reason for hiding this comment

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

could we rename this test to: [uri + empty host]?

@@ -134,6 +134,26 @@ describe("Router", function()
assert.equal("api-1", res.headers["kong-api-name"])
end)

it("routes by method-only if no Host header present", function()
Copy link
Member

Choose a reason for hiding this comment

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

Would it be possible to create a new describe block for empty/no Host header tests? Like so:

describe("requests with no Host header", function()
  it("HTTP/1.0 routes normally", function()

  end)

  it("HTTP/1.1 is rejected by NGINX", function()
    -- new test: assert NGINX's behavior with HTTP/1.1 (missing from this PR)
  end)
end)

-- based on the source of https://github.com/pintsized/lua-resty-http
local sock = ngx.socket.tcp()
finally(function() sock:close() end)
local ok, err = sock:connect(helpers.test_conf.proxy_ip,
Copy link
Member

Choose a reason for hiding this comment

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

style: it is nice to see the effort to stay under 80 chars. As per CONTRIBUTING.md, the preferred way of doing so is to align subsequent arguments right under the first one :)

finally(function() sock:close() end)
local ok, err = sock:connect(helpers.test_conf.proxy_ip,
helpers.test_conf.proxy_port)
assert(ok, err)
Copy link
Member

Choose a reason for hiding this comment

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

The Lua idiom is to directly do:

assert(sock:connect(...))

helpers.test_conf.proxy_port)
assert(ok, err)
local req = "GET /get HTTP/1.0\r\nKong-Debug: 1\r\n\r\n"
sock:send(req)
Copy link
Member

Choose a reason for hiding this comment

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

We should also check for errors here

local req = "GET /get HTTP/1.0\r\nKong-Debug: 1\r\n\r\n"
sock:send(req)
local line, err = sock:receive("*l")
assert(line, err)
Copy link
Member

Choose a reason for hiding this comment

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

In this case, the idiom becomes:

local line = assert(sock:receive("*l"))

local line, err = sock:receive("*l")
assert(line, err)
local status = tonumber(string.sub(line, 10, 12))
assert.equal(status, 200)
Copy link
Member

Choose a reason for hiding this comment

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

The arguments need to be reversed here: it will produce a confusing error message if this fails (expected values come first in luassert, which is the library providing those extended assertions)

local status = tonumber(string.sub(line, 10, 12))
assert.equal(status, 200)
local remainder, err = sock:receive("*a")
assert(remainder, err)
Copy link
Member

Choose a reason for hiding this comment

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

ditto: better use the proper lua idioms

local remainder, err = sock:receive("*a")
assert(remainder, err)
assert(string.find(string.lower(remainder),
"kong-api-name: api-1", 1, true))
Copy link
Member

Choose a reason for hiding this comment

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

Here, we can use luassert's extended assertions too:

assert.matches("kong-api-name: api-1", string.lower(remainder), nil, true)

@@ -831,7 +831,7 @@ function _M.new(apis)
end
end

local req_host = ngx.var.http_host
local req_host = ngx.var.http_host or ""

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we allow this bevahior only when the request protocol is HTTP/1.0? The Host header is required for 1.1 requests; i would proffer that Kong should require 1.1 clients to follow the spec and not accept invalid requests.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, the goal of this patch is to support this behavior only for HTTP/1.0 (as discussed with @rainest). There is probably nothing else to add in the router since NGINX should disallow HTTP/1.1 requests without the Host head already (hence why the ask for the test so we avoid a future regression). We could also add a check in the router but it seems unnecessary to me...

Travis Raines added 2 commits February 13, 2018 11:17
HTTP/1.1 requires the Host header per RFC 2616. NGINX is expected to
return status 4400 for requests lacking it.
@thibaultcha
Copy link
Member

Thanks! Merged to master with some modifications (including asserting that the NGINX error is caught by Kong itself). Good job!

@thibaultcha thibaultcha deleted the fix/empty-host-routing branch February 14, 2018 01:45
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.

kong error when host is empty
3 participants