Example #1
0
    def __init__(self, request, dispatcher, allowDraft75=False, strict=False):
        """Construct an instance.

        Args:
            request: mod_python request.
            dispatcher: Dispatcher (dispatch.Dispatcher).
            allowDraft75: allow draft 75 handshake protocol.
            strict: Strictly check handshake request in draft 75.
                Default: False. If True, request.connection must provide
                get_memorized_lines method.

        Handshaker will add attributes such as ws_resource in performing
        handshake.
        """

        self._logger = util.get_class_logger(self)

        self._request = request
        self._dispatcher = dispatcher
        self._strict = strict
        self._hybi07Handshaker = hybi06.Handshaker(request, dispatcher)
        self._hybi00Handshaker = hybi00.Handshaker(request, dispatcher)
        self._hixie75Handshaker = None
        if allowDraft75:
            self._hixie75Handshaker = draft75.Handshaker(
                request, dispatcher, strict)
Example #2
0
 def test_good_request_with_nonprintable_key(self):
     request = _create_request(_GOOD_REQUEST_WITH_NONPRINTABLE_KEY)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_WITH_NONPRINTABLE_KEY,
                      request.connection.written_data())
     self.assertEqual('sample', request.ws_protocol)
Example #3
0
 def test_good_request_default_no_protocol(self):
     request = _create_request(_GOOD_REQUEST_NO_PROTOCOL)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_NO_PROTOCOL,
                      request.connection.written_data())
     self.assertEqual(None, request.ws_protocol)
Example #4
0
 def test_good_request_nondefault_port(self):
     request = _create_request(_GOOD_REQUEST_NONDEFAULT_PORT)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_NONDEFAULT_PORT,
                      request.connection.written_data())
     self.assertEqual('sample', request.ws_protocol)
Example #5
0
 def test_good_request_secure_default_port(self):
     request = _create_request(_GOOD_REQUEST)
     request.connection.local_addr = ('0.0.0.0', 443)
     request.is_https_ = True
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_SECURE,
                      request.connection.written_data())
     self.assertEqual('sample', request.ws_protocol)
Example #6
0
 def test_good_request_default_port(self):
     request = _create_request(_GOOD_REQUEST)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_DEFAULT_PORT,
                      request.connection.written_data())
     self.assertEqual('/demo', request.ws_resource)
     self.assertEqual('http://example.com', request.ws_origin)
     self.assertEqual('ws://example.com/demo', request.ws_location)
     self.assertEqual('sample', request.ws_protocol)
Example #7
0
def do_handshake(request, dispatcher, allowDraft75=False, strict=False):
    """Performs WebSocket handshake.

    Args:
        request: mod_python request.
        dispatcher: Dispatcher (dispatch.Dispatcher).
        allowDraft75: allow draft 75 handshake protocol.
        strict: Strictly check handshake request in draft 75.
            Default: False. If True, request.connection must provide
            get_memorized_lines method.

    Handshaker will add attributes such as ws_resource in performing
    handshake.
    """

    _LOGGER.debug('Client\'s opening handshake resource: %r', request.uri)
    # To print mimetools.Message as escaped one-line string, we converts
    # headers_in to dict object. Without conversion, if we use %r, it just
    # prints the type and address, and if we use %s, it prints the original
    # header string as multiple lines.
    #
    # Both mimetools.Message and MpTable_Type of mod_python can be
    # converted to dict.
    #
    # mimetools.Message.__str__ returns the original header string.
    # dict(mimetools.Message object) returns the map from header names to
    # header values. While MpTable_Type doesn't have such __str__ but just
    # __repr__ which formats itself as well as dictionary object.
    _LOGGER.debug('Client\'s opening handshake headers: %r',
                  dict(request.headers_in))

    handshakers = []
    handshakers.append(
        ('IETF HyBi latest', hybi.Handshaker(request, dispatcher)))
    handshakers.append(('IETF HyBi 00', hybi00.Handshaker(request,
                                                          dispatcher)))
    if allowDraft75:
        handshakers.append(
            ('IETF Hixie 75', draft75.Handshaker(request, dispatcher, strict)))

    for name, handshaker in handshakers:
        _LOGGER.debug('Trying %s protocol', name)
        try:
            handshaker.do_handshake()
            _LOGGER.info('Established (%s protocol)', name)
            return
        except HandshakeException, e:
            _LOGGER.debug(
                'Failed to complete opening handshake as %s protocol: %r',
                name, e)
            if e.status:
                raise e
        except AbortedByUserException, e:
            raise
Example #8
0
def do_handshake(request, dispatcher, allowDraft75=False, strict=False):
    """Performs WebSocket handshake.

    Args:
        request: mod_python request.
        dispatcher: Dispatcher (dispatch.Dispatcher).
        allowDraft75: obsolete argument. ignored.
        strict: obsolete argument. ignored.

    Handshaker will add attributes such as ws_resource in performing
    handshake.
    """

    _LOGGER.debug('Client\'s opening handshake resource: %r', request.uri)
    # To print mimetools.Message as escaped one-line string, we converts
    # headers_in to dict object. Without conversion, if we use %r, it just
    # prints the type and address, and if we use %s, it prints the original
    # header string as multiple lines.
    #
    # Both mimetools.Message and MpTable_Type of mod_python can be
    # converted to dict.
    #
    # mimetools.Message.__str__ returns the original header string.
    # dict(mimetools.Message object) returns the map from header names to
    # header values. While MpTable_Type doesn't have such __str__ but just
    # __repr__ which formats itself as well as dictionary object.
    _LOGGER.debug('Client\'s opening handshake headers: %r',
                  dict(request.headers_in))

    handshakers = []
    handshakers.append(('RFC 6455', hybi.Handshaker(request, dispatcher)))
    handshakers.append(('HyBi 00', hybi00.Handshaker(request, dispatcher)))

    for name, handshaker in handshakers:
        _LOGGER.debug('Trying protocol version %s', name)
        try:
            handshaker.do_handshake()
            _LOGGER.info('Established (%s protocol)', name)
            return
        except HandshakeException as e:
            _LOGGER.debug(
                'Failed to complete opening handshake as %s protocol: %r',
                name, e)
            if e.status:
                raise e
        except AbortedByUserException as e:
            raise
        except VersionException as e:
            raise

    # TODO(toyoshim): Add a test to cover the case all handshakers fail.
    raise HandshakeException(
        'Failed to complete opening handshake for all available protocols',
        status=common.HTTP_STATUS_BAD_REQUEST)
Example #9
0
 def test_bad_requests(self):
     for request in map(_create_request, _BAD_REQUESTS):
         handshaker = handshake.Handshaker(request, mock.MockDispatcher())
         self.assertRaises(HandshakeException, handshaker.do_handshake)
Example #10
0
 def test_good_request_optional_headers(self):
     request = _create_request(_GOOD_REQUEST_WITH_OPTIONAL_HEADERS)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual('AValue', request.headers_in['AKey'])
     self.assertEqual('', request.headers_in['EmptyValue'])
Example #11
0
 def test_good_request_capitalized_header_values(self):
     request = _create_request(_GOOD_REQUEST_CAPITALIZED_HEADER_VALUES)
     handshaker = handshake.Handshaker(request, mock.MockDispatcher())
     handshaker.do_handshake()
     self.assertEqual(_GOOD_RESPONSE_DEFAULT_PORT,
                      request.connection.written_data())