Override Sec-WebSocket-Protocol websocket handshake response header after custom headers to avoid duplication (#10793)

Motivation:

According rfc (https://tools.ietf.org/html/rfc6455#section-11.3.4), `Sec-WebSocket-Protocol` header field MUST NOT appear
more than once in an HTTP response.
At the moment we can pass `Sec-WebSocket-Protocol`  via custom headers and it will be added to response.

Modification:

Change method add() to set() for avoid duplication. If we pass sub protocols in handshaker constructor it means that they are preferred over custom ones.

Result:

Less error prone behavior.
This commit is contained in:
Andrey Mizurov 2020-11-19 11:49:44 +03:00 committed by GitHub
parent 3354c7b0bf
commit f40b4f15a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 14 additions and 5 deletions

View File

@ -165,7 +165,7 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
}
} else {
res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
}
}
@ -189,7 +189,7 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
String protocol = req.headers().get(HttpHeaderNames.WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.headers().add(HttpHeaderNames.WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
res.headers().set(HttpHeaderNames.WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
}
return res;

View File

@ -161,7 +161,7 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
}
} else {
res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
}
}
return res;

View File

@ -167,7 +167,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
}
} else {
res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
}
}
return res;

View File

@ -165,7 +165,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
}
} else {
res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
}
}
return res;

View File

@ -48,12 +48,15 @@ public abstract class WebSocketServerHandshakerTest {
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==")
.set(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, "http://example.com")
.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, "chat, superchat")
.set(HttpHeaderNames.WEBSOCKET_PROTOCOL, "chat, superchat")
.set(HttpHeaderNames.SEC_WEBSOCKET_VERSION, webSocketVersion().toAsciiString());
HttpHeaders customResponseHeaders = new DefaultHttpHeaders();
// set duplicate required headers and one custom
customResponseHeaders
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE)
.set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET)
.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, "superchat")
.set(HttpHeaderNames.WEBSOCKET_PROTOCOL, "superchat")
.set("custom", "header");
if (webSocketVersion() != WebSocketVersion.V00) {
@ -68,8 +71,14 @@ public abstract class WebSocketServerHandshakerTest {
assertEquals(1, responseHeaders.getAll(HttpHeaderNames.CONNECTION).size());
assertEquals(1, responseHeaders.getAll(HttpHeaderNames.UPGRADE).size());
assertTrue(responseHeaders.containsValue("custom", "header", true));
if (webSocketVersion() != WebSocketVersion.V00) {
assertFalse(responseHeaders.containsValue(HttpHeaderNames.SEC_WEBSOCKET_ACCEPT, "12345", false));
assertEquals(1, responseHeaders.getAll(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL).size());
assertEquals("chat", responseHeaders.get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL));
} else {
assertEquals(1, responseHeaders.getAll(HttpHeaderNames.WEBSOCKET_PROTOCOL).size());
assertEquals("chat", responseHeaders.get(HttpHeaderNames.WEBSOCKET_PROTOCOL));
}
} finally {
request.release();