Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions conformance/tests/httproute-https-listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ var HTTPRouteHTTPSListener = suite.ConformanceTest{
host string
statusCode int
backend string
serverName string
}{
{host: "example.org", statusCode: 200, backend: "infra-backend-v1"},
{host: "unknown-example.org", statusCode: 404},
{host: "second-example.org", statusCode: 200, backend: "infra-backend-v2"},
{host: "example.org", serverName: "example.org", statusCode: 200, backend: "infra-backend-v1"},
{host: "example.org", serverName: "second-example.org", statusCode: 421},
{host: "second-example.org", serverName: "example.org", statusCode: 421},
Comment on lines +66 to +67
Copy link
Member

Choose a reason for hiding this comment

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

I think the relevant part of the spec is here:

// the Gateway SHOULD return a 421.

We're actually using RFC 2119 interpretation of keywords here, so SHOULD is a recommendation, not a requirement. With that said, I think we could justify an extended test (separate feature name) to cover this.

cc @youngnick @rikatz

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we enforce this behaviour only for reused connections? If Cx is estabilishing a new connection per request then misdirected does not make sense.

@snorwin can you verify that connection is being reused in this test? I was looking into RoundTripper and I can see that DisableKeepAlives is set.

Copy link
Member Author

Choose a reason for hiding this comment

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

For example, a request might have been misdirected, deliberately or accidentally, such that the information within a received Host header field differs from the connection's host or port.
https://www.rfc-editor.org/rfc/rfc9110.html#name-rejecting-misdirected-reque

In the case of TLS, the connection’s host is determined by the SNI extension sent during the initial TLS handshake. In my opinion, it should not matter whether the connection was established specifically for this request or reused from a previous one.

@kl52752 which HTTP status code would you expect when a request sent over a newly established connection has a mismatch between the SNI value and the Host header?

Related references:

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm referring to:

// * If another Listener has an exact match or more specific wildcard entry,
// the Gateway SHOULD return a 421.

Imagine we have 2 listeners on the same port one with *.example.com and second one with foo.example.com.

Like you mentioned SNI is validated in initial TLS handshake, so if client is connecting to *.example.com and this is the only "destination" for this request I think that 200 should be returned because TLS handshake was performed for *.example.com.

What we should test is that after client connects to *.example.com and reuse this connection to foo.example.com on different listener then 421 should be returned.

Does it makes sense?

Copy link
Member Author

Choose a reason for hiding this comment

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

I understand your example. Let’s assume we have 2 listeners on the same port one with *.example.com and second one with foo.example.com.

What HTTP error code would you expect for a request on a new connection with SNI bar.example.com and a Host header foo.example.com?

Copy link
Contributor

Choose a reason for hiding this comment

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

oh yeah sorry I missed the fact that SNI and host mismatch here. Now it makes sense :)

Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC:

  • Anything around 421 should be a separate test since its a SHOULD
  • 421 should only be returned when it would otherwise match, otherwise its a 404. We should have cases to handle this, and ensure we do not return 421 when there is not otherwise a match

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, one thing i think is vague in the spec

	//
	// * If another Listener has an exact match or more specific wildcard entry,
	//   the Gateway SHOULD return a 421.

Can an empty listener.hostname be "more specific wildcard entry"? On one hand, empty != wildcard, but on the other hand, empty is a complete wildcard.

We treat case 4 {host: "unknown-example.org", serverName: "second-example.org", statusCode: 404}, as a 404. But, IMO, this seems like it should be misdirected: the fact the 'other listener' has no hostname disqualifies is irrelevant to users and show behave the same as a wildcard IMO.

I am leaning towards changing this test and making the spec slightly tweaked...

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, a closer look suggests this must be a 421 even with the current wording of the spec:

if (another listener has an exact match or more specific wildcard) {
	// per discussion, this is currently NOT hit, but IMO should be
	421
} else if (current listener does not match host) {
	// This is hit
	if (another listener does match the host) {
		// This IS hit, because it doesn't disqualify unspecified listener hostnames
		421
	} else {
		404 // The test currently incorrectly asserts 404 here
	}
}

{host: "unknown-example.org", serverName: "unknown-example.org", statusCode: 404},
{host: "unknown-example.org", serverName: "second-example.org", statusCode: 404},
Comment on lines +68 to +69
Copy link
Member

Choose a reason for hiding this comment

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

Since these are both a MUST, I don't think they need any qualifiers and can be a part of a core conformance test. Hopefully these don't trip up any existing implementations.

/cc @kl52752 @rostislavbobo

{host: "second-example.org", serverName: "second-example.org", statusCode: 200, backend: "infra-backend-v2"},
}

for i, tc := range cases {
Expand All @@ -74,7 +78,7 @@ var HTTPRouteHTTPSListener = suite.ConformanceTest{
Namespace: "gateway-conformance-infra",
}
t.Run(expected.GetTestCaseName(i), func(t *testing.T) {
tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, tc.host, expected)
tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, tc.serverName, expected)
})
}
},
Expand Down