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