def fetch_message(self): """ Receive at least one message from the server, if available. :return: 2-tuple of number of detail messages and number of summary messages fetched """ if self._closed: raise ServiceUnavailable( "Failed to read from closed connection {!r} ({!r})".format( self.unresolved_address, self.server_info.address)) if self._defunct: raise ServiceUnavailable( "Failed to read from defunct connection {!r} ({!r})".format( self.unresolved_address, self.server_info.address)) if not self.responses: return 0, 0 # Receive exactly one message details, summary_signature, summary_metadata = next(self.inbox) if details: log.debug("[#%04X] S: RECORD * %d", self.local_port, len(details)) # Do not log any data self.responses[0].on_records(details) if summary_signature is None: return len(details), 0 response = self.responses.popleft() response.complete = True if summary_signature == b"\x70": log.debug("[#%04X] S: SUCCESS %r", self.local_port, summary_metadata) response.on_success(summary_metadata or {}) elif summary_signature == b"\x7E": log.debug("[#%04X] S: IGNORED", self.local_port) response.on_ignored(summary_metadata or {}) elif summary_signature == b"\x7F": log.debug("[#%04X] S: FAILURE %r", self.local_port, summary_metadata) try: response.on_failure(summary_metadata or {}) except (ServiceUnavailable, DatabaseUnavailable): if self.pool: self.pool.deactivate(address=self.unresolved_address), raise except (NotALeader, ForbiddenOnReadOnlyDatabase): if self.pool: self.pool.on_write_failure( address=self.unresolved_address), raise else: raise BoltProtocolError( "Unexpected response message with signature %02X" % summary_signature, address=self.unresolved_address) return len(details), 1
def _handshake(s, resolved_address): """ :param s: Socket :param resolved_address: :return: (socket, version, client_handshake, server_response_data) """ local_port = s.getsockname()[1] # TODO: Optimize logging code handshake = Bolt.get_handshake() import struct handshake = struct.unpack(">16B", handshake) handshake = [handshake[i:i + 4] for i in range(0, len(handshake), 4)] supported_versions = [("0x%02X%02X%02X%02X" % (vx[0], vx[1], vx[2], vx[3])) for vx in handshake] log.debug("[#%04X] C: <MAGIC> 0x%08X", local_port, int.from_bytes(Bolt.MAGIC_PREAMBLE, byteorder="big")) log.debug("[#%04X] C: <HANDSHAKE> %s %s %s %s", local_port, *supported_versions) data = Bolt.MAGIC_PREAMBLE + Bolt.get_handshake() s.sendall(data) # Handle the handshake response ready_to_read = False while not ready_to_read: ready_to_read, _, _ = select((s,), (), (), 1) try: data = s.recv(4) except OSError: raise ServiceUnavailable("Failed to read any data from server {!r} " "after connected".format(resolved_address)) data_size = len(data) if data_size == 0: # If no data is returned after a successful select # response, the server has closed the connection log.debug("[#%04X] S: <CLOSE>", local_port) s.close() raise BoltHandshakeError("Connection to {address} closed without handshake response".format(address=resolved_address), address=resolved_address, request_data=handshake, response_data=None) if data_size != 4: # Some garbled data has been received log.debug("[#%04X] S: @*#!", local_port) s.close() raise BoltProtocolError("Expected four byte Bolt handshake response from %r, received %r instead; check for incorrect port number" % (resolved_address, data), address=resolved_address) elif data == b"HTTP": log.debug("[#%04X] S: <CLOSE>", local_port) s.close() raise ServiceUnavailable("Cannot to connect to Bolt service on {!r} " "(looks like HTTP)".format(resolved_address)) agreed_version = data[-1], data[-2] log.debug("[#%04X] S: <HANDSHAKE> 0x%06X%02X", local_port, agreed_version[1], agreed_version[0]) return s, agreed_version, handshake, data
def test_bolt_protocol_error(): with pytest.raises(BoltProtocolError) as e: error = BoltProtocolError( "Driver does not support Bolt protocol version: 0x%06X%02X" % (2, 5), address="localhost") assert error.address == "localhost" raise error # The regexp parameter of the match method is matched with the re.search function. with pytest.raises(AssertionError): e.match("FAIL!") e.match("Driver does not support Bolt protocol version: 0x00000205")
def test_serviceunavailable_raised_from_bolt_protocol_error_with_implicit_style( ): error = BoltProtocolError( "Driver does not support Bolt protocol version: 0x%06X%02X" % (2, 5), address="localhost") with pytest.raises(ServiceUnavailable) as e: assert error.address == "localhost" try: raise error except BoltProtocolError as error_bolt_protocol: raise ServiceUnavailable( str(error_bolt_protocol)) from error_bolt_protocol # The regexp parameter of the match method is matched with the re.search function. with pytest.raises(AssertionError): e.match("FAIL!") e.match("Driver does not support Bolt protocol version: 0x00000205") assert e.value.__cause__ is error
def _secure(s, host, ssl_context): local_port = s.getsockname()[1] # Secure the connection if an SSL context has been provided if ssl_context: log.debug("[#%04X] C: <SECURE> %s", local_port, host) try: sni_host = host if HAS_SNI and host else None s = ssl_context.wrap_socket(s, server_hostname=sni_host) except (SSLError, OSError) as cause: s.close() error = BoltSecurityError(message="Failed to establish encrypted connection.", address=(host, local_port)) error.__cause__ = cause raise error else: # Check that the server provides a certificate der_encoded_server_certificate = s.getpeercert(binary_form=True) if der_encoded_server_certificate is None: s.close() raise BoltProtocolError("When using an encrypted socket, the server should always provide a certificate", address=(host, local_port)) return s
def fail(metadata): raise BoltProtocolError("RESET failed %r" % metadata, self.unresolved_address)