zlib.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. 'use strict';
  2. const { kMaxLength } = require('buffer');
  3. const {
  4. createInflate,
  5. constants: {
  6. DEFLATE,
  7. INFLATE,
  8. Z_DEFAULT_CHUNK,
  9. Z_DEFAULT_COMPRESSION,
  10. Z_DEFAULT_MEMLEVEL,
  11. Z_DEFAULT_STRATEGY,
  12. Z_DEFAULT_WINDOWBITS,
  13. Z_PARTIAL_FLUSH,
  14. }
  15. } = require('zlib');
  16. const ZlibHandle = createInflate()._handle.constructor;
  17. function processCallback() {
  18. throw new Error('Should not get here');
  19. }
  20. function zlibOnError(message, errno, code) {
  21. const self = this._owner;
  22. // There is no way to cleanly recover.
  23. // Continuing only obscures problems.
  24. const error = new Error(message);
  25. error.errno = errno;
  26. error.code = code;
  27. self._err = error;
  28. }
  29. function _close(engine) {
  30. // Caller may invoke .close after a zlib error (which will null _handle).
  31. if (!engine._handle)
  32. return;
  33. engine._handle.close();
  34. engine._handle = null;
  35. }
  36. class Zlib {
  37. constructor(mode) {
  38. const windowBits = Z_DEFAULT_WINDOWBITS;
  39. const level = Z_DEFAULT_COMPRESSION;
  40. const memLevel = Z_DEFAULT_MEMLEVEL;
  41. const strategy = Z_DEFAULT_STRATEGY;
  42. const dictionary = undefined;
  43. this._err = undefined;
  44. this._writeState = new Uint32Array(2);
  45. this._chunkSize = Z_DEFAULT_CHUNK;
  46. this._maxOutputLength = kMaxLength;
  47. this._outBuffer = Buffer.allocUnsafe(this._chunkSize);
  48. this._outOffset = 0;
  49. this._handle = new ZlibHandle(mode);
  50. this._handle._owner = this;
  51. this._handle.onerror = zlibOnError;
  52. this._handle.init(windowBits,
  53. level,
  54. memLevel,
  55. strategy,
  56. this._writeState,
  57. processCallback,
  58. dictionary);
  59. }
  60. writeSync(chunk, retChunks) {
  61. const handle = this._handle;
  62. if (!handle)
  63. throw new Error('Invalid Zlib instance');
  64. let availInBefore = chunk.length;
  65. let availOutBefore = this._chunkSize - this._outOffset;
  66. let inOff = 0;
  67. let availOutAfter;
  68. let availInAfter;
  69. let buffers;
  70. let nread = 0;
  71. const state = this._writeState;
  72. let buffer = this._outBuffer;
  73. let offset = this._outOffset;
  74. const chunkSize = this._chunkSize;
  75. while (true) {
  76. handle.writeSync(Z_PARTIAL_FLUSH,
  77. chunk, // in
  78. inOff, // in_off
  79. availInBefore, // in_len
  80. buffer, // out
  81. offset, // out_off
  82. availOutBefore); // out_len
  83. if (this._err)
  84. throw this._err;
  85. availOutAfter = state[0];
  86. availInAfter = state[1];
  87. const inDelta = availInBefore - availInAfter;
  88. const have = availOutBefore - availOutAfter;
  89. if (have > 0) {
  90. const out = (offset === 0 && have === buffer.length
  91. ? buffer
  92. : buffer.slice(offset, offset + have));
  93. offset += have;
  94. if (!buffers)
  95. buffers = out;
  96. else if (buffers.push === undefined)
  97. buffers = [buffers, out];
  98. else
  99. buffers.push(out);
  100. nread += out.byteLength;
  101. if (nread > this._maxOutputLength) {
  102. _close(this);
  103. throw new Error(
  104. `Output length exceeded maximum of ${this._maxOutputLength}`
  105. );
  106. }
  107. } else if (have !== 0) {
  108. throw new Error('have should not go down');
  109. }
  110. // Exhausted the output buffer, or used all the input create a new one.
  111. if (availOutAfter === 0 || offset >= chunkSize) {
  112. availOutBefore = chunkSize;
  113. offset = 0;
  114. buffer = Buffer.allocUnsafe(chunkSize);
  115. }
  116. if (availOutAfter === 0) {
  117. // Not actually done. Need to reprocess.
  118. // Also, update the availInBefore to the availInAfter value,
  119. // so that if we have to hit it a third (fourth, etc.) time,
  120. // it'll have the correct byte counts.
  121. inOff += inDelta;
  122. availInBefore = availInAfter;
  123. } else {
  124. break;
  125. }
  126. }
  127. this._outBuffer = buffer;
  128. this._outOffset = offset;
  129. if (nread === 0)
  130. buffers = Buffer.alloc(0);
  131. if (retChunks) {
  132. buffers.totalLen = nread;
  133. return buffers;
  134. }
  135. if (buffers.push === undefined)
  136. return buffers;
  137. const output = Buffer.allocUnsafe(nread);
  138. for (let i = 0, p = 0; i < buffers.length; ++i) {
  139. const buf = buffers[i];
  140. output.set(buf, p);
  141. p += buf.length;
  142. }
  143. return output;
  144. }
  145. }
  146. class ZlibPacketWriter {
  147. constructor(protocol) {
  148. this.allocStart = 0;
  149. this.allocStartKEX = 0;
  150. this._protocol = protocol;
  151. this._zlib = new Zlib(DEFLATE);
  152. }
  153. cleanup() {
  154. if (this._zlib)
  155. _close(this._zlib);
  156. }
  157. alloc(payloadSize, force) {
  158. return Buffer.allocUnsafe(payloadSize);
  159. }
  160. finalize(payload, force) {
  161. if (this._protocol._kexinit === undefined || force) {
  162. const output = this._zlib.writeSync(payload, true);
  163. const packet = this._protocol._cipher.allocPacket(output.totalLen);
  164. if (output.push === undefined) {
  165. packet.set(output, 5);
  166. } else {
  167. for (let i = 0, p = 5; i < output.length; ++i) {
  168. const chunk = output[i];
  169. packet.set(chunk, p);
  170. p += chunk.length;
  171. }
  172. }
  173. return packet;
  174. }
  175. return payload;
  176. }
  177. }
  178. class PacketWriter {
  179. constructor(protocol) {
  180. this.allocStart = 5;
  181. this.allocStartKEX = 5;
  182. this._protocol = protocol;
  183. }
  184. cleanup() {}
  185. alloc(payloadSize, force) {
  186. if (this._protocol._kexinit === undefined || force)
  187. return this._protocol._cipher.allocPacket(payloadSize);
  188. return Buffer.allocUnsafe(payloadSize);
  189. }
  190. finalize(packet, force) {
  191. return packet;
  192. }
  193. }
  194. class ZlibPacketReader {
  195. constructor() {
  196. this._zlib = new Zlib(INFLATE);
  197. }
  198. cleanup() {
  199. if (this._zlib)
  200. _close(this._zlib);
  201. }
  202. read(data) {
  203. return this._zlib.writeSync(data, false);
  204. }
  205. }
  206. class PacketReader {
  207. cleanup() {}
  208. read(data) {
  209. return data;
  210. }
  211. }
  212. module.exports = {
  213. PacketReader,
  214. PacketWriter,
  215. ZlibPacketReader,
  216. ZlibPacketWriter,
  217. };