michael@0: # Copyright 2012, Google Inc. michael@0: # All rights reserved. michael@0: # michael@0: # Redistribution and use in source and binary forms, with or without michael@0: # modification, are permitted provided that the following conditions are michael@0: # met: michael@0: # michael@0: # * Redistributions of source code must retain the above copyright michael@0: # notice, this list of conditions and the following disclaimer. michael@0: # * Redistributions in binary form must reproduce the above michael@0: # copyright notice, this list of conditions and the following disclaimer michael@0: # in the documentation and/or other materials provided with the michael@0: # distribution. michael@0: # * Neither the name of Google Inc. nor the names of its michael@0: # contributors may be used to endorse or promote products derived from michael@0: # this software without specific prior written permission. michael@0: # michael@0: # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: michael@0: # Constants indicating WebSocket protocol version. michael@0: VERSION_HIXIE75 = -1 michael@0: VERSION_HYBI00 = 0 michael@0: VERSION_HYBI01 = 1 michael@0: VERSION_HYBI02 = 2 michael@0: VERSION_HYBI03 = 2 michael@0: VERSION_HYBI04 = 4 michael@0: VERSION_HYBI05 = 5 michael@0: VERSION_HYBI06 = 6 michael@0: VERSION_HYBI07 = 7 michael@0: VERSION_HYBI08 = 8 michael@0: VERSION_HYBI09 = 8 michael@0: VERSION_HYBI10 = 8 michael@0: VERSION_HYBI11 = 8 michael@0: VERSION_HYBI12 = 8 michael@0: VERSION_HYBI13 = 13 michael@0: VERSION_HYBI14 = 13 michael@0: VERSION_HYBI15 = 13 michael@0: VERSION_HYBI16 = 13 michael@0: VERSION_HYBI17 = 13 michael@0: michael@0: # Constants indicating WebSocket protocol latest version. michael@0: VERSION_HYBI_LATEST = VERSION_HYBI13 michael@0: michael@0: # Port numbers michael@0: DEFAULT_WEB_SOCKET_PORT = 80 michael@0: DEFAULT_WEB_SOCKET_SECURE_PORT = 443 michael@0: michael@0: # Schemes michael@0: WEB_SOCKET_SCHEME = 'ws' michael@0: WEB_SOCKET_SECURE_SCHEME = 'wss' michael@0: michael@0: # Frame opcodes defined in the spec. michael@0: OPCODE_CONTINUATION = 0x0 michael@0: OPCODE_TEXT = 0x1 michael@0: OPCODE_BINARY = 0x2 michael@0: OPCODE_CLOSE = 0x8 michael@0: OPCODE_PING = 0x9 michael@0: OPCODE_PONG = 0xa michael@0: michael@0: # UUIDs used by HyBi 04 and later opening handshake and frame masking. michael@0: WEBSOCKET_ACCEPT_UUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' michael@0: michael@0: # Opening handshake header names and expected values. michael@0: UPGRADE_HEADER = 'Upgrade' michael@0: WEBSOCKET_UPGRADE_TYPE = 'websocket' michael@0: WEBSOCKET_UPGRADE_TYPE_HIXIE75 = 'WebSocket' michael@0: CONNECTION_HEADER = 'Connection' michael@0: UPGRADE_CONNECTION_TYPE = 'Upgrade' michael@0: HOST_HEADER = 'Host' michael@0: ORIGIN_HEADER = 'Origin' michael@0: SEC_WEBSOCKET_ORIGIN_HEADER = 'Sec-WebSocket-Origin' michael@0: SEC_WEBSOCKET_KEY_HEADER = 'Sec-WebSocket-Key' michael@0: SEC_WEBSOCKET_ACCEPT_HEADER = 'Sec-WebSocket-Accept' michael@0: SEC_WEBSOCKET_VERSION_HEADER = 'Sec-WebSocket-Version' michael@0: SEC_WEBSOCKET_PROTOCOL_HEADER = 'Sec-WebSocket-Protocol' michael@0: SEC_WEBSOCKET_EXTENSIONS_HEADER = 'Sec-WebSocket-Extensions' michael@0: SEC_WEBSOCKET_DRAFT_HEADER = 'Sec-WebSocket-Draft' michael@0: SEC_WEBSOCKET_KEY1_HEADER = 'Sec-WebSocket-Key1' michael@0: SEC_WEBSOCKET_KEY2_HEADER = 'Sec-WebSocket-Key2' michael@0: SEC_WEBSOCKET_LOCATION_HEADER = 'Sec-WebSocket-Location' michael@0: michael@0: # Extensions michael@0: DEFLATE_STREAM_EXTENSION = 'deflate-stream' michael@0: DEFLATE_FRAME_EXTENSION = 'deflate-frame' michael@0: X_WEBKIT_DEFLATE_FRAME_EXTENSION = 'x-webkit-deflate-frame' michael@0: michael@0: # Status codes michael@0: # Code STATUS_NO_STATUS_RECEIVED, STATUS_ABNORMAL_CLOSURE, and michael@0: # STATUS_TLS_HANDSHAKE are pseudo codes to indicate specific error cases. michael@0: # Could not be used for codes in actual closing frames. michael@0: # Application level errors must use codes in the range michael@0: # STATUS_USER_REGISTERED_BASE to STATUS_USER_PRIVATE_MAX. The codes in the michael@0: # range STATUS_USER_REGISTERED_BASE to STATUS_USER_REGISTERED_MAX are managed michael@0: # by IANA. Usually application must define user protocol level errors in the michael@0: # range STATUS_USER_PRIVATE_BASE to STATUS_USER_PRIVATE_MAX. michael@0: STATUS_NORMAL_CLOSURE = 1000 michael@0: STATUS_GOING_AWAY = 1001 michael@0: STATUS_PROTOCOL_ERROR = 1002 michael@0: STATUS_UNSUPPORTED_DATA = 1003 michael@0: STATUS_NO_STATUS_RECEIVED = 1005 michael@0: STATUS_ABNORMAL_CLOSURE = 1006 michael@0: STATUS_INVALID_FRAME_PAYLOAD_DATA = 1007 michael@0: STATUS_POLICY_VIOLATION = 1008 michael@0: STATUS_MESSAGE_TOO_BIG = 1009 michael@0: STATUS_MANDATORY_EXTENSION = 1010 michael@0: STATUS_INTERNAL_SERVER_ERROR = 1011 michael@0: STATUS_TLS_HANDSHAKE = 1015 michael@0: STATUS_USER_REGISTERED_BASE = 3000 michael@0: STATUS_USER_REGISTERED_MAX = 3999 michael@0: STATUS_USER_PRIVATE_BASE = 4000 michael@0: STATUS_USER_PRIVATE_MAX = 4999 michael@0: # Following definitions are aliases to keep compatibility. Applications must michael@0: # not use these obsoleted definitions anymore. michael@0: STATUS_NORMAL = STATUS_NORMAL_CLOSURE michael@0: STATUS_UNSUPPORTED = STATUS_UNSUPPORTED_DATA michael@0: STATUS_CODE_NOT_AVAILABLE = STATUS_NO_STATUS_RECEIVED michael@0: STATUS_ABNORMAL_CLOSE = STATUS_ABNORMAL_CLOSURE michael@0: STATUS_INVALID_FRAME_PAYLOAD = STATUS_INVALID_FRAME_PAYLOAD_DATA michael@0: STATUS_MANDATORY_EXT = STATUS_MANDATORY_EXTENSION michael@0: michael@0: # HTTP status codes michael@0: HTTP_STATUS_BAD_REQUEST = 400 michael@0: HTTP_STATUS_FORBIDDEN = 403 michael@0: HTTP_STATUS_NOT_FOUND = 404 michael@0: michael@0: michael@0: def is_control_opcode(opcode): michael@0: return (opcode >> 3) == 1 michael@0: michael@0: michael@0: class ExtensionParameter(object): michael@0: """Holds information about an extension which is exchanged on extension michael@0: negotiation in opening handshake. michael@0: """ michael@0: michael@0: def __init__(self, name): michael@0: self._name = name michael@0: # TODO(tyoshino): Change the data structure to more efficient one such michael@0: # as dict when the spec changes to say like michael@0: # - Parameter names must be unique michael@0: # - The order of parameters is not significant michael@0: self._parameters = [] michael@0: michael@0: def name(self): michael@0: return self._name michael@0: michael@0: def add_parameter(self, name, value): michael@0: self._parameters.append((name, value)) michael@0: michael@0: def get_parameters(self): michael@0: return self._parameters michael@0: michael@0: def get_parameter_names(self): michael@0: return [name for name, unused_value in self._parameters] michael@0: michael@0: def has_parameter(self, name): michael@0: for param_name, param_value in self._parameters: michael@0: if param_name == name: michael@0: return True michael@0: return False michael@0: michael@0: def get_parameter_value(self, name): michael@0: for param_name, param_value in self._parameters: michael@0: if param_name == name: michael@0: return param_value michael@0: michael@0: michael@0: # vi:sts=4 sw=4 et