| 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 |