def process_subprotocol(headers, available_subprotocols): """ Handle the Sec-WebSocket-Protocol HTTP response header. Check that it contains exactly one supported subprotocol. Return the selected subprotocol. """ subprotocol = None header_values = headers.get_all('Sec-WebSocket-Protocol') if header_values is not None: if available_subprotocols is None: raise InvalidHandshake("No subprotocols supported") parsed_header_values = sum([ parse_subprotocol_list(header_value) for header_value in header_values ], []) if len(parsed_header_values) > 1: raise InvalidHandshake("Multiple subprotocols: {}".format( ', '.join(parsed_header_values))) subprotocol = parsed_header_values[0] if subprotocol not in available_subprotocols: raise NegotiationError( "Unsupported subprotocol: {}".format(subprotocol)) return subprotocol
async def handshake(self, *args, **kwargs): await WebSocketClientProtocol.handshake(self, *args, **kwargs) await self.send( ejson.dumps( { "msg": "connect", "version": "1", "support": ["1"], } ) ) recv = ejson.loads(await self.recv()) if recv["msg"] != "connected": await self.close() raise NegotiationError("Unable to connect.") asyncio.create_task(self._websocket_message_handler()) result = await self._authenticate() if not result: await self.close() raise SecurityError("Unable to authenticate.")
def process_extensions(headers, available_extensions): """ Handle the Sec-WebSocket-Extensions HTTP response header. Check that each extension is supported, as well as its parameters. Return the list of accepted extensions. Raise :exc:`~websockets.exceptions.InvalidHandshake` to abort the connection. :rfc:`6455` leaves the rules up to the specification of each :extension. To provide this level of flexibility, for each extension accepted by the server, we check for a match with each extension available in the client configuration. If no match is found, an exception is raised. If several variants of the same extension are accepted by the server, it may be configured severel times, which won't make sense in general. Extensions must implement their own requirements. For this purpose, the list of previously accepted extensions is provided. Other requirements, for example related to mandatory extensions or the order of extensions, may be implemented by overriding this method. """ accepted_extensions = [] header_values = headers.get_all('Sec-WebSocket-Extensions') if header_values is not None: if available_extensions is None: raise InvalidHandshake("No extensions supported") parsed_header_values = sum([ parse_extension_list(header_value) for header_value in header_values ], []) for name, response_params in parsed_header_values: for extension_factory in available_extensions: # Skip non-matching extensions based on their name. if extension_factory.name != name: continue # Skip non-matching extensions based on their params. try: extension = extension_factory.process_response_params( response_params, accepted_extensions) except NegotiationError: continue # Add matching extension to the final list. accepted_extensions.append(extension) # Break out of the loop once we have a match. break # If we didn't break from the loop, no extension in our list # matched what the server sent. Fail the connection. else: raise NegotiationError( "Unsupported extension: name = {}, params = {}".format( name, response_params)) return accepted_extensions
def process_response_params(self, params, accepted_extensions): if params: raise NegotiationError() return NoOpExtension()
def process_request_params(self, params, accepted_extensions): if params != [("op", self.op)]: raise NegotiationError() return [("op", self.op)], OpExtension(self.op)