OLD | NEW |
1 # Copyright 2012, Google Inc. | 1 # Copyright 2012, Google Inc. |
2 # All rights reserved. | 2 # All rights reserved. |
3 # | 3 # |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 from mod_pywebsocket.stream import StreamOptions | 62 from mod_pywebsocket.stream import StreamOptions |
63 from mod_pywebsocket import util | 63 from mod_pywebsocket import util |
64 | 64 |
65 | 65 |
66 # Used to validate the value in the Sec-WebSocket-Key header strictly. RFC 4648 | 66 # Used to validate the value in the Sec-WebSocket-Key header strictly. RFC 4648 |
67 # disallows non-zero padding, so the character right before == must be any of | 67 # disallows non-zero padding, so the character right before == must be any of |
68 # A, Q, g and w. | 68 # A, Q, g and w. |
69 _SEC_WEBSOCKET_KEY_REGEX = re.compile('^[+/0-9A-Za-z]{21}[AQgw]==$') | 69 _SEC_WEBSOCKET_KEY_REGEX = re.compile('^[+/0-9A-Za-z]{21}[AQgw]==$') |
70 | 70 |
71 # Defining aliases for values used frequently. | 71 # Defining aliases for values used frequently. |
72 _VERSION_HYBI08 = common.VERSION_HYBI08 | |
73 _VERSION_HYBI08_STRING = str(_VERSION_HYBI08) | |
74 _VERSION_LATEST = common.VERSION_HYBI_LATEST | 72 _VERSION_LATEST = common.VERSION_HYBI_LATEST |
75 _VERSION_LATEST_STRING = str(_VERSION_LATEST) | 73 _VERSION_LATEST_STRING = str(_VERSION_LATEST) |
76 _SUPPORTED_VERSIONS = [ | 74 _SUPPORTED_VERSIONS = [ |
77 _VERSION_LATEST, | 75 _VERSION_LATEST, |
78 _VERSION_HYBI08, | |
79 ] | 76 ] |
80 | 77 |
81 | 78 |
82 def compute_accept(key): | 79 def compute_accept(key): |
83 """Computes value for the Sec-WebSocket-Accept header from value of the | 80 """Computes value for the Sec-WebSocket-Accept header from value of the |
84 Sec-WebSocket-Key header. | 81 Sec-WebSocket-Key header. |
85 """ | 82 """ |
86 | 83 |
87 accept_binary = util.sha1_hash( | 84 accept_binary = util.sha1_hash( |
88 key + common.WEBSOCKET_ACCEPT_UUID).digest() | 85 key + common.WEBSOCKET_ACCEPT_UUID).digest() |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 common.WEBSOCKET_UPGRADE_TYPE) | 140 common.WEBSOCKET_UPGRADE_TYPE) |
144 | 141 |
145 self._validate_connection_header() | 142 self._validate_connection_header() |
146 | 143 |
147 self._request.ws_resource = self._request.uri | 144 self._request.ws_resource = self._request.uri |
148 | 145 |
149 unused_host = get_mandatory_header(self._request, common.HOST_HEADER) | 146 unused_host = get_mandatory_header(self._request, common.HOST_HEADER) |
150 | 147 |
151 self._request.ws_version = self._check_version() | 148 self._request.ws_version = self._check_version() |
152 | 149 |
153 # This handshake must be based on latest hybi. We are responsible to | |
154 # fallback to HTTP on handshake failure as latest hybi handshake | |
155 # specifies. | |
156 try: | 150 try: |
157 self._get_origin() | 151 self._get_origin() |
158 self._set_protocol() | 152 self._set_protocol() |
159 self._parse_extensions() | 153 self._parse_extensions() |
160 | 154 |
161 # Key validation, response generation. | 155 # Key validation, response generation. |
162 | 156 |
163 key = self._get_key() | 157 key = self._get_key() |
164 (accept, accept_binary) = compute_accept(key) | 158 (accept, accept_binary) = compute_accept(key) |
165 self._logger.debug( | 159 self._logger.debug( |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 'request any subprotocol') | 273 'request any subprotocol') |
280 | 274 |
281 self._send_handshake(accept) | 275 self._send_handshake(accept) |
282 except HandshakeException, e: | 276 except HandshakeException, e: |
283 if not e.status: | 277 if not e.status: |
284 # Fallback to 400 bad request by default. | 278 # Fallback to 400 bad request by default. |
285 e.status = common.HTTP_STATUS_BAD_REQUEST | 279 e.status = common.HTTP_STATUS_BAD_REQUEST |
286 raise e | 280 raise e |
287 | 281 |
288 def _get_origin(self): | 282 def _get_origin(self): |
289 if self._request.ws_version is _VERSION_HYBI08: | 283 origin_header = common.ORIGIN_HEADER |
290 origin_header = common.SEC_WEBSOCKET_ORIGIN_HEADER | |
291 else: | |
292 origin_header = common.ORIGIN_HEADER | |
293 origin = self._request.headers_in.get(origin_header) | 284 origin = self._request.headers_in.get(origin_header) |
294 if origin is None: | 285 if origin is None: |
295 self._logger.debug('Client request does not have origin header') | 286 self._logger.debug('Client request does not have origin header') |
296 self._request.ws_origin = origin | 287 self._request.ws_origin = origin |
297 | 288 |
298 def _check_version(self): | 289 def _check_version(self): |
299 version = get_mandatory_header(self._request, | 290 version = get_mandatory_header(self._request, |
300 common.SEC_WEBSOCKET_VERSION_HEADER) | 291 common.SEC_WEBSOCKET_VERSION_HEADER) |
301 if version == _VERSION_HYBI08_STRING: | |
302 return _VERSION_HYBI08 | |
303 if version == _VERSION_LATEST_STRING: | 292 if version == _VERSION_LATEST_STRING: |
304 return _VERSION_LATEST | 293 return _VERSION_LATEST |
305 | 294 |
306 if version.find(',') >= 0: | 295 if version.find(',') >= 0: |
307 raise HandshakeException( | 296 raise HandshakeException( |
308 'Multiple versions (%r) are not allowed for header %s' % | 297 'Multiple versions (%r) are not allowed for header %s' % |
309 (version, common.SEC_WEBSOCKET_VERSION_HEADER), | 298 (version, common.SEC_WEBSOCKET_VERSION_HEADER), |
310 status=common.HTTP_STATUS_BAD_REQUEST) | 299 status=common.HTTP_STATUS_BAD_REQUEST) |
311 raise VersionException( | 300 raise VersionException( |
312 'Unsupported version %r for header %s' % | 301 'Unsupported version %r for header %s' % |
(...skipping 15 matching lines...) Expand all Loading... |
328 self._logger.debug('Subprotocols requested: %r', | 317 self._logger.debug('Subprotocols requested: %r', |
329 self._request.ws_requested_protocols) | 318 self._request.ws_requested_protocols) |
330 | 319 |
331 def _parse_extensions(self): | 320 def _parse_extensions(self): |
332 extensions_header = self._request.headers_in.get( | 321 extensions_header = self._request.headers_in.get( |
333 common.SEC_WEBSOCKET_EXTENSIONS_HEADER) | 322 common.SEC_WEBSOCKET_EXTENSIONS_HEADER) |
334 if not extensions_header: | 323 if not extensions_header: |
335 self._request.ws_requested_extensions = None | 324 self._request.ws_requested_extensions = None |
336 return | 325 return |
337 | 326 |
338 if self._request.ws_version is common.VERSION_HYBI08: | |
339 allow_quoted_string=False | |
340 else: | |
341 allow_quoted_string=True | |
342 try: | 327 try: |
343 self._request.ws_requested_extensions = common.parse_extensions( | 328 self._request.ws_requested_extensions = common.parse_extensions( |
344 extensions_header, allow_quoted_string=allow_quoted_string) | 329 extensions_header) |
345 except common.ExtensionParsingException, e: | 330 except common.ExtensionParsingException, e: |
346 raise HandshakeException( | 331 raise HandshakeException( |
347 'Failed to parse Sec-WebSocket-Extensions header: %r' % e) | 332 'Failed to parse Sec-WebSocket-Extensions header: %r' % e) |
348 | 333 |
349 self._logger.debug( | 334 self._logger.debug( |
350 'Extensions requested: %r', | 335 'Extensions requested: %r', |
351 map(common.ExtensionParameter.name, | 336 map(common.ExtensionParameter.name, |
352 self._request.ws_requested_extensions)) | 337 self._request.ws_requested_extensions)) |
353 | 338 |
354 def _validate_key(self, key): | 339 def _validate_key(self, key): |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 return ''.join(response) | 411 return ''.join(response) |
427 | 412 |
428 def _send_handshake(self, accept): | 413 def _send_handshake(self, accept): |
429 raw_response = self._create_handshake_response(accept) | 414 raw_response = self._create_handshake_response(accept) |
430 self._request.connection.write(raw_response) | 415 self._request.connection.write(raw_response) |
431 self._logger.debug('Sent server\'s opening handshake: %r', | 416 self._logger.debug('Sent server\'s opening handshake: %r', |
432 raw_response) | 417 raw_response) |
433 | 418 |
434 | 419 |
435 # vi:sts=4 sw=4 et | 420 # vi:sts=4 sw=4 et |
OLD | NEW |