Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | # Copyright 2012, Google Inc. |
michael@0 | 2 | # All rights reserved. |
michael@0 | 3 | # |
michael@0 | 4 | # Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | # modification, are permitted provided that the following conditions are |
michael@0 | 6 | # met: |
michael@0 | 7 | # |
michael@0 | 8 | # * Redistributions of source code must retain the above copyright |
michael@0 | 9 | # notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | # * Redistributions in binary form must reproduce the above |
michael@0 | 11 | # copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | # in the documentation and/or other materials provided with the |
michael@0 | 13 | # distribution. |
michael@0 | 14 | # * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | # contributors may be used to endorse or promote products derived from |
michael@0 | 16 | # this software without specific prior written permission. |
michael@0 | 17 | # |
michael@0 | 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | |
michael@0 | 31 | # Constants indicating WebSocket protocol version. |
michael@0 | 32 | VERSION_HIXIE75 = -1 |
michael@0 | 33 | VERSION_HYBI00 = 0 |
michael@0 | 34 | VERSION_HYBI01 = 1 |
michael@0 | 35 | VERSION_HYBI02 = 2 |
michael@0 | 36 | VERSION_HYBI03 = 2 |
michael@0 | 37 | VERSION_HYBI04 = 4 |
michael@0 | 38 | VERSION_HYBI05 = 5 |
michael@0 | 39 | VERSION_HYBI06 = 6 |
michael@0 | 40 | VERSION_HYBI07 = 7 |
michael@0 | 41 | VERSION_HYBI08 = 8 |
michael@0 | 42 | VERSION_HYBI09 = 8 |
michael@0 | 43 | VERSION_HYBI10 = 8 |
michael@0 | 44 | VERSION_HYBI11 = 8 |
michael@0 | 45 | VERSION_HYBI12 = 8 |
michael@0 | 46 | VERSION_HYBI13 = 13 |
michael@0 | 47 | VERSION_HYBI14 = 13 |
michael@0 | 48 | VERSION_HYBI15 = 13 |
michael@0 | 49 | VERSION_HYBI16 = 13 |
michael@0 | 50 | VERSION_HYBI17 = 13 |
michael@0 | 51 | |
michael@0 | 52 | # Constants indicating WebSocket protocol latest version. |
michael@0 | 53 | VERSION_HYBI_LATEST = VERSION_HYBI13 |
michael@0 | 54 | |
michael@0 | 55 | # Port numbers |
michael@0 | 56 | DEFAULT_WEB_SOCKET_PORT = 80 |
michael@0 | 57 | DEFAULT_WEB_SOCKET_SECURE_PORT = 443 |
michael@0 | 58 | |
michael@0 | 59 | # Schemes |
michael@0 | 60 | WEB_SOCKET_SCHEME = 'ws' |
michael@0 | 61 | WEB_SOCKET_SECURE_SCHEME = 'wss' |
michael@0 | 62 | |
michael@0 | 63 | # Frame opcodes defined in the spec. |
michael@0 | 64 | OPCODE_CONTINUATION = 0x0 |
michael@0 | 65 | OPCODE_TEXT = 0x1 |
michael@0 | 66 | OPCODE_BINARY = 0x2 |
michael@0 | 67 | OPCODE_CLOSE = 0x8 |
michael@0 | 68 | OPCODE_PING = 0x9 |
michael@0 | 69 | OPCODE_PONG = 0xa |
michael@0 | 70 | |
michael@0 | 71 | # UUIDs used by HyBi 04 and later opening handshake and frame masking. |
michael@0 | 72 | WEBSOCKET_ACCEPT_UUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' |
michael@0 | 73 | |
michael@0 | 74 | # Opening handshake header names and expected values. |
michael@0 | 75 | UPGRADE_HEADER = 'Upgrade' |
michael@0 | 76 | WEBSOCKET_UPGRADE_TYPE = 'websocket' |
michael@0 | 77 | WEBSOCKET_UPGRADE_TYPE_HIXIE75 = 'WebSocket' |
michael@0 | 78 | CONNECTION_HEADER = 'Connection' |
michael@0 | 79 | UPGRADE_CONNECTION_TYPE = 'Upgrade' |
michael@0 | 80 | HOST_HEADER = 'Host' |
michael@0 | 81 | ORIGIN_HEADER = 'Origin' |
michael@0 | 82 | SEC_WEBSOCKET_ORIGIN_HEADER = 'Sec-WebSocket-Origin' |
michael@0 | 83 | SEC_WEBSOCKET_KEY_HEADER = 'Sec-WebSocket-Key' |
michael@0 | 84 | SEC_WEBSOCKET_ACCEPT_HEADER = 'Sec-WebSocket-Accept' |
michael@0 | 85 | SEC_WEBSOCKET_VERSION_HEADER = 'Sec-WebSocket-Version' |
michael@0 | 86 | SEC_WEBSOCKET_PROTOCOL_HEADER = 'Sec-WebSocket-Protocol' |
michael@0 | 87 | SEC_WEBSOCKET_EXTENSIONS_HEADER = 'Sec-WebSocket-Extensions' |
michael@0 | 88 | SEC_WEBSOCKET_DRAFT_HEADER = 'Sec-WebSocket-Draft' |
michael@0 | 89 | SEC_WEBSOCKET_KEY1_HEADER = 'Sec-WebSocket-Key1' |
michael@0 | 90 | SEC_WEBSOCKET_KEY2_HEADER = 'Sec-WebSocket-Key2' |
michael@0 | 91 | SEC_WEBSOCKET_LOCATION_HEADER = 'Sec-WebSocket-Location' |
michael@0 | 92 | |
michael@0 | 93 | # Extensions |
michael@0 | 94 | DEFLATE_STREAM_EXTENSION = 'deflate-stream' |
michael@0 | 95 | DEFLATE_FRAME_EXTENSION = 'deflate-frame' |
michael@0 | 96 | X_WEBKIT_DEFLATE_FRAME_EXTENSION = 'x-webkit-deflate-frame' |
michael@0 | 97 | |
michael@0 | 98 | # Status codes |
michael@0 | 99 | # Code STATUS_NO_STATUS_RECEIVED, STATUS_ABNORMAL_CLOSURE, and |
michael@0 | 100 | # STATUS_TLS_HANDSHAKE are pseudo codes to indicate specific error cases. |
michael@0 | 101 | # Could not be used for codes in actual closing frames. |
michael@0 | 102 | # Application level errors must use codes in the range |
michael@0 | 103 | # STATUS_USER_REGISTERED_BASE to STATUS_USER_PRIVATE_MAX. The codes in the |
michael@0 | 104 | # range STATUS_USER_REGISTERED_BASE to STATUS_USER_REGISTERED_MAX are managed |
michael@0 | 105 | # by IANA. Usually application must define user protocol level errors in the |
michael@0 | 106 | # range STATUS_USER_PRIVATE_BASE to STATUS_USER_PRIVATE_MAX. |
michael@0 | 107 | STATUS_NORMAL_CLOSURE = 1000 |
michael@0 | 108 | STATUS_GOING_AWAY = 1001 |
michael@0 | 109 | STATUS_PROTOCOL_ERROR = 1002 |
michael@0 | 110 | STATUS_UNSUPPORTED_DATA = 1003 |
michael@0 | 111 | STATUS_NO_STATUS_RECEIVED = 1005 |
michael@0 | 112 | STATUS_ABNORMAL_CLOSURE = 1006 |
michael@0 | 113 | STATUS_INVALID_FRAME_PAYLOAD_DATA = 1007 |
michael@0 | 114 | STATUS_POLICY_VIOLATION = 1008 |
michael@0 | 115 | STATUS_MESSAGE_TOO_BIG = 1009 |
michael@0 | 116 | STATUS_MANDATORY_EXTENSION = 1010 |
michael@0 | 117 | STATUS_INTERNAL_SERVER_ERROR = 1011 |
michael@0 | 118 | STATUS_TLS_HANDSHAKE = 1015 |
michael@0 | 119 | STATUS_USER_REGISTERED_BASE = 3000 |
michael@0 | 120 | STATUS_USER_REGISTERED_MAX = 3999 |
michael@0 | 121 | STATUS_USER_PRIVATE_BASE = 4000 |
michael@0 | 122 | STATUS_USER_PRIVATE_MAX = 4999 |
michael@0 | 123 | # Following definitions are aliases to keep compatibility. Applications must |
michael@0 | 124 | # not use these obsoleted definitions anymore. |
michael@0 | 125 | STATUS_NORMAL = STATUS_NORMAL_CLOSURE |
michael@0 | 126 | STATUS_UNSUPPORTED = STATUS_UNSUPPORTED_DATA |
michael@0 | 127 | STATUS_CODE_NOT_AVAILABLE = STATUS_NO_STATUS_RECEIVED |
michael@0 | 128 | STATUS_ABNORMAL_CLOSE = STATUS_ABNORMAL_CLOSURE |
michael@0 | 129 | STATUS_INVALID_FRAME_PAYLOAD = STATUS_INVALID_FRAME_PAYLOAD_DATA |
michael@0 | 130 | STATUS_MANDATORY_EXT = STATUS_MANDATORY_EXTENSION |
michael@0 | 131 | |
michael@0 | 132 | # HTTP status codes |
michael@0 | 133 | HTTP_STATUS_BAD_REQUEST = 400 |
michael@0 | 134 | HTTP_STATUS_FORBIDDEN = 403 |
michael@0 | 135 | HTTP_STATUS_NOT_FOUND = 404 |
michael@0 | 136 | |
michael@0 | 137 | |
michael@0 | 138 | def is_control_opcode(opcode): |
michael@0 | 139 | return (opcode >> 3) == 1 |
michael@0 | 140 | |
michael@0 | 141 | |
michael@0 | 142 | class ExtensionParameter(object): |
michael@0 | 143 | """Holds information about an extension which is exchanged on extension |
michael@0 | 144 | negotiation in opening handshake. |
michael@0 | 145 | """ |
michael@0 | 146 | |
michael@0 | 147 | def __init__(self, name): |
michael@0 | 148 | self._name = name |
michael@0 | 149 | # TODO(tyoshino): Change the data structure to more efficient one such |
michael@0 | 150 | # as dict when the spec changes to say like |
michael@0 | 151 | # - Parameter names must be unique |
michael@0 | 152 | # - The order of parameters is not significant |
michael@0 | 153 | self._parameters = [] |
michael@0 | 154 | |
michael@0 | 155 | def name(self): |
michael@0 | 156 | return self._name |
michael@0 | 157 | |
michael@0 | 158 | def add_parameter(self, name, value): |
michael@0 | 159 | self._parameters.append((name, value)) |
michael@0 | 160 | |
michael@0 | 161 | def get_parameters(self): |
michael@0 | 162 | return self._parameters |
michael@0 | 163 | |
michael@0 | 164 | def get_parameter_names(self): |
michael@0 | 165 | return [name for name, unused_value in self._parameters] |
michael@0 | 166 | |
michael@0 | 167 | def has_parameter(self, name): |
michael@0 | 168 | for param_name, param_value in self._parameters: |
michael@0 | 169 | if param_name == name: |
michael@0 | 170 | return True |
michael@0 | 171 | return False |
michael@0 | 172 | |
michael@0 | 173 | def get_parameter_value(self, name): |
michael@0 | 174 | for param_name, param_value in self._parameters: |
michael@0 | 175 | if param_name == name: |
michael@0 | 176 | return param_value |
michael@0 | 177 | |
michael@0 | 178 | |
michael@0 | 179 | # vi:sts=4 sw=4 et |