Example #1
0
 def _skip_spaces(self):
     # 4.1 35. read a byte from the server
     while True:
         ch = _receive_bytes(self._socket, 1)
         if ch == ' ':  # 0x20
             continue
         return ch
Example #2
0
 def _read_fields(self):
     # 4.1 32. let /fields/ be a list of name-value pairs, initially empty.
     fields = {}
     while True:  # "Field"
         # 4.1 33. let /name/ and /value/ be empty byte arrays
         name = ''
         value = ''
         # 4.1 34. read /name/
         name = self._read_name()
         if name is None:
             break
             # 4.1 35. read spaces
         # TODO(tyoshino): Skip only one space as described in the spec.
         ch = self._skip_spaces()
         # 4.1 36. read /value/
         value = self._read_value(ch)
         # 4.1 37. read a byte from the server
         ch = _receive_bytes(self._socket, 1)
         if ch != '\n':  # 0x0A
             raise ClientHandshakeError(
                 'Expected LF but found %r while reading value %r for '
                 'header %r' % (ch, value, name))
         self._logger.debug('Received %r header', name)
         # 4.1 38. append an entry to the /fields/ list that has the name
         # given by the string obtained by interpreting the /name/ byte
         # array as a UTF-8 stream and the value given by the string
         # obtained by interpreting the /value/ byte array as a UTF-8 byte
         # stream.
         fields.setdefault(name, []).append(value)
         # 4.1 39. return to the "Field" step above
     return fields
Example #3
0
 def _read_value(self, ch):
     # 4.1 33. let /value/ be empty byte arrays
     value = ''
     # 4.1 36. read a byte from server.
     while True:
         if ch == '\r':  # 0x0D
             return value
         elif ch == '\n':  # 0x0A
             raise ClientHandshakeError(
                 'Unexpected LF when reading header value %r' % value)
         else:
             value += ch
         ch = _receive_bytes(self._socket, 1)
Example #4
0
 def _read_name(self):
     # 4.1 33. let /name/ be empty byte arrays
     name = ''
     while True:
         # 4.1 34. read a byte from the server
         ch = _receive_bytes(self._socket, 1)
         if ch == '\r':  # 0x0D
             return None
         elif ch == '\n':  # 0x0A
             raise ClientHandshakeError(
                 'Unexpected LF when reading header name %r' % name)
         elif ch == ':':  # 0x3A
             return name
         elif ch >= 'A' and ch <= 'Z':  # Range 0x31 to 0x5A
             ch = chr(ord(ch) + 0x20)
             name += ch
         else:
             name += ch
    def handshake(self):
        """Performs opening handshake on the specified socket.

        Raises:
            ClientHandshakeError: handshake failed.
        """

        request_line = _build_method_line(self._options.get('resource'))
        self._logger.debug('Client\'s opening handshake Request-Line: %r',
            request_line)
        self._socket.sendall(request_line)

        fields = []
        fields.append(_format_host_header(
            self._options.get('server_host'),
            int(self._options.get('server_port')),
            self._options.get('use_tls')=='True'))
        fields.append(_UPGRADE_HEADER)
        fields.append(_CONNECTION_HEADER)
        if self._options.get('origin') is not None:
            if self._options.get('protocol_version') == _PROTOCOL_VERSION_HYBI08:
                fields.append(_origin_header(
                    common.SEC_WEBSOCKET_ORIGIN_HEADER,
                    self._options.get('origin')))
            else:
                fields.append(_origin_header(common.ORIGIN_HEADER,
                    self._options.get('origin')))

        original_key = os.urandom(16)
        self._key = base64.b64encode(original_key)
        self._logger.debug(
            '%s: %r (%s)',
            common.SEC_WEBSOCKET_KEY_HEADER,
            self._key,
            util.hexify(original_key))
        fields.append(
            '%s: %s\r\n' % (common.SEC_WEBSOCKET_KEY_HEADER, self._key))

        if int(self._options.get('version_header')) > 0:
            fields.append('%s: %d\r\n' % (common.SEC_WEBSOCKET_VERSION_HEADER,
                                          int(self._options.get('version_header'))))
        else:
            fields.append('%s: %d\r\n' % (common.SEC_WEBSOCKET_VERSION_HEADER,
                                          common.VERSION_HYBI_LATEST))

        extensions_to_request = []

        if self._options.get('deflate_stream') == 'True':
            extensions_to_request.append(
                common.ExtensionParameter(
                    common.DEFLATE_STREAM_EXTENSION))

        if self._options.get('deflate_frame') == 'True':
            extensions_to_request.append(
                common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION))

        if len(extensions_to_request) != 0:
            fields.append(
                '%s: %s\r\n' %
                (common.SEC_WEBSOCKET_EXTENSIONS_HEADER,
                 common.format_extensions(extensions_to_request)))

        for field in fields:
            self._socket.sendall(field)

        self._socket.sendall('\r\n')

        self._logger.debug('Sent client\'s opening handshake headers: %r',
            fields)
        self._logger.debug('Start reading Status-Line')

        status_line = ''
        while True:
            ch = _receive_bytes(self._socket, 1)
            status_line += ch
            if ch == '\n':
                break

        m = re.match('HTTP/\\d+\.\\d+ (\\d\\d\\d) .*\r\n', status_line)
        if m is None:
            raise ClientHandshakeError(
                'Wrong status line format: %r' % status_line)
        status_code = m.group(1)
        if status_code != '101':
            self._logger.debug('Unexpected status code %s with following '
                               'headers: %r', status_code, self._read_fields())
            raise ClientHandshakeError(
                'Expected HTTP status code 101 but found %r' % status_code)

        self._logger.debug('Received valid Status-Line')
        self._logger.debug('Start reading headers until we see an empty line')

        fields = self._read_fields()

        ch = _receive_bytes(self._socket, 1)
        if ch != '\n':  # 0x0A
            raise ClientHandshakeError(
                'Expected LF but found %r while reading value %r for header '
                'name %r' % (ch, value, name))

        self._logger.debug('Received an empty line')
        self._logger.debug('Server\'s opening handshake headers: %r', fields)

        _validate_mandatory_header(
            fields,
            common.UPGRADE_HEADER,
            common.WEBSOCKET_UPGRADE_TYPE,
            False)

        _validate_mandatory_header(
            fields,
            common.CONNECTION_HEADER,
            common.UPGRADE_CONNECTION_TYPE,
            False)

        accept = _get_mandatory_header(
            fields, common.SEC_WEBSOCKET_ACCEPT_HEADER)

        # Validate
        try:
            binary_accept = base64.b64decode(accept)
        except TypeError, e:
            raise HandshakeError(
                'Illegal value for header %s: %r' %
                (common.SEC_WEBSOCKET_ACCEPT_HEADER, accept))