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.

135 lines
3.2 KiB

4 years ago
  1. 'use strict';
  2. var NodeHTTPParser = require('http-parser-js').HTTPParser,
  3. Buffer = require('safe-buffer').Buffer;
  4. var TYPES = {
  5. request: NodeHTTPParser.REQUEST || 'request',
  6. response: NodeHTTPParser.RESPONSE || 'response'
  7. };
  8. var HttpParser = function(type) {
  9. this._type = type;
  10. this._parser = new NodeHTTPParser(TYPES[type]);
  11. this._complete = false;
  12. this.headers = {};
  13. var current = null,
  14. self = this;
  15. this._parser.onHeaderField = function(b, start, length) {
  16. current = b.toString('utf8', start, start + length).toLowerCase();
  17. };
  18. this._parser.onHeaderValue = function(b, start, length) {
  19. var value = b.toString('utf8', start, start + length);
  20. if (self.headers.hasOwnProperty(current))
  21. self.headers[current] += ', ' + value;
  22. else
  23. self.headers[current] = value;
  24. };
  25. this._parser.onHeadersComplete = this._parser[NodeHTTPParser.kOnHeadersComplete] =
  26. function(majorVersion, minorVersion, headers, method, pathname, statusCode) {
  27. var info = arguments[0];
  28. if (typeof info === 'object') {
  29. method = info.method;
  30. pathname = info.url;
  31. statusCode = info.statusCode;
  32. headers = info.headers;
  33. }
  34. self.method = (typeof method === 'number') ? HttpParser.METHODS[method] : method;
  35. self.statusCode = statusCode;
  36. self.url = pathname;
  37. if (!headers) return;
  38. for (var i = 0, n = headers.length, key, value; i < n; i += 2) {
  39. key = headers[i].toLowerCase();
  40. value = headers[i+1];
  41. if (self.headers.hasOwnProperty(key))
  42. self.headers[key] += ', ' + value;
  43. else
  44. self.headers[key] = value;
  45. }
  46. self._complete = true;
  47. };
  48. };
  49. HttpParser.METHODS = {
  50. 0: 'DELETE',
  51. 1: 'GET',
  52. 2: 'HEAD',
  53. 3: 'POST',
  54. 4: 'PUT',
  55. 5: 'CONNECT',
  56. 6: 'OPTIONS',
  57. 7: 'TRACE',
  58. 8: 'COPY',
  59. 9: 'LOCK',
  60. 10: 'MKCOL',
  61. 11: 'MOVE',
  62. 12: 'PROPFIND',
  63. 13: 'PROPPATCH',
  64. 14: 'SEARCH',
  65. 15: 'UNLOCK',
  66. 16: 'BIND',
  67. 17: 'REBIND',
  68. 18: 'UNBIND',
  69. 19: 'ACL',
  70. 20: 'REPORT',
  71. 21: 'MKACTIVITY',
  72. 22: 'CHECKOUT',
  73. 23: 'MERGE',
  74. 24: 'M-SEARCH',
  75. 25: 'NOTIFY',
  76. 26: 'SUBSCRIBE',
  77. 27: 'UNSUBSCRIBE',
  78. 28: 'PATCH',
  79. 29: 'PURGE',
  80. 30: 'MKCALENDAR',
  81. 31: 'LINK',
  82. 32: 'UNLINK'
  83. };
  84. var VERSION = (process.version || '')
  85. .match(/[0-9]+/g)
  86. .map(function(n) { return parseInt(n, 10) });
  87. if (VERSION[0] === 0 && VERSION[1] === 12) {
  88. HttpParser.METHODS[16] = 'REPORT';
  89. HttpParser.METHODS[17] = 'MKACTIVITY';
  90. HttpParser.METHODS[18] = 'CHECKOUT';
  91. HttpParser.METHODS[19] = 'MERGE';
  92. HttpParser.METHODS[20] = 'M-SEARCH';
  93. HttpParser.METHODS[21] = 'NOTIFY';
  94. HttpParser.METHODS[22] = 'SUBSCRIBE';
  95. HttpParser.METHODS[23] = 'UNSUBSCRIBE';
  96. HttpParser.METHODS[24] = 'PATCH';
  97. HttpParser.METHODS[25] = 'PURGE';
  98. }
  99. HttpParser.prototype.isComplete = function() {
  100. return this._complete;
  101. };
  102. HttpParser.prototype.parse = function(chunk) {
  103. var consumed = this._parser.execute(chunk, 0, chunk.length);
  104. if (typeof consumed !== 'number') {
  105. this.error = consumed;
  106. this._complete = true;
  107. return;
  108. }
  109. if (this._complete)
  110. this.body = (consumed < chunk.length)
  111. ? chunk.slice(consumed)
  112. : Buffer.alloc(0);
  113. };
  114. module.exports = HttpParser;