bare-http1 4.1.1 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +10 -35
- package/index.js +4 -2
- package/lib/agent.js +2 -9
- package/lib/client-connection.js +40 -164
- package/lib/client-request.js +2 -4
- package/lib/constants.d.ts +0 -7
- package/lib/constants.js +0 -7
- package/lib/errors.d.ts +1 -1
- package/lib/errors.js +3 -3
- package/lib/server-connection.js +59 -183
- package/lib/server-response.js +2 -5
- package/lib/server.js +1 -4
- package/package.json +3 -2
package/index.d.ts
CHANGED
|
@@ -8,11 +8,7 @@ import {
|
|
|
8
8
|
} from 'bare-tcp'
|
|
9
9
|
import Buffer from 'bare-buffer'
|
|
10
10
|
import URL from 'bare-url'
|
|
11
|
-
import constants, {
|
|
12
|
-
HTTPMethod,
|
|
13
|
-
HTTPStatusCode,
|
|
14
|
-
HTTPStatusMessage
|
|
15
|
-
} from './lib/constants'
|
|
11
|
+
import constants, { HTTPMethod, HTTPStatusCode, HTTPStatusMessage } from './lib/constants'
|
|
16
12
|
import HTTPError from './lib/errors'
|
|
17
13
|
|
|
18
14
|
export {
|
|
@@ -111,18 +107,13 @@ export interface HTTPAgent {
|
|
|
111
107
|
|
|
112
108
|
getName(opts: { host: string; port: number }): string
|
|
113
109
|
|
|
114
|
-
addRequest(
|
|
115
|
-
req: HTTPClientRequest,
|
|
116
|
-
opts: TCPSocketOptions & TCPSocketConnectOptions
|
|
117
|
-
): void
|
|
110
|
+
addRequest(req: HTTPClientRequest, opts: TCPSocketOptions & TCPSocketConnectOptions): void
|
|
118
111
|
|
|
119
112
|
destroy(): void
|
|
120
113
|
}
|
|
121
114
|
|
|
122
115
|
export class HTTPAgent {
|
|
123
|
-
constructor(
|
|
124
|
-
opts?: HTTPAgentOptions & TCPSocketOptions & TCPSocketConnectOptions
|
|
125
|
-
)
|
|
116
|
+
constructor(opts?: HTTPAgentOptions & TCPSocketOptions & TCPSocketConnectOptions)
|
|
126
117
|
|
|
127
118
|
static global: HTTPAgent
|
|
128
119
|
}
|
|
@@ -137,8 +128,7 @@ export interface HTTPServerEvents extends TCPServerEvents {
|
|
|
137
128
|
timeout: [socket: TCPSocket]
|
|
138
129
|
}
|
|
139
130
|
|
|
140
|
-
export interface HTTPServer<M extends HTTPServerEvents = HTTPServerEvents>
|
|
141
|
-
extends TCPServer<M> {
|
|
131
|
+
export interface HTTPServer<M extends HTTPServerEvents = HTTPServerEvents> extends TCPServer<M> {
|
|
142
132
|
readonly timeout: number | undefined
|
|
143
133
|
|
|
144
134
|
setTimeout(ms: number, ontimeout?: () => void): this
|
|
@@ -150,9 +140,7 @@ export class HTTPServer {
|
|
|
150
140
|
onrequest?: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
|
|
151
141
|
)
|
|
152
142
|
|
|
153
|
-
constructor(
|
|
154
|
-
onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
|
|
155
|
-
)
|
|
143
|
+
constructor(onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void)
|
|
156
144
|
}
|
|
157
145
|
|
|
158
146
|
export { HTTPServer as Server }
|
|
@@ -168,10 +156,7 @@ export interface HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
168
156
|
headers?: Record<string, string | number>
|
|
169
157
|
): void
|
|
170
158
|
|
|
171
|
-
writeHead(
|
|
172
|
-
statusCode: HTTPStatusCode,
|
|
173
|
-
headers?: Record<string, string | number>
|
|
174
|
-
): void
|
|
159
|
+
writeHead(statusCode: HTTPStatusCode, headers?: Record<string, string | number>): void
|
|
175
160
|
}
|
|
176
161
|
|
|
177
162
|
export class HTTPServerResponse {
|
|
@@ -191,16 +176,10 @@ export interface HTTPServerConnection {
|
|
|
191
176
|
|
|
192
177
|
readonly req: HTTPIncomingMessage | null
|
|
193
178
|
readonly res: HTTPServerResponse | null
|
|
194
|
-
|
|
195
|
-
readonly idle: boolean
|
|
196
179
|
}
|
|
197
180
|
|
|
198
181
|
export class HTTPServerConnection {
|
|
199
|
-
constructor(
|
|
200
|
-
server: HTTPServer,
|
|
201
|
-
socket: TCPSocket,
|
|
202
|
-
opts?: HTTPServerConnectionOptions
|
|
203
|
-
)
|
|
182
|
+
constructor(server: HTTPServer, socket: TCPSocket, opts?: HTTPServerConnectionOptions)
|
|
204
183
|
|
|
205
184
|
static for(socket: TCPSocket): HTTPServerConnection
|
|
206
185
|
}
|
|
@@ -219,9 +198,8 @@ export interface HTTPClientRequestOptions extends TCPSocketConnectOptions {
|
|
|
219
198
|
path?: string
|
|
220
199
|
}
|
|
221
200
|
|
|
222
|
-
export interface HTTPClientRequest<
|
|
223
|
-
|
|
224
|
-
> extends HTTPOutgoingMessage<M> {
|
|
201
|
+
export interface HTTPClientRequest<M extends HTTPClientRequestEvents = HTTPClientRequestEvents>
|
|
202
|
+
extends HTTPOutgoingMessage<M> {
|
|
225
203
|
readonly method: HTTPMethod
|
|
226
204
|
readonly path: string
|
|
227
205
|
readonly headers: Record<string, string | number>
|
|
@@ -253,10 +231,7 @@ export class HTTPClientConnection {
|
|
|
253
231
|
|
|
254
232
|
static for(socket: TCPSocket): HTTPClientConnection | null
|
|
255
233
|
|
|
256
|
-
static from(
|
|
257
|
-
socket: TCPSocket,
|
|
258
|
-
opts?: HTTPClientConnectionOptions
|
|
259
|
-
): HTTPClientConnection
|
|
234
|
+
static from(socket: TCPSocket, opts?: HTTPClientConnectionOptions): HTTPClientConnection
|
|
260
235
|
}
|
|
261
236
|
|
|
262
237
|
export { HTTPClientConnection as ClientConnection }
|
package/index.js
CHANGED
|
@@ -40,10 +40,12 @@ exports.request = function request(url, opts, onresponse) {
|
|
|
40
40
|
|
|
41
41
|
// For Node.js compatibility
|
|
42
42
|
opts.host = opts.hostname || opts.host
|
|
43
|
-
opts.port =
|
|
44
|
-
typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
|
|
43
|
+
opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
|
|
45
44
|
}
|
|
46
45
|
|
|
46
|
+
// TODO: Renable the default global agent when hangs have been sorted
|
|
47
|
+
opts.agent = opts.agent || new exports.Agent()
|
|
48
|
+
|
|
47
49
|
return new exports.ClientRequest(opts, onresponse)
|
|
48
50
|
}
|
|
49
51
|
|
package/lib/agent.js
CHANGED
|
@@ -12,12 +12,7 @@ module.exports = class HTTPAgent extends EventEmitter {
|
|
|
12
12
|
this._sockets = new Map()
|
|
13
13
|
this._freeSockets = new Map()
|
|
14
14
|
|
|
15
|
-
this._keepAlive =
|
|
16
|
-
typeof keepAlive === 'number'
|
|
17
|
-
? keepAlive
|
|
18
|
-
: keepAlive
|
|
19
|
-
? keepAliveMsecs
|
|
20
|
-
: -1
|
|
15
|
+
this._keepAlive = typeof keepAlive === 'number' ? keepAlive : keepAlive ? keepAliveMsecs : -1
|
|
21
16
|
|
|
22
17
|
this._opts = { ...opts }
|
|
23
18
|
}
|
|
@@ -108,9 +103,7 @@ module.exports = class HTTPAgent extends EventEmitter {
|
|
|
108
103
|
}
|
|
109
104
|
|
|
110
105
|
_onremove(socket, name, all = true) {
|
|
111
|
-
for (const set of all
|
|
112
|
-
? [this._sockets, this._freeSockets]
|
|
113
|
-
: [this._sockets]) {
|
|
106
|
+
for (const set of all ? [this._sockets, this._freeSockets] : [this._sockets]) {
|
|
114
107
|
const sockets = set.get(name)
|
|
115
108
|
if (sockets === undefined) continue
|
|
116
109
|
|
package/lib/client-connection.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
const HTTPParser = require('bare-http-parser')
|
|
1
2
|
const HTTPIncomingMessage = require('./incoming-message')
|
|
2
|
-
const constants = require('./constants')
|
|
3
3
|
const errors = require('./errors')
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const {
|
|
6
|
+
constants: { RESPONSE, DATA, END }
|
|
7
|
+
} = HTTPParser
|
|
8
|
+
|
|
9
|
+
const EMPTY = Buffer.alloc(0)
|
|
6
10
|
|
|
7
11
|
module.exports = class HTTPClientConnection {
|
|
8
12
|
static _connections = new WeakMap()
|
|
@@ -25,10 +29,7 @@ module.exports = class HTTPClientConnection {
|
|
|
25
29
|
|
|
26
30
|
this._IncomingMessage = IncomingMessage
|
|
27
31
|
|
|
28
|
-
this.
|
|
29
|
-
this._length = -1
|
|
30
|
-
this._read = 0
|
|
31
|
-
this._buffer = null
|
|
32
|
+
this._parser = new HTTPParser()
|
|
32
33
|
this._idle = true
|
|
33
34
|
|
|
34
35
|
this._onerror = this._onerror.bind(this)
|
|
@@ -68,154 +69,50 @@ module.exports = class HTTPClientConnection {
|
|
|
68
69
|
_ondata(data) {
|
|
69
70
|
this._idle = false
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let hits = 0
|
|
80
|
-
|
|
81
|
-
for (let i = 0; i < this._buffer.byteLength; i++) {
|
|
82
|
-
const b = this._buffer[i]
|
|
83
|
-
|
|
84
|
-
if (hits === 0 && b === 13) {
|
|
85
|
-
hits++
|
|
86
|
-
} else if (hits === 1 && b === 10) {
|
|
87
|
-
hits++
|
|
88
|
-
|
|
89
|
-
if (this._state === constants.state.BEFORE_CHUNK) {
|
|
90
|
-
const head = this._buffer.subarray(0, i - 1)
|
|
91
|
-
this._buffer =
|
|
92
|
-
i + 1 === this._buffer.byteLength
|
|
93
|
-
? null
|
|
94
|
-
: this._buffer.subarray(i + 1)
|
|
95
|
-
i = 0
|
|
96
|
-
hits = 0
|
|
97
|
-
this._onchunklength(head)
|
|
98
|
-
|
|
99
|
-
if (this._buffer === null) break
|
|
100
|
-
} else if (this._state === constants.state.IN_CHUNK) {
|
|
101
|
-
const chunk = this._buffer.subarray(0, i - 1)
|
|
102
|
-
|
|
103
|
-
if (chunk.byteLength !== this._length) {
|
|
104
|
-
hits = 0
|
|
105
|
-
continue
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this._buffer =
|
|
109
|
-
i + 1 === this._buffer.byteLength
|
|
110
|
-
? null
|
|
111
|
-
: this._buffer.subarray(i + 1)
|
|
112
|
-
i = 0
|
|
113
|
-
hits = 0
|
|
114
|
-
this._onchunk(chunk)
|
|
115
|
-
|
|
116
|
-
if (this._buffer === null) break
|
|
117
|
-
}
|
|
118
|
-
} else if (hits === 2 && b === 13) {
|
|
119
|
-
hits++
|
|
120
|
-
} else if (hits === 3 && b === 10) {
|
|
121
|
-
if (this._state === constants.state.BEFORE_HEAD) {
|
|
122
|
-
const head = this._buffer.subarray(0, i - 3)
|
|
123
|
-
this._buffer =
|
|
124
|
-
i + 1 === this._buffer.byteLength
|
|
125
|
-
? null
|
|
126
|
-
: this._buffer.subarray(i + 1)
|
|
127
|
-
i = 0
|
|
128
|
-
hits = 0
|
|
129
|
-
this._onhead(head)
|
|
130
|
-
|
|
131
|
-
if (this._buffer === null) break
|
|
132
|
-
}
|
|
133
|
-
} else {
|
|
134
|
-
hits = 0
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
72
|
+
try {
|
|
73
|
+
for (const op of this._parser.push(data)) {
|
|
74
|
+
switch (op.type) {
|
|
75
|
+
case RESPONSE:
|
|
76
|
+
this.req.on('close', () => {
|
|
77
|
+
this.req = null
|
|
78
|
+
})
|
|
138
79
|
|
|
139
|
-
|
|
140
|
-
|
|
80
|
+
this.res = new this._IncomingMessage(this.socket, op.headers, {
|
|
81
|
+
statusCode: op.code,
|
|
82
|
+
statusMessage: op.reason
|
|
83
|
+
})
|
|
141
84
|
|
|
142
|
-
|
|
143
|
-
|
|
85
|
+
this.res.on('close', () => {
|
|
86
|
+
this.res = null
|
|
144
87
|
|
|
145
|
-
|
|
146
|
-
if (!statusCode || !statusMessage.length) return this.socket.destroy()
|
|
88
|
+
this._idle = true
|
|
147
89
|
|
|
148
|
-
|
|
90
|
+
this.socket.emit('free')
|
|
91
|
+
})
|
|
149
92
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
headers[name.toLowerCase()] = value
|
|
154
|
-
}
|
|
93
|
+
if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
|
|
94
|
+
return this._onupgrade(this._parser.end())
|
|
95
|
+
}
|
|
155
96
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
})
|
|
97
|
+
this.req.emit('response', this.res)
|
|
98
|
+
break
|
|
159
99
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
})
|
|
100
|
+
case DATA:
|
|
101
|
+
this.res.push(op.data)
|
|
102
|
+
break
|
|
164
103
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (headers.connection && headers.connection.toLowerCase() === 'upgrade') {
|
|
171
|
-
const head = this._buffer
|
|
172
|
-
this._buffer = null
|
|
173
|
-
return this._onupgrade(head)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
this.req.emit('response', this.res)
|
|
177
|
-
|
|
178
|
-
if (headers['transfer-encoding'] === 'chunked') {
|
|
179
|
-
this._state = constants.state.BEFORE_CHUNK
|
|
180
|
-
} else {
|
|
181
|
-
this._length = parseInt(headers['content-length'], 10) || 0
|
|
182
|
-
|
|
183
|
-
if (this._length === 0) return this._onfinished()
|
|
184
|
-
|
|
185
|
-
this._state = constants.state.IN_BODY
|
|
186
|
-
|
|
187
|
-
if (this._buffer) {
|
|
188
|
-
const body = this._buffer
|
|
189
|
-
this._buffer = null
|
|
190
|
-
this._onbody(body)
|
|
104
|
+
case END:
|
|
105
|
+
if (this.res) this.res.push(null)
|
|
106
|
+
if (this.req) this.req._continueFinal()
|
|
107
|
+
break
|
|
108
|
+
}
|
|
191
109
|
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
this.socket.destroy(err)
|
|
192
112
|
}
|
|
193
113
|
}
|
|
194
114
|
|
|
195
|
-
|
|
196
|
-
this._length = parseInt(data.toString(), 16)
|
|
197
|
-
|
|
198
|
-
if (this._length === 0) this._onfinished()
|
|
199
|
-
else this._state = constants.state.IN_CHUNK
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
_onchunk(data) {
|
|
203
|
-
this._read += data.byteLength
|
|
204
|
-
|
|
205
|
-
this.res.push(data)
|
|
206
|
-
|
|
207
|
-
this._state = constants.state.BEFORE_CHUNK
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
_onbody(data) {
|
|
211
|
-
this._read += data.byteLength
|
|
212
|
-
|
|
213
|
-
this.res.push(data)
|
|
214
|
-
|
|
215
|
-
if (this._read === this._length) this._onfinished()
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
_onupgrade(head) {
|
|
115
|
+
_onupgrade(data) {
|
|
219
116
|
this._ondetach()
|
|
220
117
|
|
|
221
118
|
const req = this.req
|
|
@@ -223,7 +120,7 @@ module.exports = class HTTPClientConnection {
|
|
|
223
120
|
req.upgrade = true
|
|
224
121
|
req.destroy()
|
|
225
122
|
|
|
226
|
-
if (req.emit('upgrade', this.res, this.socket,
|
|
123
|
+
if (req.emit('upgrade', this.res, this.socket, data || EMPTY)) return
|
|
227
124
|
|
|
228
125
|
this.socket.destroy()
|
|
229
126
|
}
|
|
@@ -232,21 +129,6 @@ module.exports = class HTTPClientConnection {
|
|
|
232
129
|
if (this.req) this.req.emit('timeout')
|
|
233
130
|
}
|
|
234
131
|
|
|
235
|
-
_onfinished() {
|
|
236
|
-
if (this.res) this.res.push(null)
|
|
237
|
-
if (this.req) this.req._continueFinal()
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
_onreset() {
|
|
241
|
-
this._state = constants.state.BEFORE_HEAD
|
|
242
|
-
this._length = -1
|
|
243
|
-
this._read = 0
|
|
244
|
-
this._buffer = null
|
|
245
|
-
this._idle = true
|
|
246
|
-
|
|
247
|
-
this.socket.emit('free')
|
|
248
|
-
}
|
|
249
|
-
|
|
250
132
|
_ondrain() {
|
|
251
133
|
if (this.req) this.req._continueWrite()
|
|
252
134
|
}
|
|
@@ -263,9 +145,3 @@ module.exports = class HTTPClientConnection {
|
|
|
263
145
|
HTTPClientConnection._connections.delete(this.socket)
|
|
264
146
|
}
|
|
265
147
|
}
|
|
266
|
-
|
|
267
|
-
function splitHeader(s) {
|
|
268
|
-
const i = s.indexOf(': ')
|
|
269
|
-
if (i === -1) return [null, null]
|
|
270
|
-
return [s.slice(0, i), s.slice(i + 2)]
|
|
271
|
-
}
|
package/lib/client-request.js
CHANGED
|
@@ -13,8 +13,7 @@ module.exports = class HTTPClientRequest extends HTTPOutgoingMessage {
|
|
|
13
13
|
|
|
14
14
|
opts = opts ? { ...opts } : {}
|
|
15
15
|
|
|
16
|
-
const agent =
|
|
17
|
-
opts.agent === false ? new HTTPAgent() : opts.agent || HTTPAgent.global
|
|
16
|
+
const agent = opts.agent === false ? new HTTPAgent() : opts.agent || HTTPAgent.global
|
|
18
17
|
const method = opts.method || 'GET'
|
|
19
18
|
const path = opts.path || '/'
|
|
20
19
|
const host = (opts.host = opts.host || 'localhost')
|
|
@@ -50,8 +49,7 @@ module.exports = class HTTPClientRequest extends HTTPOutgoingMessage {
|
|
|
50
49
|
const v = this.headers[name]
|
|
51
50
|
|
|
52
51
|
if (n === 'content-length') this._chunked = false
|
|
53
|
-
if (n === 'connection' && v && v.toLowerCase() === 'upgrade')
|
|
54
|
-
upgrade = true
|
|
52
|
+
if (n === 'connection' && v && v.toLowerCase() === 'upgrade') upgrade = true
|
|
55
53
|
|
|
56
54
|
h += `${httpCase(n)}: ${v}\r\n`
|
|
57
55
|
}
|
package/lib/constants.d.ts
CHANGED
package/lib/constants.js
CHANGED
package/lib/errors.d.ts
CHANGED
package/lib/errors.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = class HTTPError extends Error {
|
|
2
|
-
constructor(msg,
|
|
2
|
+
constructor(msg, fn = HTTPError, code = fn.name) {
|
|
3
3
|
super(`${code}: ${msg}`)
|
|
4
4
|
this.code = code
|
|
5
5
|
|
|
@@ -13,10 +13,10 @@ module.exports = class HTTPError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
static NOT_IMPLEMENTED(msg = 'Method not implemented') {
|
|
16
|
-
return new HTTPError(msg,
|
|
16
|
+
return new HTTPError(msg, HTTPError.NOT_IMPLEMENTED)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
static CONNECTION_LOST(msg = 'Socket hung up') {
|
|
20
|
-
return new HTTPError(msg,
|
|
20
|
+
return new HTTPError(msg, HTTPError.CONNECTION_LOST)
|
|
21
21
|
}
|
|
22
22
|
}
|
package/lib/server-connection.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
const tcp = require('bare-tcp')
|
|
2
2
|
const { isEnded, isFinished, getStreamError } = require('bare-stream')
|
|
3
|
+
const HTTPParser = require('bare-http-parser')
|
|
3
4
|
const HTTPIncomingMessage = require('./incoming-message')
|
|
4
5
|
const HTTPServerResponse = require('./server-response')
|
|
5
|
-
const constants = require('./constants')
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const {
|
|
8
|
+
constants: { REQUEST, DATA, END }
|
|
9
|
+
} = HTTPParser
|
|
10
|
+
|
|
11
|
+
const EMPTY = Buffer.alloc(0)
|
|
8
12
|
|
|
9
13
|
module.exports = class HTTPServerConnection {
|
|
10
14
|
static _connections = new WeakMap()
|
|
@@ -14,10 +18,7 @@ module.exports = class HTTPServerConnection {
|
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
constructor(server, socket, opts = {}) {
|
|
17
|
-
const {
|
|
18
|
-
IncomingMessage = HTTPIncomingMessage,
|
|
19
|
-
ServerResponse = HTTPServerResponse
|
|
20
|
-
} = opts
|
|
21
|
+
const { IncomingMessage = HTTPIncomingMessage, ServerResponse = HTTPServerResponse } = opts
|
|
21
22
|
|
|
22
23
|
this.server = server
|
|
23
24
|
this.socket = socket
|
|
@@ -28,10 +29,7 @@ module.exports = class HTTPServerConnection {
|
|
|
28
29
|
this._IncomingMessage = IncomingMessage
|
|
29
30
|
this._ServerResponse = ServerResponse
|
|
30
31
|
|
|
31
|
-
this.
|
|
32
|
-
this._length = -1
|
|
33
|
-
this._read = 0
|
|
34
|
-
this._buffer = null
|
|
32
|
+
this._parser = new HTTPParser()
|
|
35
33
|
this._idle = true
|
|
36
34
|
|
|
37
35
|
this._onclose = this._onclose.bind(this)
|
|
@@ -65,161 +63,61 @@ module.exports = class HTTPServerConnection {
|
|
|
65
63
|
_ondata(data) {
|
|
66
64
|
this._idle = false
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} else if (hits === 2 && b === 13) {
|
|
116
|
-
hits++
|
|
117
|
-
} else if (hits === 3 && b === 10) {
|
|
118
|
-
if (this._state === constants.state.BEFORE_HEAD) {
|
|
119
|
-
const head = this._buffer.subarray(0, i - 3)
|
|
120
|
-
this._buffer =
|
|
121
|
-
i + 1 === this._buffer.byteLength
|
|
122
|
-
? null
|
|
123
|
-
: this._buffer.subarray(i + 1)
|
|
124
|
-
i = 0
|
|
125
|
-
hits = 0
|
|
126
|
-
this._onhead(head)
|
|
127
|
-
|
|
128
|
-
if (this._buffer === null) break
|
|
66
|
+
try {
|
|
67
|
+
for (const op of this._parser.push(data)) {
|
|
68
|
+
switch (op.type) {
|
|
69
|
+
case REQUEST:
|
|
70
|
+
this.req = new this._IncomingMessage(this.socket, op.headers, {
|
|
71
|
+
method: op.method,
|
|
72
|
+
url: op.url
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
this.req.on('close', () => {
|
|
76
|
+
this.req = null
|
|
77
|
+
|
|
78
|
+
this._idle = true
|
|
79
|
+
|
|
80
|
+
if (this.server._state & tcp.constants.state.CLOSING) {
|
|
81
|
+
this.socket.destroy()
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Eagerly open the request stream
|
|
86
|
+
this.req.resume()
|
|
87
|
+
this.req.pause()
|
|
88
|
+
|
|
89
|
+
if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
|
|
90
|
+
return this._onupgrade(this._parser.end())
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.res = new this._ServerResponse(
|
|
94
|
+
this.socket,
|
|
95
|
+
this.req,
|
|
96
|
+
op.headers.connection === 'close'
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
this.res.on('close', () => {
|
|
100
|
+
this.res = null
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
this.server.emit('request', this.req, this.res)
|
|
104
|
+
break
|
|
105
|
+
|
|
106
|
+
case DATA:
|
|
107
|
+
this.req.push(op.data)
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
case END:
|
|
111
|
+
if (this.req) this.req.push(null)
|
|
112
|
+
break
|
|
129
113
|
}
|
|
130
|
-
} else {
|
|
131
|
-
hits = 0
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
_onhead(data) {
|
|
137
|
-
this._state = constants.state.IN_HEAD
|
|
138
|
-
|
|
139
|
-
const r = data.toString().split('\r\n')
|
|
140
|
-
if (r.length === 0) return this.socket.destroy()
|
|
141
|
-
|
|
142
|
-
const [method, url] = r[0].split(' ')
|
|
143
|
-
if (!method || !url) return this.socket.destroy()
|
|
144
|
-
|
|
145
|
-
const headers = {}
|
|
146
|
-
|
|
147
|
-
for (let i = 1; i < r.length; i++) {
|
|
148
|
-
const [name, value] = splitHeader(r[i])
|
|
149
|
-
if (name === null) return this.socket.destroy()
|
|
150
|
-
headers[name.toLowerCase()] = value
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
this.req = new this._IncomingMessage(this.socket, headers, { method, url })
|
|
154
|
-
|
|
155
|
-
this.req.on('close', () => {
|
|
156
|
-
this.req = null
|
|
157
|
-
this._onreset()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
// Eagerly open the request stream
|
|
161
|
-
this.req.resume()
|
|
162
|
-
this.req.pause()
|
|
163
|
-
|
|
164
|
-
if (headers.connection && headers.connection.toLowerCase() === 'upgrade') {
|
|
165
|
-
const head = this._buffer
|
|
166
|
-
this._buffer = null
|
|
167
|
-
return this._onupgrade(head)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
this.res = new this._ServerResponse(
|
|
171
|
-
this.socket,
|
|
172
|
-
this.req,
|
|
173
|
-
headers.connection === 'close'
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
this.res.on('close', () => {
|
|
177
|
-
this.res = null
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
this.server.emit('request', this.req, this.res)
|
|
181
|
-
|
|
182
|
-
if (headers['transfer-encoding'] === 'chunked') {
|
|
183
|
-
this._state = constants.state.BEFORE_CHUNK
|
|
184
|
-
} else {
|
|
185
|
-
this._length = parseInt(headers['content-length'], 10) || 0
|
|
186
|
-
|
|
187
|
-
if (this._length === 0) return this._onfinished()
|
|
188
|
-
|
|
189
|
-
this._state = constants.state.IN_BODY
|
|
190
|
-
|
|
191
|
-
if (this._buffer) {
|
|
192
|
-
const body = this._buffer
|
|
193
|
-
this._buffer = null
|
|
194
|
-
this._onbody(body)
|
|
195
114
|
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
this.socket.destroy(err)
|
|
196
117
|
}
|
|
197
118
|
}
|
|
198
119
|
|
|
199
|
-
|
|
200
|
-
this._length = parseInt(data.toString(), 16)
|
|
201
|
-
|
|
202
|
-
if (this._length === 0) this._onfinished()
|
|
203
|
-
else this._state = constants.state.IN_CHUNK
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
_onchunk(data) {
|
|
207
|
-
this._read += data.byteLength
|
|
208
|
-
|
|
209
|
-
this.req.push(data)
|
|
210
|
-
|
|
211
|
-
this._state = constants.state.BEFORE_CHUNK
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
_onbody(data) {
|
|
215
|
-
this._read += data.byteLength
|
|
216
|
-
|
|
217
|
-
this.req.push(data)
|
|
218
|
-
|
|
219
|
-
if (this._read === this._length) this._onfinished()
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
_onupgrade(head) {
|
|
120
|
+
_onupgrade(data) {
|
|
223
121
|
this._ondetach()
|
|
224
122
|
|
|
225
123
|
const req = this.req
|
|
@@ -227,7 +125,7 @@ module.exports = class HTTPServerConnection {
|
|
|
227
125
|
req.upgrade = true
|
|
228
126
|
req.destroy()
|
|
229
127
|
|
|
230
|
-
this.server.emit('upgrade', req, this.socket,
|
|
128
|
+
this.server.emit('upgrade', req, this.socket, data || EMPTY)
|
|
231
129
|
}
|
|
232
130
|
|
|
233
131
|
_ontimeout() {
|
|
@@ -238,22 +136,6 @@ module.exports = class HTTPServerConnection {
|
|
|
238
136
|
if (!reqTimeout && !resTimeout && !serverTimeout) this.socket.destroy()
|
|
239
137
|
}
|
|
240
138
|
|
|
241
|
-
_onfinished() {
|
|
242
|
-
if (this.req) this.req.push(null)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
_onreset() {
|
|
246
|
-
this._state = constants.state.BEFORE_HEAD
|
|
247
|
-
this._length = -1
|
|
248
|
-
this._read = 0
|
|
249
|
-
this._buffer = null
|
|
250
|
-
this._idle = true
|
|
251
|
-
|
|
252
|
-
if (this.server._state & tcp.constants.state.CLOSING) {
|
|
253
|
-
this.socket.destroy()
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
139
|
_ondrain() {
|
|
258
140
|
if (this.res) this.res._continueWrite()
|
|
259
141
|
}
|
|
@@ -271,9 +153,3 @@ module.exports = class HTTPServerConnection {
|
|
|
271
153
|
}
|
|
272
154
|
|
|
273
155
|
function noop() {}
|
|
274
|
-
|
|
275
|
-
function splitHeader(s) {
|
|
276
|
-
const i = s.indexOf(': ')
|
|
277
|
-
if (i === -1) return [null, null]
|
|
278
|
-
return [s.slice(0, i), s.slice(i + 2)]
|
|
279
|
-
}
|
package/lib/server-response.js
CHANGED
|
@@ -42,9 +42,7 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
42
42
|
'HTTP/1.1 ' +
|
|
43
43
|
this.statusCode +
|
|
44
44
|
' ' +
|
|
45
|
-
(this.statusMessage === null
|
|
46
|
-
? constants.status[this.statusCode]
|
|
47
|
-
: this.statusMessage) +
|
|
45
|
+
(this.statusMessage === null ? constants.status[this.statusCode] : this.statusMessage) +
|
|
48
46
|
'\r\n'
|
|
49
47
|
|
|
50
48
|
for (const name of Object.keys(this.headers)) {
|
|
@@ -52,8 +50,7 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
52
50
|
const v = this.headers[name]
|
|
53
51
|
|
|
54
52
|
if (n === 'content-length') this._chunked = false
|
|
55
|
-
if (n === 'connection' && v && v.toLowerCase() === 'close')
|
|
56
|
-
this._close = true
|
|
53
|
+
if (n === 'connection' && v && v.toLowerCase() === 'close') this._close = true
|
|
57
54
|
|
|
58
55
|
h += httpCase(n) + ': ' + v + '\r\n'
|
|
59
56
|
}
|
package/lib/server.js
CHANGED
|
@@ -12,10 +12,7 @@ module.exports = class HTTPServer extends TCPServer {
|
|
|
12
12
|
|
|
13
13
|
this._timeout = 0
|
|
14
14
|
|
|
15
|
-
this.on(
|
|
16
|
-
'connection',
|
|
17
|
-
(socket) => new HTTPServerConnection(this, socket, opts)
|
|
18
|
-
)
|
|
15
|
+
this.on('connection', (socket) => new HTTPServerConnection(this, socket, opts))
|
|
19
16
|
|
|
20
17
|
if (onrequest) this.on('request', onrequest)
|
|
21
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-http1",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"description": "Native HTTP/1 library for JavaScript",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./package": "./package.json",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"homepage": "https://github.com/holepunchto/bare-http1#readme",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"bare-events": "^2.6.0",
|
|
40
|
+
"bare-http-parser": "^1.0.0",
|
|
40
41
|
"bare-stream": "^2.3.0",
|
|
41
42
|
"bare-tcp": "^2.0.3"
|
|
42
43
|
},
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"bare-url": "^2.1.3",
|
|
46
47
|
"brittle": "^3.3.0",
|
|
47
48
|
"prettier": "^3.4.1",
|
|
48
|
-
"prettier-config-
|
|
49
|
+
"prettier-config-holepunch": "^2.0.0"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
52
|
"bare-buffer": "*",
|