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

feat: Fix maybeWebSocketUpgrade to return true when Connection/Upgrade header has multiple… #5958

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -885,11 +885,11 @@ private static boolean isContentAlwaysEmpty(HttpMethod method) {

private static boolean maybeWebSocketUpgrade(AsciiString header, CharSequence value) {
if (HttpHeaderNames.CONNECTION.contentEqualsIgnoreCase(header) &&
HttpHeaderValues.UPGRADE.contentEqualsIgnoreCase(value)) {
AsciiString.containsIgnoreCase(value, HttpHeaderValues.UPGRADE)) {
return true;
}
return HttpHeaderNames.UPGRADE.contentEqualsIgnoreCase(header) &&
HttpHeaderValues.WEBSOCKET.contentEqualsIgnoreCase(value);
AsciiString.containsIgnoreCase(value, HttpHeaderValues.WEBSOCKET);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think either websocketxxx or xxxwebsocket is a valid header value. How about splitting the value with a comma , before checking the equality?

Copy link
Member

Choose a reason for hiding this comment

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

Can we also add a test case that makes sure it doesn't pick up headers like connection: not-upgrade-lol and upgrade: madam-websocket?

}

private static CaseInsensitiveMap toLowercaseMap(Iterator<? extends CharSequence> valuesIter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,20 @@ void toArmeriaRequestHeaders() {
assertThat(headers.authority()).isEqualTo("foo:36462");
}

@Test
void toArmeriaForWebSocketUpgrade() {
final io.netty.handler.codec.http.HttpHeaders in = new DefaultHttpHeaders()
.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE + ", " + HttpHeaderValues.UPGRADE)
.add(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET + ", additional_value");
final HttpHeadersBuilder out = HttpHeaders.builder();
out.sizeHint(in.size());
toArmeria(in, out);
final HttpHeaders outHeaders = out.build();

assertThat(outHeaders.get(HttpHeaderNames.CONNECTION)).isEqualTo("keep-alive, upgrade");
assertThat(outHeaders.get(HttpHeaderNames.UPGRADE)).isEqualTo("websocket, additional_value");
}

@Test
void isAbsoluteUri() {
final String good = "none+http://a.com";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ void http1Handshake(SessionProtocol sessionProtocol, boolean useThreadRescheduli
.build();
final RequestHeadersBuilder headersBuilder =
RequestHeaders.builder(HttpMethod.GET, "/chat")
.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE.toString());
// It works even if the header contains multiple values
Copy link
Contributor

Choose a reason for hiding this comment

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

Question) When I checked, it seems like this test passes with the main branch without the changes in this PR.

I'm curious, were you able to verify the same bug with the HEAD of the main branch? It seems a little odd since ArmeriaHttpUtil#maybeWebSocketUpgrade is only called for trailers in the server-side which doesn't seem to make sense to me.

Copy link
Author

@blue-hope blue-hope Nov 7, 2024

Choose a reason for hiding this comment

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

Thanks, @jrhee17. In toArmeria released in version 1.28.0, I found that the purgeHttp1OnlyHeaders process was dropping useless additional headers, and that is what I intended to. I'll do it again on my server and figure out what was the issue.

.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE +
", " + HttpHeaderValues.KEEP_ALIVE);
final Channel channel;
try (ClientRequestContextCaptor captor = Clients.newContextCaptor()) {
final AggregatedHttpResponse res = client.execute(headersBuilder.build()).aggregate().join();
Expand All @@ -114,7 +116,7 @@ void http1Handshake(SessionProtocol sessionProtocol, boolean useThreadRescheduli
"Connection: Upgrade");
}

headersBuilder.add(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET.toString());
headersBuilder.add(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET + ", additional_value");
try (ClientRequestContextCaptor captor = Clients.newContextCaptor()) {
final AggregatedHttpResponse res = client.execute(headersBuilder.build()).aggregate().join();

Expand Down
Loading