You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.2 KiB
147 lines
4.2 KiB
// An experimental fake MySQL server for tricky integration tests. Expanded
|
|
// as needed.
|
|
|
|
var Net = require('net');
|
|
var Packets = require('../lib/protocol/packets');
|
|
var PacketWriter = require('../lib/protocol/PacketWriter');
|
|
var Parser = require('../lib/protocol/Parser');
|
|
var Auth = require('../lib/protocol/Auth');
|
|
var EventEmitter = require('events').EventEmitter;
|
|
var Util = require('util');
|
|
|
|
module.exports = FakeServer;
|
|
Util.inherits(FakeServer, EventEmitter);
|
|
function FakeServer(options) {
|
|
EventEmitter.call(this);
|
|
|
|
this._server = null;
|
|
this._connections = [];
|
|
}
|
|
|
|
FakeServer.prototype.listen = function(port, cb) {
|
|
this._server = Net.createServer(this._handleConnection.bind(this));
|
|
this._server.listen(port, cb);
|
|
};
|
|
|
|
FakeServer.prototype._handleConnection = function(socket) {
|
|
var connection = new FakeConnection(socket);
|
|
this.emit('connection', connection);
|
|
this._connections.push(connection);
|
|
};
|
|
|
|
FakeServer.prototype.destroy = function() {
|
|
this._server.close();
|
|
this._connections.forEach(function(connection) {
|
|
connection.destroy();
|
|
});
|
|
};
|
|
|
|
Util.inherits(FakeConnection, EventEmitter);
|
|
function FakeConnection(socket) {
|
|
EventEmitter.call(this);
|
|
|
|
this._socket = socket;
|
|
this._parser = new Parser({onPacket: this._parsePacket.bind(this)});
|
|
|
|
this._handshakeInitializationPacket = null;
|
|
this._clientAuthenticationPacket = null;
|
|
this._oldPasswordPacket = null;
|
|
this._handshakeOptions = {};
|
|
|
|
socket.on('data', this._handleData.bind(this));
|
|
}
|
|
|
|
FakeConnection.prototype.handshake = function(options) {
|
|
this._handshakeOptions = options || {};
|
|
|
|
this._handshakeInitializationPacket = new Packets.HandshakeInitializationPacket({
|
|
scrambleBuff1: new Buffer(8),
|
|
scrambleBuff2: new Buffer(12),
|
|
});
|
|
|
|
this._sendPacket(this._handshakeInitializationPacket);
|
|
};
|
|
|
|
FakeConnection.prototype.deny = function(message, errno) {
|
|
this._sendPacket(new Packets.ErrorPacket({
|
|
message: message,
|
|
errno: errno,
|
|
}));
|
|
};
|
|
|
|
FakeConnection.prototype._sendPacket = function(packet) {
|
|
var writer = new PacketWriter();
|
|
packet.write(writer);
|
|
this._socket.write(writer.toBuffer(this._parser));
|
|
};
|
|
|
|
FakeConnection.prototype._handleData = function(buffer) {
|
|
this._parser.write(buffer);
|
|
};
|
|
|
|
FakeConnection.prototype._parsePacket = function(header) {
|
|
var Packet = this._determinePacket(header);
|
|
var packet = new Packet();
|
|
|
|
packet.parse(this._parser);
|
|
|
|
switch (Packet) {
|
|
case Packets.ClientAuthenticationPacket:
|
|
this._clientAuthenticationPacket = packet;
|
|
|
|
if (this._handshakeOptions.oldPassword) {
|
|
this._sendPacket(new Packets.UseOldPasswordPacket());
|
|
} else {
|
|
if (this._handshakeOptions.user || this._handshakeOptions.password) {
|
|
throw new Error('not implemented');
|
|
}
|
|
|
|
this._sendPacket(new Packets.OkPacket());
|
|
this._parser.resetPacketNumber();
|
|
}
|
|
break;
|
|
case Packets.OldPasswordPacket:
|
|
this._oldPasswordPacket = packet;
|
|
|
|
var expected = Auth.scramble323(this._handshakeInitializationPacket.scrambleBuff(), this._handshakeOptions.password);
|
|
var got = packet.scrambleBuff;
|
|
|
|
var toString = function(buffer) {
|
|
return Array.prototype.slice.call(buffer).join(',');
|
|
};
|
|
|
|
if (toString(expected) === toString(got)) {
|
|
this._sendPacket(new Packets.OkPacket());
|
|
} else {
|
|
this._sendPacket(new Packets.ErrorPacket());
|
|
}
|
|
|
|
this._parser.resetPacketNumber();
|
|
break;
|
|
case Packets.ComQueryPacket:
|
|
this.emit('query', packet);
|
|
break;
|
|
default:
|
|
throw new Error('Unexpected packet: ' + Packet.name)
|
|
}
|
|
};
|
|
|
|
FakeConnection.prototype._determinePacket = function() {
|
|
if (!this._clientAuthenticationPacket) {
|
|
return Packets.ClientAuthenticationPacket;
|
|
} else if (this._handshakeOptions.oldPassword && !this._oldPasswordPacket) {
|
|
return Packets.OldPasswordPacket;
|
|
}
|
|
|
|
var firstByte = this._parser.peak();
|
|
switch (firstByte) {
|
|
case 0x03: return Packets.ComQueryPacket;
|
|
default:
|
|
throw new Error('Unknown packet, first byte: ' + firstByte);
|
|
break;
|
|
}
|
|
};
|
|
|
|
FakeConnection.prototype.destroy = function() {
|
|
this._socket.destroy();
|
|
};
|