FakeServer.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // An experimental fake MySQL server for tricky integration tests. Expanded
  2. // as needed.
  3. var Net = require('net');
  4. var Packets = require('../lib/protocol/packets');
  5. var PacketWriter = require('../lib/protocol/PacketWriter');
  6. var Parser = require('../lib/protocol/Parser');
  7. var Auth = require('../lib/protocol/Auth');
  8. var EventEmitter = require('events').EventEmitter;
  9. var Util = require('util');
  10. module.exports = FakeServer;
  11. Util.inherits(FakeServer, EventEmitter);
  12. function FakeServer(options) {
  13. EventEmitter.call(this);
  14. this._server = null;
  15. this._connections = [];
  16. }
  17. FakeServer.prototype.listen = function(port, cb) {
  18. this._server = Net.createServer(this._handleConnection.bind(this));
  19. this._server.listen(port, cb);
  20. };
  21. FakeServer.prototype._handleConnection = function(socket) {
  22. var connection = new FakeConnection(socket);
  23. this.emit('connection', connection);
  24. this._connections.push(connection);
  25. };
  26. FakeServer.prototype.destroy = function() {
  27. this._server.close();
  28. this._connections.forEach(function(connection) {
  29. connection.destroy();
  30. });
  31. };
  32. Util.inherits(FakeConnection, EventEmitter);
  33. function FakeConnection(socket) {
  34. EventEmitter.call(this);
  35. this._socket = socket;
  36. this._parser = new Parser({onPacket: this._parsePacket.bind(this)});
  37. this._handshakeInitializationPacket = null;
  38. this._clientAuthenticationPacket = null;
  39. this._oldPasswordPacket = null;
  40. this._handshakeOptions = {};
  41. socket.on('data', this._handleData.bind(this));
  42. }
  43. FakeConnection.prototype.handshake = function(options) {
  44. this._handshakeOptions = options || {};
  45. this._handshakeInitializationPacket = new Packets.HandshakeInitializationPacket({
  46. scrambleBuff1: new Buffer(8),
  47. scrambleBuff2: new Buffer(12),
  48. });
  49. this._sendPacket(this._handshakeInitializationPacket);
  50. };
  51. FakeConnection.prototype.deny = function(message, errno) {
  52. this._sendPacket(new Packets.ErrorPacket({
  53. message: message,
  54. errno: errno,
  55. }));
  56. };
  57. FakeConnection.prototype._sendPacket = function(packet) {
  58. var writer = new PacketWriter();
  59. packet.write(writer);
  60. this._socket.write(writer.toBuffer(this._parser));
  61. };
  62. FakeConnection.prototype._handleData = function(buffer) {
  63. this._parser.write(buffer);
  64. };
  65. FakeConnection.prototype._parsePacket = function(header) {
  66. var Packet = this._determinePacket(header);
  67. var packet = new Packet();
  68. packet.parse(this._parser);
  69. switch (Packet) {
  70. case Packets.ClientAuthenticationPacket:
  71. this._clientAuthenticationPacket = packet;
  72. if (this._handshakeOptions.oldPassword) {
  73. this._sendPacket(new Packets.UseOldPasswordPacket());
  74. } else {
  75. if (this._handshakeOptions.user || this._handshakeOptions.password) {
  76. throw new Error('not implemented');
  77. }
  78. this._sendPacket(new Packets.OkPacket());
  79. this._parser.resetPacketNumber();
  80. }
  81. break;
  82. case Packets.OldPasswordPacket:
  83. this._oldPasswordPacket = packet;
  84. var expected = Auth.scramble323(this._handshakeInitializationPacket.scrambleBuff(), this._handshakeOptions.password);
  85. var got = packet.scrambleBuff;
  86. var toString = function(buffer) {
  87. return Array.prototype.slice.call(buffer).join(',');
  88. };
  89. if (toString(expected) === toString(got)) {
  90. this._sendPacket(new Packets.OkPacket());
  91. } else {
  92. this._sendPacket(new Packets.ErrorPacket());
  93. }
  94. this._parser.resetPacketNumber();
  95. break;
  96. case Packets.ComQueryPacket:
  97. this.emit('query', packet);
  98. break;
  99. default:
  100. throw new Error('Unexpected packet: ' + Packet.name)
  101. }
  102. };
  103. FakeConnection.prototype._determinePacket = function() {
  104. if (!this._clientAuthenticationPacket) {
  105. return Packets.ClientAuthenticationPacket;
  106. } else if (this._handshakeOptions.oldPassword && !this._oldPasswordPacket) {
  107. return Packets.OldPasswordPacket;
  108. }
  109. var firstByte = this._parser.peak();
  110. switch (firstByte) {
  111. case 0x03: return Packets.ComQueryPacket;
  112. default:
  113. throw new Error('Unknown packet, first byte: ' + firstByte);
  114. break;
  115. }
  116. };
  117. FakeConnection.prototype.destroy = function() {
  118. this._socket.destroy();
  119. };