View Javadoc
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.DefaultHttpResponse;
22  import io.netty.handler.codec.http.HttpHeaderNames;
23  import io.netty.handler.codec.http.HttpRequest;
24  import io.netty.handler.codec.http.HttpResponse;
25  import io.netty.handler.codec.http.HttpResponseStatus;
26  import io.netty.handler.codec.http.HttpVersion;
27  
28  /**
29   * Auto-detects the version of the Web Socket protocol in use and creates a new proper
30   * {@link WebSocketServerHandshaker}.
31   */
32  public class WebSocketServerHandshakerFactory {
33  
34      private final String webSocketURL;
35  
36      private final String subprotocols;
37  
38      private final boolean allowExtensions;
39  
40      private final int maxFramePayloadLength;
41  
42      private final boolean allowMaskMismatch;
43  
44      /**
45       * Constructor specifying the destination web socket location
46       *
47       * @param webSocketURL
48       *            URL for web socket communications. e.g "ws://myhost.com/mypath".
49       *            Subsequent web socket frames will be sent to this URL.
50       * @param subprotocols
51       *            CSV of supported protocols. Null if sub protocols not supported.
52       * @param allowExtensions
53       *            Allow extensions to be used in the reserved bits of the web socket frame
54       */
55      public WebSocketServerHandshakerFactory(
56              String webSocketURL, String subprotocols, boolean allowExtensions) {
57          this(webSocketURL, subprotocols, allowExtensions, 65536);
58      }
59  
60      /**
61       * Constructor specifying the destination web socket location
62       *
63       * @param webSocketURL
64       *            URL for web socket communications. e.g "ws://myhost.com/mypath".
65       *            Subsequent web socket frames will be sent to this URL.
66       * @param subprotocols
67       *            CSV of supported protocols. Null if sub protocols not supported.
68       * @param allowExtensions
69       *            Allow extensions to be used in the reserved bits of the web socket frame
70       * @param maxFramePayloadLength
71       *            Maximum allowable frame payload length. Setting this value to your application's
72       *            requirement may reduce denial of service attacks using long data frames.
73       */
74      public WebSocketServerHandshakerFactory(
75              String webSocketURL, String subprotocols, boolean allowExtensions,
76              int maxFramePayloadLength) {
77          this(webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength, false);
78      }
79  
80      /**
81       * Constructor specifying the destination web socket location
82       *
83       * @param webSocketURL
84       *            URL for web socket communications. e.g "ws://myhost.com/mypath".
85       *            Subsequent web socket frames will be sent to this URL.
86       * @param subprotocols
87       *            CSV of supported protocols. Null if sub protocols not supported.
88       * @param allowExtensions
89       *            Allow extensions to be used in the reserved bits of the web socket frame
90       * @param maxFramePayloadLength
91       *            Maximum allowable frame payload length. Setting this value to your application's
92       *            requirement may reduce denial of service attacks using long data frames.
93       * @param allowMaskMismatch
94       *            Allows to loosen the masking requirement on received frames. When this is set to false then also
95       *            frames which are not masked properly according to the standard will still be accepted.
96       */
97      public WebSocketServerHandshakerFactory(
98              String webSocketURL, String subprotocols, boolean allowExtensions,
99              int maxFramePayloadLength, boolean allowMaskMismatch) {
100         this.webSocketURL = webSocketURL;
101         this.subprotocols = subprotocols;
102         this.allowExtensions = allowExtensions;
103         this.maxFramePayloadLength = maxFramePayloadLength;
104         this.allowMaskMismatch = allowMaskMismatch;
105     }
106 
107     /**
108      * Instances a new handshaker
109      *
110      * @return A new WebSocketServerHandshaker for the requested web socket version. Null if web
111      *         socket version is not supported.
112      */
113     public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
114 
115         CharSequence version = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_VERSION);
116         if (version != null) {
117             if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
118                 // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification).
119                 return new WebSocketServerHandshaker13(
120                         webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength, allowMaskMismatch);
121             } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) {
122                 // Version 8 of the wire protocol - version 10 of the draft hybi specification.
123                 return new WebSocketServerHandshaker08(
124                         webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength, allowMaskMismatch);
125             } else if (version.equals(WebSocketVersion.V07.toHttpHeaderValue())) {
126                 // Version 8 of the wire protocol - version 07 of the draft hybi specification.
127                 return new WebSocketServerHandshaker07(
128                         webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength, allowMaskMismatch);
129             } else {
130                 return null;
131             }
132         } else {
133             // Assume version 00 where version header was not specified
134             return new WebSocketServerHandshaker00(webSocketURL, subprotocols, maxFramePayloadLength);
135         }
136     }
137 
138     /**
139      * Return that we need cannot not support the web socket version
140      */
141     public static ChannelFuture sendUnsupportedVersionResponse(Channel channel) {
142         return sendUnsupportedVersionResponse(channel, channel.newPromise());
143     }
144 
145     /**
146      * Return that we need cannot not support the web socket version
147      */
148     public static ChannelFuture sendUnsupportedVersionResponse(Channel channel, ChannelPromise promise) {
149         HttpResponse res = new DefaultHttpResponse(
150                 HttpVersion.HTTP_1_1,
151                 HttpResponseStatus.UPGRADE_REQUIRED);
152         res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
153         return channel.write(res, promise);
154     }
155 }