-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Remove connection-specific headeres for HTTP/2 and HTTP/3 #24543
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
Conversation
I think this conflicts with the changes @JamesNK just made. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, please rebase.
@Kahbazi Are you still interested in proceeding with this PR? |
af5bff1
to
d6752d6
Compare
@BrennanConroy Sorry for the delay. I rebased and updated the PR. |
Spec - https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-field-formatting-and-compre
Kestrel isn't an intermediary and it doesn't transform request protocols. It could be used as part of an intermediary, like YARP, but in that case it is YARPs job to remove these headers when transforming a HTTP/1.1 call to 2 or 3. I don't see why this code should be part of Kestrel. |
A) It's kestrel's job to enforce protocol correctness, it shouldn't allow outgoing or incoming protocol violations. We have similar checks for incoming requests: aspnetcore/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs Lines 1314 to 1317 in be472db
B) For consistency with IIS & Http.Sys which I expect removes these silently from responses. |
I don't think this is a good enough reason to use all of the time. Kestrel is the only server where we can control this level of behavior and that's an advantage. That said, I think we saw other servers beyond our own NOT have this behavior (go, node) so it's worth considering. |
d6752d6
to
cad4c5f
Compare
Rebased. I spoke with @Kahbazi and volunteered to finish this PR for them. I confirmed the behavior in Http.Sys where these headers are all silently removed. This approach allows the server to maintain both protocol compliance and app compatibility. These headers may be added by a library that is not in the developers control. For Kestrel I've added a generic log statement that "A response header has been removed because it was invalid for the current protocol." . This is logged at the debug level because the issue is something the app can ignore unless they want to learn more about the protocol details. I've limited it to one log per response to limit the complexity and noise. |
Currently the PR's behavior is checking for certain set headers when using HTTP/2+, and then clearing them. From a performance perspective, wouldn't it be better to make setting these headers noop in HTTP/2? That avoids checking whether these headers are set in every HTTP/2+ request. |
The overhead should be pretty minimal, a few bitwise checks, but you've given me an idea on how to reduce that further. I'll try it and report back. |
I've updated this to consolidate the operations for these headers and reduce overhead. The headers collection is quite performant already, the relevant code is only setting two fields. You wouldn't be able to avoid the normal dictionary-like operations for Headers.Add to find those fields. I'd rather keep the logic here in CreateResponseHeaders. The headers collections don't currently know about things like request protocols, the protocol specific logic for response headers is all consolidated in CreateResponseHeaders right now. I think that makes it easier to maintain. @halter73 any thoughts on this? |
src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.cs
Outdated
Show resolved
Hide resolved
I do like keeping the main logic in CreateResponseHeaders. I think the current implementations of HasInvalidH2H3Headers and ClearInvalidH2H3Headers() are plenty efficient. You could even argue it creates less branching logic on the set-headers path compared to proactively avoiding setting them. We could microbenchmark, but I'm not too concerned about optimizing the case where invalid headers are being set as long as it isn't terrible. |
src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Stephen Halter <[email protected]>
src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3StreamTests.cs
Outdated
Show resolved
Hide resolved
@@ -65,6 +65,7 @@ public static class HeaderNames | |||
public static readonly string Pragma = "Pragma"; | |||
public static readonly string ProxyAuthenticate = "Proxy-Authenticate"; | |||
public static readonly string ProxyAuthorization = "Proxy-Authorization"; | |||
public static readonly string ProxyConnection = "Proxy-Connection"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping @dotnet/aspnet-api-review. We should probably send an email as a heads up.
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
@@ -117,6 +117,10 @@ internal class KestrelTrace : IKestrelTrace | |||
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(40, nameof(Http2MaxConcurrentStreamsReached)), | |||
@"Connection id ""{ConnectionId}"" reached the maximum number of concurrent HTTP/2 streams allowed."); | |||
|
|||
private static readonly Action<ILogger, Exception> _invalidResponseHeaderRemoved = | |||
LoggerMessage.Define(LogLevel.Information, new EventId(41, nameof(InvalidResponseHeaderRemoved)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still would prefer this is a warning at least for the early previews. If we get feedback that this is too noisy or not helpful, we could lower the severity. I'll approve as-is since I don't feel super strongly about it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LoggerMessage.Define(LogLevel.Information, new EventId(41, nameof(InvalidResponseHeaderRemoved)), | |
LoggerMessage.Define(LogLevel.Warning, new EventId(41, nameof(InvalidResponseHeaderRemoved)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair, we'll see what they say.
@@ -117,6 +117,10 @@ internal class KestrelTrace : IKestrelTrace | |||
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(40, nameof(Http2MaxConcurrentStreamsReached)), | |||
@"Connection id ""{ConnectionId}"" reached the maximum number of concurrent HTTP/2 streams allowed."); | |||
|
|||
private static readonly Action<ILogger, Exception> _invalidResponseHeaderRemoved = | |||
LoggerMessage.Define(LogLevel.Information, new EventId(41, nameof(InvalidResponseHeaderRemoved)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: in the rest of the stack we try to avoid using nameof
for the EventId
because changing the name is technically a breaking change and it's easier to accidentally change it when renaming a method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not sure why all of the Kestrel ones use nameof. Changing them is out of scope here. I'll file something.
#28159
Hello @Tratcher! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
Fixes #24502