diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java index 69ca9776cf..9a7304f346 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java @@ -35,7 +35,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { private static final int DEFAULT_MAX_FRAME_SIZE = 16384; - private final int maxFrameSize; + private final long maxFrameSize; private boolean receivedClosingHandshake; public WebSocket00FrameDecoder() { @@ -52,6 +52,17 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { public WebSocket00FrameDecoder(int maxFrameSize) { this.maxFrameSize = maxFrameSize; } + + /** + * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}. If the client + * sends a frame size larger than {@code maxFrameSize}, the channel will be closed. + * + * @param maxFrameSize + * the maximum frame size to decode + */ + public WebSocket00FrameDecoder(long maxFrameSize) { + this.maxFrameSize = maxFrameSize; + } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java index b590c11d8a..19d81ec2eb 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java @@ -82,6 +82,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder this.maxFramePayloadLength) { + protocolViolation(channel, "Max frame length of " + this.maxFramePayloadLength + " has been exceeded."); + return null; + } if (logger.isDebugEnabled()) { logger.debug("Decoding WebSocket Frame length=" + framePayloadLength); } @@ -236,10 +258,12 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder customHeaders; + private final long maxFramePayloadLength; + /** - * Base constructor + * Base constructor with default values * * @param webSocketUrl * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -54,10 +56,31 @@ public abstract class WebSocketClientHandshaker { */ public WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol, Map customHeaders) { + this(webSocketUrl, version, subprotocol, customHeaders, Long.MAX_VALUE); + } + + /** + * Base constructor + * + * @param webSocketUrl + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. + * @param customHeaders + * Map of custom headers to add to the client request + * @param maxFramePayloadLength + * Maximum length of a frame's payload + */ + public WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol, + Map customHeaders, long maxFramePayloadLength) { this.webSocketUrl = webSocketUrl; this.version = version; expectedSubprotocol = subprotocol; this.customHeaders = customHeaders; + this.maxFramePayloadLength = maxFramePayloadLength; } /** @@ -74,6 +97,13 @@ public abstract class WebSocketClientHandshaker { return version; } + /** + * Returns the max length for any frame's payload + */ + public long getMaxFramePayloadLength() { + return maxFramePayloadLength; + } + /** * Flag to indicate if the opening handshake is complete */ diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java index fc5ae38dac..b52b840907 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java @@ -49,7 +49,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { private byte[] expectedChallengeResponseBytes; /** - * Constructor specifying the destination web socket location and version to initiate + * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -63,8 +63,27 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { */ public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, Map customHeaders) { - super(webSocketURL, version, subprotocol, customHeaders); - + this(webSocketURL, version, subprotocol, customHeaders, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location and version to initiate + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. + * @param customHeaders + * Map of custom headers to add to the client request + * @param maxFramePayloadLength + * Maximum length of a frame's payload + */ + public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, + Map customHeaders, long maxFramePayloadLength) { + super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); } /** @@ -138,17 +157,16 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { request.addHeader(Names.UPGRADE, Values.WEBSOCKET); request.addHeader(Names.CONNECTION, Values.UPGRADE); request.addHeader(Names.HOST, wsURL.getHost()); - + int wsPort = wsURL.getPort(); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { - // if the port is not standard (80/443) its needed to add the port to the header. + // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ":" + wsPort; } request.addHeader(Names.ORIGIN, originValue); - request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1); request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2); if (getExpectedSubprotocol() != null && !getExpectedSubprotocol().equals("")) { @@ -220,7 +238,8 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); setActualSubprotocol(protocol); - channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket00FrameDecoder()); + channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", + new WebSocket00FrameDecoder(this.getMaxFramePayloadLength())); setHandshakeComplete(); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java index 4e8f24598d..5ba568e3cc 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java @@ -54,7 +54,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location and version to initiate + * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -70,7 +70,29 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { */ public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) { - super(webSocketURL, version, subprotocol, customHeaders); + this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); + } + + /** + * Constructor + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Map of custom headers to add to the client request + * @param maxFramePayloadLength + * Maximum length of a frame's payload + */ + public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { + super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); this.allowExtensions = allowExtensions; } @@ -122,11 +144,11 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { request.addHeader(Names.CONNECTION, Values.UPGRADE); request.addHeader(Names.SEC_WEBSOCKET_KEY, key); request.addHeader(Names.HOST, wsURL.getHost()); - + int wsPort = wsURL.getPort(); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { - // if the port is not standard (80/443) its needed to add the port to the header. + // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ":" + wsPort; } @@ -134,7 +156,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { // Use Sec-WebSocket-Origin // See https://github.com/netty/netty/issues/264 request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue); - + if (protocol != null && !protocol.equals("")) { request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, protocol); } @@ -195,7 +217,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.getHeader(Names.CONNECTION)); } - + String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT); if (accept == null || !accept.equals(expectedChallengeResponseString)) { throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, @@ -203,7 +225,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { } channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", - new WebSocket08FrameDecoder(false, allowExtensions)); + new WebSocket08FrameDecoder(false, allowExtensions, this.getMaxFramePayloadLength())); setHandshakeComplete(); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java index 6d2348b4ae..5f31eed5b0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java @@ -54,7 +54,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location and version to initiate + * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -70,10 +70,32 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { */ public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) { - super(webSocketURL, version, subprotocol, customHeaders); + this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); + } + + /** + * Constructor + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Map of custom headers to add to the client request + * @param maxFramePayloadLength + * Maximum length of a frame's payload + */ + public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { + super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); this.allowExtensions = allowExtensions; } - + /** * /** *

@@ -200,7 +222,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { } channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", - new WebSocket13FrameDecoder(false, allowExtensions)); + new WebSocket13FrameDecoder(false, allowExtensions, this.getMaxFramePayloadLength())); setHandshakeComplete(); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java index a199299411..e6d6b9c542 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java @@ -41,17 +41,40 @@ public class WebSocketClientHandshakerFactory { */ public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) throws WebSocketHandshakeException { + return newHandshaker(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); + } + + /** + * Instances a new handshaker + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. Null if no sub-protocol support is required. + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Custom HTTP headers to send during the handshake + * @param maxFramePayloadLength + * Maximum allowable frame payload length. Setting this value to your application's requirement may + * reduce denial of service attacks using long data frames. + * @throws WebSocketHandshakeException + */ + public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) throws WebSocketHandshakeException { if (version == WebSocketVersion.V13) { - return new WebSocketClientHandshaker13(webSocketURL, version, subprotocol, allowExtensions, customHeaders); + return new WebSocketClientHandshaker13(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength); } if (version == WebSocketVersion.V08) { - return new WebSocketClientHandshaker08(webSocketURL, version, subprotocol, allowExtensions, customHeaders); + return new WebSocketClientHandshaker08(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength); } if (version == WebSocketVersion.V00) { - return new WebSocketClientHandshaker00(webSocketURL, version, subprotocol, customHeaders); + return new WebSocketClientHandshaker00(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); } throw new WebSocketHandshakeException("Protocol version " + version.toString() + " not supported."); - } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java index e22561bc88..e648915a6f 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java @@ -33,9 +33,11 @@ public abstract class WebSocketServerHandshaker { private final WebSocketVersion version; + private final long maxFramePayloadLength; + /** - * Constructor specifying the destination web socket location - * + * Constructor using default values + * * @param version * the protocol version * @param webSocketUrl @@ -44,8 +46,25 @@ public abstract class WebSocketServerHandshaker { * @param subprotocols * CSV of supported protocols. Null if sub protocols not supported. */ - protected WebSocketServerHandshaker( - WebSocketVersion version, String webSocketUrl, String subprotocols) { + protected WebSocketServerHandshaker(WebSocketVersion version, String webSocketUrl, String subprotocols) { + this(version, webSocketUrl, subprotocols, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location + * + * @param version + * the protocol version + * @param webSocketUrl + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols. Null if sub protocols not supported. + * @param maxFramePayloadLength + * Maximum length of a frame's payload + */ + protected WebSocketServerHandshaker(WebSocketVersion version, String webSocketUrl, String subprotocols, + long maxFramePayloadLength) { this.version = version; this.webSocketUrl = webSocketUrl; if (subprotocols != null) { @@ -57,6 +76,7 @@ public abstract class WebSocketServerHandshaker { } else { this.subprotocols = new String[0]; } + this.maxFramePayloadLength = maxFramePayloadLength; } /** @@ -71,7 +91,7 @@ public abstract class WebSocketServerHandshaker { */ public Set getSubprotocols() { Set ret = new LinkedHashSet(); - for (String p: this.subprotocols) { + for (String p : this.subprotocols) { ret.add(p); } return ret; @@ -84,9 +104,16 @@ public abstract class WebSocketServerHandshaker { return version; } + /** + * Returns the max length for any frame's payload + */ + public long getMaxFramePayloadLength() { + return maxFramePayloadLength; + } + /** * Performs the opening handshake - * + * * @param channel * Channel * @param req @@ -96,7 +123,7 @@ public abstract class WebSocketServerHandshaker { /** * Performs the closing handshake - * + * * @param channel * Channel * @param frame @@ -106,7 +133,7 @@ public abstract class WebSocketServerHandshaker { /** * Selects the first matching supported sub protocol - * + * * @param requestedSubprotocols * CSV of protocols to be supported. e.g. "chat, superchat" * @return First matching supported sub protocol. Null if not found. @@ -117,10 +144,10 @@ public abstract class WebSocketServerHandshaker { } String[] requesteSubprotocolArray = requestedSubprotocols.split(","); - for (String p: requesteSubprotocolArray) { + for (String p : requesteSubprotocolArray) { String requestedSubprotocol = p.trim(); - for (String supportedSubprotocol: subprotocols) { + for (String supportedSubprotocol : subprotocols) { if (requestedSubprotocol.equals(supportedSubprotocol)) { return requestedSubprotocol; } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java index 4af7445fd5..78a5f7669b 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java @@ -51,7 +51,7 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker00.class); /** - * Constructor specifying the destination web socket location + * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -60,7 +60,23 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { * CSV of supported protocols */ public WebSocketServerHandshaker00(String webSocketURL, String subprotocols) { - super(WebSocketVersion.V00, webSocketURL, subprotocols); + this(webSocketURL, subprotocols, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols + * @param maxFramePayloadLength + * Maximum allowable frame payload length. Setting this value to your application's requirement may + * reduce denial of service attacks using long data frames. + */ + public WebSocketServerHandshaker00(String webSocketURL, String subprotocols, long maxFramePayloadLength) { + super(WebSocketVersion.V00, webSocketURL, subprotocols, maxFramePayloadLength); } /** @@ -167,7 +183,8 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { if (p.get(HttpChunkAggregator.class) != null) { p.remove(HttpChunkAggregator.class); } - p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket00FrameDecoder()); + p.replace(HttpRequestDecoder.class, "wsdecoder", + new WebSocket00FrameDecoder(this.getMaxFramePayloadLength())); ChannelFuture future = channel.write(res); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java index 5fabceaf86..96eedfc580 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java @@ -50,7 +50,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location + * Constructor using defaults * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -61,7 +61,26 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { * Allow extensions to be used in the reserved bits of the web socket frame */ public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) { - super(WebSocketVersion.V08, webSocketURL, subprotocols); + this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param maxFramePayloadLength + * Maximum allowable frame payload length. Setting this value to your application's requirement may + * reduce denial of service attacks using long data frames. + */ + public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions, + long maxFramePayloadLength) { + super(WebSocketVersion.V08, webSocketURL, subprotocols, maxFramePayloadLength); this.allowExtensions = allowExtensions; } @@ -142,7 +161,8 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { p.remove(HttpChunkAggregator.class); } - p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket08FrameDecoder(true, allowExtensions)); + p.replace(HttpRequestDecoder.class, "wsdecoder", + new WebSocket08FrameDecoder(true, allowExtensions, this.getMaxFramePayloadLength())); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket08FrameEncoder(false)); return future; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java index f8debb39c9..dab9a8f8d9 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java @@ -51,7 +51,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location + * Constructor using defaults * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be @@ -62,7 +62,26 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { * Allow extensions to be used in the reserved bits of the web socket frame */ public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions) { - super(WebSocketVersion.V13, webSocketURL, subprotocols); + this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param maxFramePayloadLength + * Maximum allowable frame payload length. Setting this value to your application's requirement may + * reduce denial of service attacks using long data frames. + */ + public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions, + long maxFramePayloadLength) { + super(WebSocketVersion.V13, webSocketURL, subprotocols, maxFramePayloadLength); this.allowExtensions = allowExtensions; } @@ -143,7 +162,8 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { p.remove(HttpChunkAggregator.class); } - p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, allowExtensions)); + p.replace(HttpRequestDecoder.class, "wsdecoder", + new WebSocket13FrameDecoder(true, allowExtensions, this.getMaxFramePayloadLength())); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket13FrameEncoder(false)); return future; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java index 4428bc5ea0..5f1cde5ba2 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java @@ -34,6 +34,8 @@ public class WebSocketServerHandshakerFactory { private final boolean allowExtensions; + private final long maxFramePayloadLength; + /** * Constructor specifying the destination web socket location * @@ -46,10 +48,31 @@ public class WebSocketServerHandshakerFactory { * Allow extensions to be used in the reserved bits of the web socket frame */ public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions) { + this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); + } + + /** + * Constructor specifying the destination web socket location + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols. Null if sub protocols not supported. + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + * @param maxFramePayloadLength + * Maximum allowable frame payload length. Setting this value to your application's requirement may + * reduce denial of service attacks using long data frames. + */ + public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions, + long maxFramePayloadLength) { this.webSocketURL = webSocketURL; this.subprotocols = subprotocols; this.allowExtensions = allowExtensions; + this.maxFramePayloadLength = maxFramePayloadLength; } + /** * Instances a new handshaker @@ -63,16 +86,16 @@ public class WebSocketServerHandshakerFactory { if (version != null) { if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) { // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification). - return new WebSocketServerHandshaker13(webSocketURL, subprotocols, allowExtensions); + return new WebSocketServerHandshaker13(webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength); } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) { // Version 8 of the wire protocol - version 10 of the draft hybi specification. - return new WebSocketServerHandshaker08(webSocketURL, subprotocols, allowExtensions); + return new WebSocketServerHandshaker08(webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength); } else { return null; } } else { // Assume version 00 where version header was not specified - return new WebSocketServerHandshaker00(webSocketURL, subprotocols); + return new WebSocketServerHandshaker00(webSocketURL, subprotocols, maxFramePayloadLength); } } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java index 8e98282542..ef18d87db6 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java @@ -75,7 +75,7 @@ public class WebSocketServerHandshaker00Test { ChannelBuffer buffer = ChannelBuffers.copiedBuffer("^n:ds[4U", Charset.defaultCharset()); req.setContent(buffer); - WebSocketServerHandshaker00 handsaker = new WebSocketServerHandshaker00("ws://example.com/chat", "chat"); + WebSocketServerHandshaker00 handsaker = new WebSocketServerHandshaker00("ws://example.com/chat", "chat", Long.MAX_VALUE); handsaker.handshake(channelMock, req); Assert.assertEquals("ws://example.com/chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_LOCATION)); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java index 6ca8a495d1..033d02672a 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java @@ -68,7 +68,7 @@ public class WebSocketServerHandshaker08Test { req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat"); req.setHeader(Names.SEC_WEBSOCKET_VERSION, "8"); - WebSocketServerHandshaker08 handsaker = new WebSocketServerHandshaker08("ws://example.com/chat", "chat", false); + WebSocketServerHandshaker08 handsaker = new WebSocketServerHandshaker08("ws://example.com/chat", "chat", false, Long.MAX_VALUE); handsaker.handshake(channelMock, req); Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT)); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java index 257e484fa5..57caf44313 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java @@ -67,7 +67,7 @@ public class WebSocketServerHandshaker13Test { req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com"); req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat"); req.setHeader(Names.SEC_WEBSOCKET_VERSION, "13"); - WebSocketServerHandshaker13 handsaker = new WebSocketServerHandshaker13("ws://example.com/chat", "chat", false); + WebSocketServerHandshaker13 handsaker = new WebSocketServerHandshaker13("ws://example.com/chat", "chat", false, Long.MAX_VALUE); handsaker.handshake(channelMock, req); Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT)); diff --git a/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java index a2a53d553d..f099662fc3 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java +++ b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java @@ -117,7 +117,7 @@ public class WebSocketClient { // Send 10 messages and wait for responses logger.info("WebSocket Client sending message"); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 1000; i++) { ch.write(new TextWebSocketFrame("Message #" + i)); }