bare-http1 4.3.0 → 4.4.0
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 +1 -1
- package/lib/agent.js +40 -8
- package/lib/client-connection.js +43 -29
- package/lib/client-request.js +42 -17
- package/lib/incoming-message.js +40 -12
- package/lib/outgoing-message.js +29 -13
- package/lib/server-connection.js +56 -37
- package/lib/server-response.js +34 -19
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ export interface HTTPAgent {
|
|
|
118
118
|
class HTTPAgent {
|
|
119
119
|
constructor(opts?: HTTPAgentOptions & TCPSocketOptions & TCPSocketConnectOptions)
|
|
120
120
|
|
|
121
|
-
static global: HTTPAgent
|
|
121
|
+
static readonly global: HTTPAgent
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export const globalAgent: HTTPAgent
|
package/lib/agent.js
CHANGED
|
@@ -5,11 +5,18 @@ const HTTPClientConnection = require('./client-connection')
|
|
|
5
5
|
class HTTPSocketSet {
|
|
6
6
|
constructor() {
|
|
7
7
|
this._sockets = new Map()
|
|
8
|
+
this._size = 0
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get size() {
|
|
12
|
+
return this._size
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
add(name, socket) {
|
|
11
16
|
const sockets = this._sockets.get(name)
|
|
12
17
|
|
|
18
|
+
this._size++
|
|
19
|
+
|
|
13
20
|
if (sockets === undefined) this._sockets.set(name, [socket])
|
|
14
21
|
else sockets.push(socket)
|
|
15
22
|
}
|
|
@@ -18,6 +25,8 @@ class HTTPSocketSet {
|
|
|
18
25
|
const sockets = this._sockets.get(name)
|
|
19
26
|
if (sockets === undefined || sockets.length === 0) return null
|
|
20
27
|
|
|
28
|
+
this._size--
|
|
29
|
+
|
|
21
30
|
const last = sockets.pop()
|
|
22
31
|
|
|
23
32
|
if (sockets.length === 0) this._sockets.delete(name)
|
|
@@ -32,6 +41,8 @@ class HTTPSocketSet {
|
|
|
32
41
|
const i = sockets.indexOf(socket)
|
|
33
42
|
if (i === -1) return
|
|
34
43
|
|
|
44
|
+
this._size--
|
|
45
|
+
|
|
35
46
|
const last = sockets.pop()
|
|
36
47
|
if (last !== socket) sockets[i] = last
|
|
37
48
|
|
|
@@ -51,16 +62,17 @@ class HTTPSocketSet {
|
|
|
51
62
|
}
|
|
52
63
|
}
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
class HTTPAgent extends EventEmitter {
|
|
55
66
|
constructor(opts = {}) {
|
|
56
67
|
super()
|
|
57
68
|
|
|
58
|
-
const { keepAlive = false, keepAliveMsecs = 1000 } = opts
|
|
69
|
+
const { keepAlive = false, keepAliveMsecs = 1000, defaultPort = 80 } = opts
|
|
59
70
|
|
|
60
71
|
this._sockets = new HTTPSocketSet()
|
|
61
72
|
this._freeSockets = new HTTPSocketSet()
|
|
62
73
|
|
|
63
74
|
this._keepAlive = typeof keepAlive === 'number' ? keepAlive : keepAlive ? keepAliveMsecs : -1
|
|
75
|
+
this._defaultPort = defaultPort
|
|
64
76
|
|
|
65
77
|
this._opts = { ...opts }
|
|
66
78
|
}
|
|
@@ -73,6 +85,10 @@ module.exports = class HTTPAgent extends EventEmitter {
|
|
|
73
85
|
return this._freeSockets.sockets()
|
|
74
86
|
}
|
|
75
87
|
|
|
88
|
+
get defaultPort() {
|
|
89
|
+
return this._defaultPort
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
createConnection(opts) {
|
|
77
93
|
return tcp.createConnection(opts)
|
|
78
94
|
}
|
|
@@ -131,27 +147,43 @@ module.exports = class HTTPAgent extends EventEmitter {
|
|
|
131
147
|
|
|
132
148
|
agent._sockets.delete(name, socket)
|
|
133
149
|
agent._freeSockets.delete(name, socket)
|
|
150
|
+
|
|
151
|
+
if (agent._sockets.size === 0) HTTPAgent._agents.delete(agent)
|
|
134
152
|
}
|
|
135
153
|
|
|
136
154
|
function ontimeout() {
|
|
155
|
+
socket.destroy()
|
|
156
|
+
|
|
137
157
|
agent._freeSockets.delete(name, socket)
|
|
138
158
|
}
|
|
139
159
|
}
|
|
140
160
|
|
|
161
|
+
if (this._sockets.size === 0) HTTPAgent._agents.add(this)
|
|
162
|
+
|
|
141
163
|
this._sockets.add(name, socket)
|
|
142
164
|
|
|
143
|
-
req.
|
|
165
|
+
req._socket = socket
|
|
144
166
|
|
|
145
167
|
const connection = HTTPClientConnection.from(socket, opts)
|
|
146
168
|
|
|
147
|
-
connection.
|
|
169
|
+
connection._req = req
|
|
148
170
|
}
|
|
149
171
|
|
|
150
172
|
destroy() {
|
|
151
|
-
for (const
|
|
152
|
-
for (const socket of set) socket.destroy()
|
|
153
|
-
}
|
|
173
|
+
for (const socket of this._sockets.sockets()) socket.destroy()
|
|
154
174
|
}
|
|
155
175
|
|
|
156
|
-
static
|
|
176
|
+
static _agents = new Set()
|
|
177
|
+
|
|
178
|
+
static _onidle() {
|
|
179
|
+
for (const agent of this._agents) {
|
|
180
|
+
for (const socket of agent._sockets.sockets()) socket.destroy()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
157
183
|
}
|
|
184
|
+
|
|
185
|
+
HTTPAgent.global = new HTTPAgent({ keepAlive: 1000, timeout: 5000 })
|
|
186
|
+
|
|
187
|
+
module.exports = HTTPAgent
|
|
188
|
+
|
|
189
|
+
Bare.on('idle', HTTPAgent._onidle.bind(HTTPAgent))
|
package/lib/client-connection.js
CHANGED
|
@@ -22,10 +22,10 @@ module.exports = class HTTPClientConnection {
|
|
|
22
22
|
constructor(socket, opts = {}) {
|
|
23
23
|
const { IncomingMessage = HTTPIncomingMessage } = opts
|
|
24
24
|
|
|
25
|
-
this.
|
|
25
|
+
this._socket = socket
|
|
26
26
|
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
27
|
+
this._req = null
|
|
28
|
+
this._res = null
|
|
29
29
|
|
|
30
30
|
this._IncomingMessage = IncomingMessage
|
|
31
31
|
|
|
@@ -50,20 +50,32 @@ module.exports = class HTTPClientConnection {
|
|
|
50
50
|
HTTPClientConnection._connections.set(socket, this)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
get socket() {
|
|
54
|
+
return this._socket
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get req() {
|
|
58
|
+
return this._req
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get res() {
|
|
62
|
+
return this._res
|
|
63
|
+
}
|
|
64
|
+
|
|
53
65
|
get idle() {
|
|
54
66
|
return this._idle
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
_onerror(err) {
|
|
58
|
-
if (this.
|
|
70
|
+
if (this._req) this._req.destroy(err)
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
_onclose() {
|
|
62
|
-
if (this.
|
|
74
|
+
if (this._req) this._req._continueFinal()
|
|
63
75
|
}
|
|
64
76
|
|
|
65
77
|
_onend() {
|
|
66
|
-
if (this.
|
|
78
|
+
if (this._req) this._req.destroy(errors.CONNECTION_LOST())
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
_ondata(data) {
|
|
@@ -73,68 +85,70 @@ module.exports = class HTTPClientConnection {
|
|
|
73
85
|
for (const op of this._parser.push(data)) {
|
|
74
86
|
switch (op.type) {
|
|
75
87
|
case RESPONSE:
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
88
|
+
this._req.on('close', () => {
|
|
89
|
+
this._req = null
|
|
78
90
|
})
|
|
79
91
|
|
|
80
|
-
this.
|
|
92
|
+
this._res = new this._IncomingMessage(this._socket, op.headers, {
|
|
81
93
|
statusCode: op.code,
|
|
82
94
|
statusMessage: op.reason
|
|
83
95
|
})
|
|
84
96
|
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
87
|
-
|
|
97
|
+
this._res.on('close', () => {
|
|
98
|
+
this._res = null
|
|
88
99
|
this._idle = true
|
|
89
100
|
|
|
90
|
-
this.
|
|
101
|
+
this._socket.emit('free')
|
|
91
102
|
})
|
|
92
103
|
|
|
93
104
|
if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
|
|
94
105
|
return this._onupgrade(this._parser.end())
|
|
95
106
|
}
|
|
96
107
|
|
|
97
|
-
this.
|
|
108
|
+
this._req.emit('response', this._res)
|
|
98
109
|
break
|
|
99
110
|
|
|
100
111
|
case DATA:
|
|
101
|
-
this.
|
|
112
|
+
this._res.push(op.data)
|
|
102
113
|
break
|
|
103
114
|
|
|
104
115
|
case END:
|
|
105
|
-
if (this.
|
|
106
|
-
if (this.
|
|
116
|
+
if (this._res) this._res.push(null)
|
|
117
|
+
if (this._req) this._req._continueFinal()
|
|
107
118
|
break
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
121
|
} catch (err) {
|
|
111
|
-
this.
|
|
122
|
+
this._socket.destroy(err)
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
|
|
115
126
|
_onupgrade(data) {
|
|
116
|
-
this.
|
|
127
|
+
this._detach()
|
|
128
|
+
|
|
129
|
+
const res = this._res
|
|
130
|
+
const req = this._req
|
|
117
131
|
|
|
118
|
-
|
|
132
|
+
res._upgrade = req._upgrade = true
|
|
119
133
|
|
|
120
|
-
req.upgrade
|
|
121
|
-
req.destroy()
|
|
134
|
+
const upgraded = req.emit('upgrade', res, this._socket, data || EMPTY)
|
|
122
135
|
|
|
123
|
-
|
|
136
|
+
res.push(null)
|
|
137
|
+
req._continueFinal()
|
|
124
138
|
|
|
125
|
-
this.
|
|
139
|
+
if (!upgraded) this._socket.destroy()
|
|
126
140
|
}
|
|
127
141
|
|
|
128
142
|
_ontimeout() {
|
|
129
|
-
if (this.
|
|
143
|
+
if (this._req) this._req.emit('timeout')
|
|
130
144
|
}
|
|
131
145
|
|
|
132
146
|
_ondrain() {
|
|
133
|
-
if (this.
|
|
147
|
+
if (this._req) this._req._continueWrite()
|
|
134
148
|
}
|
|
135
149
|
|
|
136
|
-
|
|
137
|
-
this.
|
|
150
|
+
_detach() {
|
|
151
|
+
this._socket
|
|
138
152
|
.off('error', this._onerror)
|
|
139
153
|
.off('close', this._onclose)
|
|
140
154
|
.off('end', this._onend)
|
|
@@ -142,6 +156,6 @@ module.exports = class HTTPClientConnection {
|
|
|
142
156
|
.off('drain', this._ondrain)
|
|
143
157
|
.off('timeout', this._ontimeout)
|
|
144
158
|
|
|
145
|
-
HTTPClientConnection._connections.delete(this.
|
|
159
|
+
HTTPClientConnection._connections.delete(this._socket)
|
|
146
160
|
}
|
|
147
161
|
}
|
package/lib/client-request.js
CHANGED
|
@@ -16,38 +16,48 @@ module.exports = class HTTPClientRequest extends HTTPOutgoingMessage {
|
|
|
16
16
|
const agent = opts.agent === false ? new HTTPAgent() : opts.agent || HTTPAgent.global
|
|
17
17
|
const method = opts.method || 'GET'
|
|
18
18
|
const path = opts.path || '/'
|
|
19
|
+
const defaultPort = opts.defaultPort || (agent && agent.defaultPort) || 80
|
|
19
20
|
const host = (opts.host = opts.host || 'localhost')
|
|
20
|
-
const port = (opts.port = opts.port ||
|
|
21
|
-
const headers = { host: host
|
|
21
|
+
const port = (opts.port = opts.port || defaultPort)
|
|
22
|
+
const headers = { host: hostHeader(host, port, defaultPort), ...opts.headers }
|
|
22
23
|
|
|
23
24
|
super()
|
|
24
25
|
|
|
25
26
|
agent.addRequest(this, opts)
|
|
26
27
|
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.
|
|
28
|
+
this._headers = headers
|
|
29
|
+
this._method = method
|
|
30
|
+
this._path = path
|
|
30
31
|
|
|
31
32
|
this._chunked = method !== 'GET' && method !== 'HEAD'
|
|
32
33
|
|
|
34
|
+
this._pendingWrite = null
|
|
33
35
|
this._pendingFinal = null
|
|
34
36
|
|
|
35
37
|
if (onresponse) this.once('response', onresponse)
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
get method() {
|
|
41
|
+
return this._method
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get path() {
|
|
45
|
+
return this._path
|
|
46
|
+
}
|
|
47
|
+
|
|
38
48
|
// For Node.js compatibility
|
|
39
49
|
abort() {
|
|
40
50
|
return this.destroy()
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
_header() {
|
|
44
|
-
let h = `${this.
|
|
54
|
+
let h = `${this._method} ${this._path} HTTP/1.1\r\n`
|
|
45
55
|
|
|
46
56
|
let upgrade = false
|
|
47
57
|
|
|
48
|
-
for (const name of Object.keys(this.
|
|
58
|
+
for (const name of Object.keys(this._headers)) {
|
|
49
59
|
const n = name.toLowerCase()
|
|
50
|
-
const v = this.
|
|
60
|
+
const v = this._headers[name]
|
|
51
61
|
|
|
52
62
|
if (n === 'content-length') this._chunked = false
|
|
53
63
|
if (n === 'connection' && v && v.toLowerCase() === 'upgrade') upgrade = true
|
|
@@ -65,33 +75,34 @@ module.exports = class HTTPClientRequest extends HTTPOutgoingMessage {
|
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
_write(data, encoding, cb) {
|
|
68
|
-
if (this.
|
|
78
|
+
if (this._headersSent === false) this.flushHeaders()
|
|
69
79
|
|
|
70
80
|
if (this._chunked) {
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
81
|
+
this._socket.write(Buffer.from(data.byteLength.toString(16)))
|
|
82
|
+
this._socket.write(CHUNK_DELIMITER)
|
|
73
83
|
}
|
|
74
84
|
|
|
75
|
-
let flushed = this.
|
|
85
|
+
let flushed = this._socket.write(data)
|
|
76
86
|
|
|
77
|
-
if (this._chunked) flushed = this.
|
|
87
|
+
if (this._chunked) flushed = this._socket.write(CHUNK_DELIMITER)
|
|
78
88
|
|
|
79
89
|
if (flushed) cb(null)
|
|
80
90
|
else this._pendingWrite = cb
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
_final(cb) {
|
|
84
|
-
if (this.
|
|
94
|
+
if (this._headersSent === false) this.flushHeaders()
|
|
85
95
|
|
|
86
|
-
if (this._chunked) this.
|
|
96
|
+
if (this._chunked) this._socket.write(CHUNK_TERMINATOR)
|
|
87
97
|
|
|
88
98
|
this._pendingFinal = cb
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
_predestroy() {
|
|
92
|
-
|
|
102
|
+
super._predestroy()
|
|
93
103
|
|
|
94
|
-
this.
|
|
104
|
+
this._continueWrite()
|
|
105
|
+
this._continueFinal()
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
_continueWrite() {
|
|
@@ -116,3 +127,17 @@ function httpCase(n) {
|
|
|
116
127
|
}
|
|
117
128
|
return s
|
|
118
129
|
}
|
|
130
|
+
|
|
131
|
+
function hostHeader(host, port, defaultPort) {
|
|
132
|
+
const i = host.indexOf(':')
|
|
133
|
+
|
|
134
|
+
if (i !== -1 && host.includes(':', i + 1) && host.charCodeAt(0) !== 91 /* [ */) {
|
|
135
|
+
host = `[${host}]`
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (port && +port !== defaultPort) {
|
|
139
|
+
host += ':' + port
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return host
|
|
143
|
+
}
|
package/lib/incoming-message.js
CHANGED
|
@@ -4,17 +4,45 @@ module.exports = class HTTPIncomingMessage extends Readable {
|
|
|
4
4
|
constructor(socket = null, headers = {}, opts = {}) {
|
|
5
5
|
super()
|
|
6
6
|
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
7
|
+
this._socket = socket
|
|
8
|
+
this._headers = headers
|
|
9
|
+
this._upgrade = false
|
|
10
10
|
|
|
11
11
|
// Server options
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
12
|
+
this._method = opts.method || ''
|
|
13
|
+
this._url = opts.url || ''
|
|
14
14
|
|
|
15
15
|
// Client options
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
16
|
+
this._statusCode = opts.statusCode || 0
|
|
17
|
+
this._statusMessage = opts.statusMessage || ''
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get socket() {
|
|
21
|
+
return this._socket
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get headers() {
|
|
25
|
+
return this._headers
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get upgrade() {
|
|
29
|
+
return this._upgrade
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get method() {
|
|
33
|
+
return this._method
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get url() {
|
|
37
|
+
return this._url
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get statusCode() {
|
|
41
|
+
return this._statusCode
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get statusMessage() {
|
|
45
|
+
return this._statusMessage
|
|
18
46
|
}
|
|
19
47
|
|
|
20
48
|
get httpVersion() {
|
|
@@ -22,26 +50,26 @@ module.exports = class HTTPIncomingMessage extends Readable {
|
|
|
22
50
|
}
|
|
23
51
|
|
|
24
52
|
getHeader(name) {
|
|
25
|
-
return this.
|
|
53
|
+
return this._headers[name.toLowerCase()]
|
|
26
54
|
}
|
|
27
55
|
|
|
28
56
|
getHeaders() {
|
|
29
|
-
return { ...this.
|
|
57
|
+
return { ...this._headers }
|
|
30
58
|
}
|
|
31
59
|
|
|
32
60
|
hasHeader(name) {
|
|
33
|
-
return name.toLowerCase() in this.
|
|
61
|
+
return name.toLowerCase() in this._headers
|
|
34
62
|
}
|
|
35
63
|
|
|
36
64
|
setTimeout(ms, ontimeout) {
|
|
37
65
|
if (ontimeout) this.once('timeout', ontimeout)
|
|
38
66
|
|
|
39
|
-
this.
|
|
67
|
+
this._socket.setTimeout(ms)
|
|
40
68
|
|
|
41
69
|
return this
|
|
42
70
|
}
|
|
43
71
|
|
|
44
72
|
_predestroy() {
|
|
45
|
-
if (this.
|
|
73
|
+
if (this._upgrade === false && this._socket !== null) this._socket.destroy()
|
|
46
74
|
}
|
|
47
75
|
}
|
package/lib/outgoing-message.js
CHANGED
|
@@ -5,39 +5,55 @@ module.exports = class HTTPOutgoingMessage extends Writable {
|
|
|
5
5
|
constructor(socket = null) {
|
|
6
6
|
super()
|
|
7
7
|
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
8
|
+
this._socket = socket
|
|
9
|
+
this._headers = {}
|
|
10
|
+
this._headersSent = false
|
|
11
|
+
this._upgrade = false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get socket() {
|
|
15
|
+
return this._socket
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get headers() {
|
|
19
|
+
return this._headers
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get headersSent() {
|
|
23
|
+
return this._headersSent
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get upgrade() {
|
|
27
|
+
return this._upgrade
|
|
12
28
|
}
|
|
13
29
|
|
|
14
30
|
getHeader(name) {
|
|
15
|
-
return this.
|
|
31
|
+
return this._headers[name.toLowerCase()]
|
|
16
32
|
}
|
|
17
33
|
|
|
18
34
|
getHeaders() {
|
|
19
|
-
return { ...this.
|
|
35
|
+
return { ...this._headers }
|
|
20
36
|
}
|
|
21
37
|
|
|
22
38
|
hasHeader(name) {
|
|
23
|
-
return name.toLowerCase() in this.
|
|
39
|
+
return name.toLowerCase() in this._headers
|
|
24
40
|
}
|
|
25
41
|
|
|
26
42
|
setHeader(name, value) {
|
|
27
|
-
this.
|
|
43
|
+
this._headers[name.toLowerCase()] = value
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
flushHeaders() {
|
|
31
|
-
if (this.
|
|
47
|
+
if (this._headersSent === true || this._socket === null) return
|
|
32
48
|
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
49
|
+
this._socket.write(Buffer.from(this._header()))
|
|
50
|
+
this._headersSent = true
|
|
35
51
|
}
|
|
36
52
|
|
|
37
53
|
setTimeout(ms, ontimeout) {
|
|
38
54
|
if (ontimeout) this.once('timeout', ontimeout)
|
|
39
55
|
|
|
40
|
-
this.
|
|
56
|
+
this._socket.setTimeout(ms)
|
|
41
57
|
|
|
42
58
|
return this
|
|
43
59
|
}
|
|
@@ -47,6 +63,6 @@ module.exports = class HTTPOutgoingMessage extends Writable {
|
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
_predestroy() {
|
|
50
|
-
if (this.
|
|
66
|
+
if (this._upgrade === false && this._socket !== null) this._socket.destroy()
|
|
51
67
|
}
|
|
52
68
|
}
|
package/lib/server-connection.js
CHANGED
|
@@ -19,11 +19,11 @@ module.exports = class HTTPServerConnection {
|
|
|
19
19
|
constructor(server, socket, opts = {}) {
|
|
20
20
|
const { IncomingMessage = HTTPIncomingMessage, ServerResponse = HTTPServerResponse } = opts
|
|
21
21
|
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
22
|
+
this._server = server
|
|
23
|
+
this._socket = socket
|
|
24
24
|
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
25
|
+
this._req = null
|
|
26
|
+
this._res = null
|
|
27
27
|
|
|
28
28
|
this._IncomingMessage = IncomingMessage
|
|
29
29
|
this._ServerResponse = ServerResponse
|
|
@@ -45,7 +45,23 @@ module.exports = class HTTPServerConnection {
|
|
|
45
45
|
|
|
46
46
|
HTTPServerConnection._connections.set(socket, this)
|
|
47
47
|
|
|
48
|
-
if (this.
|
|
48
|
+
if (this._server.timeout) socket.setTimeout(this._server.timeout)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get server() {
|
|
52
|
+
return this._server
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get socket() {
|
|
56
|
+
return this._socket
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get req() {
|
|
60
|
+
return this._req
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get res() {
|
|
64
|
+
return this._res
|
|
49
65
|
}
|
|
50
66
|
|
|
51
67
|
get idle() {
|
|
@@ -53,10 +69,10 @@ module.exports = class HTTPServerConnection {
|
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
_onclose() {
|
|
56
|
-
if (this.
|
|
57
|
-
if (this.
|
|
58
|
-
const err = getStreamError(this.
|
|
59
|
-
if (err) this.
|
|
72
|
+
if (this._req && !isEnded(this._req)) this._req.destroy()
|
|
73
|
+
if (this._res && !isFinished(this._res)) this._res.destroy()
|
|
74
|
+
const err = getStreamError(this._socket)
|
|
75
|
+
if (err) this._socket.destroy(err)
|
|
60
76
|
}
|
|
61
77
|
|
|
62
78
|
_ondata(data) {
|
|
@@ -66,86 +82,89 @@ module.exports = class HTTPServerConnection {
|
|
|
66
82
|
for (const op of this._parser.push(data)) {
|
|
67
83
|
switch (op.type) {
|
|
68
84
|
case REQUEST:
|
|
69
|
-
this.
|
|
85
|
+
this._req = new this._IncomingMessage(this._socket, op.headers, {
|
|
70
86
|
method: op.method,
|
|
71
87
|
url: op.url
|
|
72
88
|
})
|
|
73
89
|
|
|
74
|
-
this.
|
|
75
|
-
this.
|
|
90
|
+
this._req.on('close', () => {
|
|
91
|
+
this._req = null
|
|
76
92
|
|
|
77
93
|
this._idle = true
|
|
78
94
|
|
|
79
|
-
if (this.
|
|
95
|
+
if (this._server.closing) this._socket.destroy()
|
|
80
96
|
})
|
|
81
97
|
|
|
82
98
|
// Eagerly open the request stream
|
|
83
|
-
this.
|
|
84
|
-
this.
|
|
99
|
+
this._req.resume()
|
|
100
|
+
this._req.pause()
|
|
85
101
|
|
|
86
102
|
if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
|
|
87
103
|
return this._onupgrade(this._parser.end())
|
|
88
104
|
}
|
|
89
105
|
|
|
90
|
-
this.
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
106
|
+
this._res = new this._ServerResponse(
|
|
107
|
+
this._socket,
|
|
108
|
+
this._req,
|
|
93
109
|
op.headers.connection === 'close'
|
|
94
110
|
)
|
|
95
111
|
|
|
96
|
-
this.
|
|
97
|
-
this.
|
|
112
|
+
this._res.on('close', () => {
|
|
113
|
+
this._res = null
|
|
98
114
|
})
|
|
99
115
|
|
|
100
|
-
this.
|
|
116
|
+
this._server.emit('request', this._req, this._res)
|
|
101
117
|
break
|
|
102
118
|
|
|
103
119
|
case DATA:
|
|
104
|
-
this.
|
|
120
|
+
this._req.push(op.data)
|
|
105
121
|
break
|
|
106
122
|
|
|
107
123
|
case END:
|
|
108
|
-
if (this.
|
|
124
|
+
if (this._req) this._req.push(null)
|
|
109
125
|
break
|
|
110
126
|
}
|
|
111
127
|
}
|
|
112
128
|
} catch (err) {
|
|
113
|
-
this.
|
|
129
|
+
this._socket.destroy(err)
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
|
|
117
133
|
_onupgrade(data) {
|
|
118
|
-
this.
|
|
134
|
+
this._detach()
|
|
135
|
+
|
|
136
|
+
const req = this._req
|
|
137
|
+
|
|
138
|
+
req._upgrade = true
|
|
119
139
|
|
|
120
|
-
const
|
|
140
|
+
const upgraded = this._server.emit('upgrade', req, this._socket, data || EMPTY)
|
|
121
141
|
|
|
122
|
-
req.
|
|
123
|
-
req.destroy()
|
|
142
|
+
req.push(null)
|
|
124
143
|
|
|
125
|
-
this.
|
|
144
|
+
if (!upgraded) this._socket.destroy()
|
|
126
145
|
}
|
|
127
146
|
|
|
128
147
|
_ontimeout() {
|
|
129
|
-
const reqTimeout = this.
|
|
130
|
-
const resTimeout = this.
|
|
131
|
-
const serverTimeout = this.
|
|
148
|
+
const reqTimeout = this._req && this._req.emit('timeout')
|
|
149
|
+
const resTimeout = this._res && this._res.emit('timeout')
|
|
150
|
+
const serverTimeout = this._server.emit('timeout', this._socket)
|
|
132
151
|
|
|
133
|
-
if (!reqTimeout && !resTimeout && !serverTimeout) this.
|
|
152
|
+
if (!reqTimeout && !resTimeout && !serverTimeout) this._socket.destroy()
|
|
134
153
|
}
|
|
135
154
|
|
|
136
155
|
_ondrain() {
|
|
137
|
-
if (this.
|
|
156
|
+
if (this._res) this._res._continueWrite()
|
|
138
157
|
}
|
|
139
158
|
|
|
140
|
-
|
|
141
|
-
this.
|
|
159
|
+
_detach() {
|
|
160
|
+
this._socket
|
|
142
161
|
.off('error', noop)
|
|
143
162
|
.off('close', this._onclose)
|
|
144
163
|
.off('data', this._ondata)
|
|
145
164
|
.off('drain', this._ondrain)
|
|
146
165
|
.off('timeout', this._ontimeout)
|
|
147
166
|
|
|
148
|
-
HTTPServerConnection._connections.delete(this.
|
|
167
|
+
HTTPServerConnection._connections.delete(this._socket)
|
|
149
168
|
}
|
|
150
169
|
}
|
|
151
170
|
|
package/lib/server-response.js
CHANGED
|
@@ -8,10 +8,10 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
8
8
|
constructor(socket, req, close) {
|
|
9
9
|
super(socket)
|
|
10
10
|
|
|
11
|
-
this.
|
|
11
|
+
this._req = req
|
|
12
12
|
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
13
|
+
this._statusCode = 200
|
|
14
|
+
this._statusMessage = null
|
|
15
15
|
|
|
16
16
|
this._chunked = true
|
|
17
17
|
this._close = close
|
|
@@ -21,8 +21,21 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
21
21
|
this._pendingWrite = null
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
get req() {
|
|
25
|
+
return this._req
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get statusCode() {
|
|
29
|
+
return this._statusCode
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get statusMessage() {
|
|
33
|
+
return this._statusMessage
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
end(data) {
|
|
25
37
|
this._finishing = true
|
|
38
|
+
|
|
26
39
|
return super.end(data)
|
|
27
40
|
}
|
|
28
41
|
|
|
@@ -32,22 +45,23 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
32
45
|
statusMessage = null
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
37
|
-
|
|
48
|
+
this._statusCode = statusCode
|
|
49
|
+
this._statusMessage = statusMessage || null
|
|
50
|
+
|
|
51
|
+
if (headers) this._headers = { ...this._headers, ...headers }
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
_header() {
|
|
41
55
|
let h =
|
|
42
56
|
'HTTP/1.1 ' +
|
|
43
|
-
this.
|
|
57
|
+
this._statusCode +
|
|
44
58
|
' ' +
|
|
45
|
-
(this.
|
|
59
|
+
(this._statusMessage === null ? constants.status[this._statusCode] : this._statusMessage) +
|
|
46
60
|
'\r\n'
|
|
47
61
|
|
|
48
|
-
for (const name of Object.keys(this.
|
|
62
|
+
for (const name of Object.keys(this._headers)) {
|
|
49
63
|
const n = name.toLowerCase()
|
|
50
|
-
const v = this.
|
|
64
|
+
const v = this._headers[name]
|
|
51
65
|
|
|
52
66
|
if (n === 'content-length') this._chunked = false
|
|
53
67
|
if (n === 'connection' && v && v.toLowerCase() === 'close') this._close = true
|
|
@@ -63,7 +77,7 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
_write(data, encoding, cb) {
|
|
66
|
-
if (this.
|
|
80
|
+
if (this._headersSent === false) {
|
|
67
81
|
if (this._finishing) {
|
|
68
82
|
this.setHeader(
|
|
69
83
|
'Content-Length',
|
|
@@ -77,36 +91,37 @@ module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
|
|
|
77
91
|
if (this._onlyHeaders === true) return cb(null)
|
|
78
92
|
|
|
79
93
|
if (this._chunked) {
|
|
80
|
-
this.
|
|
81
|
-
this.
|
|
94
|
+
this._socket.write(Buffer.from(data.byteLength.toString(16)))
|
|
95
|
+
this._socket.write(CHUNK_DELIMITER)
|
|
82
96
|
}
|
|
83
97
|
|
|
84
|
-
let flushed = this.
|
|
98
|
+
let flushed = this._socket.write(data)
|
|
85
99
|
|
|
86
|
-
if (this._chunked) flushed = this.
|
|
100
|
+
if (this._chunked) flushed = this._socket.write(CHUNK_DELIMITER)
|
|
87
101
|
|
|
88
102
|
if (flushed) cb(null)
|
|
89
103
|
else this._pendingWrite = cb
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
_final(cb) {
|
|
93
|
-
if (this.
|
|
107
|
+
if (this._headersSent === false) {
|
|
94
108
|
this.setHeader('Content-Length', '0')
|
|
95
109
|
this.flushHeaders()
|
|
96
110
|
}
|
|
97
111
|
|
|
98
112
|
if (this._chunked && this._onlyHeaders === false) {
|
|
99
|
-
this.
|
|
113
|
+
this._socket.write(CHUNK_TERMINATOR)
|
|
100
114
|
}
|
|
101
115
|
|
|
102
|
-
if (this._close) this.
|
|
116
|
+
if (this._close) this._socket.end()
|
|
103
117
|
|
|
104
118
|
cb(null)
|
|
105
119
|
}
|
|
106
120
|
|
|
107
121
|
_predestroy() {
|
|
108
122
|
super._predestroy()
|
|
109
|
-
|
|
123
|
+
|
|
124
|
+
this._req.destroy()
|
|
110
125
|
this._continueWrite()
|
|
111
126
|
}
|
|
112
127
|
|