1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.handler.codec.http.websocketx;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelFuture;
20 import io.netty.channel.ChannelPromise;
21 import io.netty.handler.codec.http.HttpHeaders;
22 import io.netty.handler.codec.http.HttpHeaders.Names;
23 import io.netty.handler.codec.http.DefaultFullHttpResponse;
24 import io.netty.handler.codec.http.HttpRequest;
25 import io.netty.handler.codec.http.HttpResponse;
26 import io.netty.handler.codec.http.HttpResponseStatus;
27 import io.netty.handler.codec.http.HttpVersion;
28
29 /**
30 * Auto-detects the version of the Web Socket protocol in use and creates a new proper
31 * {@link WebSocketServerHandshaker}.
32 */
33 public class WebSocketServerHandshakerFactory {
34
35 private final String webSocketURL;
36
37 private final String subprotocols;
38
39 private final boolean allowExtensions;
40
41 private final int maxFramePayloadLength;
42
43 /**
44 * Constructor specifying the destination web socket location
45 *
46 * @param webSocketURL
47 * URL for web socket communications. e.g "ws://myhost.com/mypath".
48 * Subsequent web socket frames will be sent to this URL.
49 * @param subprotocols
50 * CSV of supported protocols. Null if sub protocols not supported.
51 * @param allowExtensions
52 * Allow extensions to be used in the reserved bits of the web socket frame
53 */
54 public WebSocketServerHandshakerFactory(
55 String webSocketURL, String subprotocols, boolean allowExtensions) {
56 this(webSocketURL, subprotocols, allowExtensions, 65536);
57 }
58
59 /**
60 * Constructor specifying the destination web socket location
61 *
62 * @param webSocketURL
63 * URL for web socket communications. e.g "ws://myhost.com/mypath".
64 * Subsequent web socket frames will be sent to this URL.
65 * @param subprotocols
66 * CSV of supported protocols. Null if sub protocols not supported.
67 * @param allowExtensions
68 * Allow extensions to be used in the reserved bits of the web socket frame
69 * @param maxFramePayloadLength
70 * Maximum allowable frame payload length. Setting this value to your application's
71 * requirement may reduce denial of service attacks using long data frames.
72 */
73 public WebSocketServerHandshakerFactory(
74 String webSocketURL, String subprotocols, boolean allowExtensions,
75 int maxFramePayloadLength) {
76 this.webSocketURL = webSocketURL;
77 this.subprotocols = subprotocols;
78 this.allowExtensions = allowExtensions;
79 this.maxFramePayloadLength = maxFramePayloadLength;
80 }
81
82 /**
83 * Instances a new handshaker
84 *
85 * @return A new WebSocketServerHandshaker for the requested web socket version. Null if web
86 * socket version is not supported.
87 */
88 public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
89
90 String version = req.headers().get(Names.SEC_WEBSOCKET_VERSION);
91 if (version != null) {
92 if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
93 // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification).
94 return new WebSocketServerHandshaker13(
95 webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength);
96 } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) {
97 // Version 8 of the wire protocol - version 10 of the draft hybi specification.
98 return new WebSocketServerHandshaker08(
99 webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength);
100 } else if (version.equals(WebSocketVersion.V07.toHttpHeaderValue())) {
101 // Version 8 of the wire protocol - version 07 of the draft hybi specification.
102 return new WebSocketServerHandshaker07(
103 webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength);
104 } else {
105 return null;
106 }
107 } else {
108 // Assume version 00 where version header was not specified
109 return new WebSocketServerHandshaker00(webSocketURL, subprotocols, maxFramePayloadLength);
110 }
111 }
112
113 /**
114 * @deprecated use {@link #sendUnsupportedVersionResponse(Channel)}
115 */
116 @Deprecated
117 public static void sendUnsupportedWebSocketVersionResponse(Channel channel) {
118 sendUnsupportedVersionResponse(channel);
119 }
120
121 /**
122 * Return that we need cannot not support the web socket version
123 */
124 public static ChannelFuture sendUnsupportedVersionResponse(Channel channel) {
125 return sendUnsupportedVersionResponse(channel, channel.newPromise());
126 }
127
128 /**
129 * Return that we need cannot not support the web socket version
130 */
131 public static ChannelFuture sendUnsupportedVersionResponse(Channel channel, ChannelPromise promise) {
132 HttpResponse res = new DefaultFullHttpResponse(
133 HttpVersion.HTTP_1_1,
134 HttpResponseStatus.UPGRADE_REQUIRED);
135 res.headers().set(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
136 HttpHeaders.setContentLength(res, 0);
137 return channel.writeAndFlush(res, promise);
138 }
139 }