def test_get_exception(self): ok_packet = '\x07\x00\x00\x01\x00\x01\x00\x00\x00\x01\x00' err_packet = '\x47\x00\x00\x02\xff\x15\x04\x23\x32\x38\x30\x30\x30'\ '\x41\x63\x63\x65\x73\x73\x20\x64\x65\x6e\x69\x65\x64'\ '\x20\x66\x6f\x72\x20\x75\x73\x65\x72\x20\x27\x68\x61'\ '\x6d\x27\x40\x27\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74'\ '\x27\x20\x28\x75\x73\x69\x6e\x67\x20\x70\x61\x73\x73'\ '\x77\x6f\x72\x64\x3a\x20\x59\x45\x53\x29' self.assertTrue( isinstance(errors.get_exception(err_packet), errors.ProgrammingError)) self.assertRaises(ValueError, errors.get_exception, ok_packet) res = errors.get_exception('\x47\x00\x00\x02\xff\x15') self.assertTrue(isinstance(res, errors.InterfaceError))
def test_get_exception(self): ok_packet = '\x07\x00\x00\x01\x00\x01\x00\x00\x00\x01\x00' err_packet = '\x47\x00\x00\x02\xff\x15\x04\x23\x32\x38\x30\x30\x30'\ '\x41\x63\x63\x65\x73\x73\x20\x64\x65\x6e\x69\x65\x64'\ '\x20\x66\x6f\x72\x20\x75\x73\x65\x72\x20\x27\x68\x61'\ '\x6d\x27\x40\x27\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74'\ '\x27\x20\x28\x75\x73\x69\x6e\x67\x20\x70\x61\x73\x73'\ '\x77\x6f\x72\x64\x3a\x20\x59\x45\x53\x29' self.assertTrue(isinstance(errors.get_exception(err_packet), errors.ProgrammingError)) self.assertRaises(ValueError, errors.get_exception, ok_packet) res = errors.get_exception('\x47\x00\x00\x02\xff\x15') self.assertTrue(isinstance(res, errors.InterfaceError))
def _do_handshake(self): """Get the handshake from the MySQL server""" packet = yield from self._socket.recv() if packet[4] == 255: raise errors.get_exception(packet) try: handshake = self._protocol.parse_handshake(packet) except Exception as err: raise errors.InterfaceError( 'Failed parsing handshake; {0}'.format(err)) regex_ver = re.compile(br"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)") match = regex_ver.match(handshake['server_version_original']) if not match: raise errors.InterfaceError("Failed parsing MySQL version") version = tuple([int(v) for v in match.groups()[0:3]]) if b'fabric' in match.group(4).lower(): if version < (1, 4): raise errors.InterfaceError( "MySQL Fabric '{0}'' is not supported".format( handshake['server_version_original'])) elif version < (4, 1): raise errors.InterfaceError( "MySQL Version '{0}' is not supported.".format( handshake['server_version_original'])) if handshake['capabilities'] & ClientFlag.PLUGIN_AUTH: self.set_client_flags([ClientFlag.PLUGIN_AUTH]) self._handshake = handshake self._server_version = version
def _handle_binary_result(self, packet): """Handle a MySQL Result This method handles a MySQL result, for example, after sending the query command. OK and EOF packets will be handled and returned. If the packet is an Error packet, an errors.Error-exception will be raised. The tuple returned by this method consist of: - the number of columns in the result, - a list of tuples with information about the columns, - the EOF packet information as a dictionary. Returns tuple() or dict() """ if not packet or len(packet) < 4: raise errors.InterfaceError('Empty response') elif packet[4] == 0: return self._handle_ok(packet) elif packet[4] == 254: return self._handle_eof(packet) elif packet[4] == 255: raise errors.get_exception(packet) # We have a binary result set column_count = self._protocol.parse_column_count(packet) if not column_count or not isinstance(column_count, int): raise errors.InterfaceError('Illegal result set.') columns = [None] * column_count for i in range(0, column_count): columns[i] = self._protocol.parse_column((yield from self._socket.recv())) eof = self._handle_eof((yield from self._socket.recv())) return (column_count, columns, eof)
def _auth_switch_request(self, username=None, password=None): """Handle second part of authentication Raises NotSupportedError when we get the old, insecure password reply back. Raises any error coming from MySQL. """ packet = yield from self._socket.recv() if packet[4] == 254 and len(packet) == 5: raise errors.NotSupportedError( "Authentication with old (insecure) passwords " "is not supported. For more information, lookup " "Password Hashing in the latest MySQL manual") elif packet[4] == 254: # AuthSwitchRequest (new_auth_plugin, auth_data) = self._protocol.parse_auth_switch_request(packet) auth = get_auth_plugin(new_auth_plugin)( auth_data, password=password, ssl_enabled=self._ssl_active) response = auth.auth_response() yield from self._socket.drain() if response == b'\x00': self._socket.send(b'') else: self._socket.send(response) packet = yield from self._socket.recv() if packet[4] != 1: return self._handle_ok(packet) else: auth_data = self._protocol.parse_auth_more_data(packet) elif packet[4] == 255: raise errors.get_exception(packet)
def _do_auth(self, username=None, password=None, database=None, client_flags=0, charset=33, ssl_options=None): """Authenticate with the MySQL server """ if client_flags & ClientFlag.SSL and ssl_options: packet = self._protocol.make_auth_ssl(charset=charset, client_flags=client_flags) self._socket.send(packet) self._socket.switch_to_ssl(**ssl_options) packet = self._protocol.make_auth( seed=self._handshake["scramble"], username=username, password=password, database=database, charset=charset, client_flags=client_flags, ) self._socket.send(packet) packet = self._socket.recv() if packet[4] == 254: raise errors.NotSupportedError( "Authentication with old (insecure) passwords " "is not supported. For more information, lookup " "Password Hashing in the latest MySQL manual" ) elif packet[4] == 255: raise errors.get_exception(packet) try: if not (client_flags & ClientFlag.CONNECT_WITH_DB) and database: self.cmd_init_db(database) except: raise return True
def _handle_binary_ok(self, packet): """Handle a MySQL Binary Protocol OK packet This method handles a MySQL Binary Protocol OK packet. When the packet is found to be an Error packet, an error will be raised. If the packet is neither an OK or an Error packet, errors.InterfaceError will be raised. Returns a dict() """ if packet[4] == 0: return self._protocol.parse_binary_prepare_ok(packet) elif packet[4] == 255: raise errors.get_exception(packet) raise errors.InterfaceError("Expected Binary OK packet")
def _handle_eof(self, packet): """Handle a MySQL EOF packet This method handles a MySQL EOF packet. When the packet is found to be an Error packet, an error will be raised. If the packet is neither and OK or an Error packet, errors.InterfaceError will be raised. Returns a dict() """ if packet[4] == 254: eof = self._protocol.parse_eof(packet) self._handle_server_status(eof["status_flag"]) return eof elif packet[4] == 255: raise errors.get_exception(packet) raise errors.InterfaceError("Expected EOF packet")
def _handle_ok(self, packet): """Handle a MySQL OK packet This method handles a MySQL OK packet. When the packet is found to be an Error packet, an error will be raised. If the packet is neither an OK or an Error packet, errors.InterfaceError will be raised. Returns a dict() """ if packet[4] == 0: ok = self._protocol.parse_ok(packet) self._handle_server_status(ok["server_status"]) return ok elif packet[4] == 255: raise errors.get_exception(packet) raise errors.InterfaceError("Expected OK packet")
def _handle_result(self, packet): """Handle a MySQL Result This method handles a MySQL result, for example, after sending the query command. OK and EOF packets will be handled and returned. If the packet is an Error packet, an errors.Error-exception will be raised. The dictionary returned of: - columns: column information - eof: the EOF-packet information Returns a dict() """ if not packet or len(packet) < 4: raise errors.InterfaceError('Empty response') elif packet[4] == 0: return self._handle_ok(packet) elif packet[4] == 251: filename = packet[5:].decode() return self._handle_load_data_infile(filename) elif packet[4] == 254: return self._handle_eof(packet) elif packet[4] == 255: raise errors.get_exception(packet) # We have a text result set column_count = self._protocol.parse_column_count(packet) if not column_count or not isinstance(column_count, int): raise errors.InterfaceError('Illegal result set.') columns = [None,] * column_count for i in range(0, column_count): columns[i] = self._protocol.parse_column((yield from self._socket.recv())) eof = self._handle_eof((yield from self._socket.recv())) self.unread_result = True return {'columns': columns, 'eof': eof}
def _do_handshake(self): """Get the handshake from the MySQL server""" packet = self._socket.recv() if packet[4] == 255: raise errors.get_exception(packet) try: handshake = self._protocol.parse_handshake(packet) except Exception as err: raise errors.InterfaceError("Failed parsing handshake; {}".format(err)) regex_ver = re.compile(b"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)") match = regex_ver.match(handshake["server_version_original"]) if not match: raise errors.InterfaceError("Failed parsing MySQL version") version = tuple([int(v) for v in match.groups()[0:3]]) if version < (4, 1): raise errors.InterfaceError( "MySQL Version '{}' is not supported.".format(handshake["server_version_original"]) ) self._handshake = handshake self._server_version = version