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)
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)
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)
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)
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)
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)
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
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)
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)
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'])
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())