1 | /* eslint-env mocha */
|
---|
2 |
|
---|
3 | var assert = require('assert')
|
---|
4 | var tls = require('tls')
|
---|
5 | var net = require('net')
|
---|
6 | var https = require('https')
|
---|
7 | var transport = require('spdy-transport')
|
---|
8 | var util = require('util')
|
---|
9 |
|
---|
10 | var fixtures = require('./fixtures')
|
---|
11 | var spdy = require('../')
|
---|
12 |
|
---|
13 | describe('SPDY Server', function () {
|
---|
14 | fixtures.everyConfig(function (protocol, alpn, version, plain) {
|
---|
15 | var server
|
---|
16 | var client
|
---|
17 |
|
---|
18 | beforeEach(function (done) {
|
---|
19 | server = spdy.createServer(Object.assign({
|
---|
20 | spdy: {
|
---|
21 | 'x-forwarded-for': true,
|
---|
22 | plain: plain
|
---|
23 | }
|
---|
24 | }, fixtures.keys))
|
---|
25 |
|
---|
26 | server.listen(fixtures.port, function () {
|
---|
27 | var socket = (plain ? net : tls).connect({
|
---|
28 | rejectUnauthorized: false,
|
---|
29 | port: fixtures.port,
|
---|
30 | ALPNProtocols: [alpn]
|
---|
31 | }, function () {
|
---|
32 | client = transport.connection.create(socket, {
|
---|
33 | protocol: protocol,
|
---|
34 | isServer: false
|
---|
35 | })
|
---|
36 | client.start(version)
|
---|
37 | done()
|
---|
38 | })
|
---|
39 | })
|
---|
40 | })
|
---|
41 |
|
---|
42 | afterEach(function (done) {
|
---|
43 | client.socket.destroy()
|
---|
44 | server.close(done)
|
---|
45 | })
|
---|
46 |
|
---|
47 | it('should process GET request', function (done) {
|
---|
48 | var stream = client.request({
|
---|
49 | method: 'GET',
|
---|
50 | path: '/get',
|
---|
51 | headers: {
|
---|
52 | a: 'b'
|
---|
53 | }
|
---|
54 | }, function (err) {
|
---|
55 | assert(!err)
|
---|
56 |
|
---|
57 | stream.on('error', (err) => {
|
---|
58 | done(err)
|
---|
59 | })
|
---|
60 |
|
---|
61 | stream.on('response', function (status, headers) {
|
---|
62 | assert.strictEqual(status, 200)
|
---|
63 | assert.strictEqual(headers.ok, 'yes')
|
---|
64 |
|
---|
65 | fixtures.expectData(stream, 'response', done)
|
---|
66 | })
|
---|
67 |
|
---|
68 | stream.end()
|
---|
69 | })
|
---|
70 |
|
---|
71 | server.on('request', function (req, res) {
|
---|
72 | assert.strictEqual(req.isSpdy, res.isSpdy)
|
---|
73 | assert.strictEqual(req.spdyVersion, res.spdyVersion)
|
---|
74 | assert(req.isSpdy)
|
---|
75 | if (!plain) {
|
---|
76 | assert(req.socket.encrypted)
|
---|
77 | assert(req.socket.getPeerCertificate())
|
---|
78 | }
|
---|
79 |
|
---|
80 | // Auto-detection
|
---|
81 | if (version === 3.1) {
|
---|
82 | assert(req.spdyVersion >= 3 && req.spdyVersion <= 3.1)
|
---|
83 | } else {
|
---|
84 | assert.strictEqual(req.spdyVersion, version)
|
---|
85 | }
|
---|
86 | assert(req.spdyStream)
|
---|
87 | assert(res.spdyStream)
|
---|
88 |
|
---|
89 | assert.strictEqual(req.method, 'GET')
|
---|
90 | assert.strictEqual(req.url, '/get')
|
---|
91 | assert.deepStrictEqual(req.headers, { a: 'b', host: 'localhost' })
|
---|
92 |
|
---|
93 | req.on('end', function () {
|
---|
94 | res.writeHead(200, {
|
---|
95 | ok: 'yes'
|
---|
96 | })
|
---|
97 | res.end('response')
|
---|
98 | assert(res.finished, 'res.finished should be set')
|
---|
99 | })
|
---|
100 | req.resume()
|
---|
101 | })
|
---|
102 | })
|
---|
103 |
|
---|
104 | it('should process POST request', function (done) {
|
---|
105 | var stream = client.request({
|
---|
106 | method: 'POST',
|
---|
107 | path: '/post'
|
---|
108 | }, function (err) {
|
---|
109 | assert(!err)
|
---|
110 |
|
---|
111 | stream.on('response', function (status, headers) {
|
---|
112 | assert.strictEqual(status, 200)
|
---|
113 | assert.strictEqual(headers.ok, 'yes')
|
---|
114 |
|
---|
115 | fixtures.expectData(stream, 'response', next)
|
---|
116 | })
|
---|
117 |
|
---|
118 | stream.end('request')
|
---|
119 | })
|
---|
120 |
|
---|
121 | server.on('request', function (req, res) {
|
---|
122 | assert.strictEqual(req.method, 'POST')
|
---|
123 | assert.strictEqual(req.url, '/post')
|
---|
124 |
|
---|
125 | res.writeHead(200, {
|
---|
126 | ok: 'yes'
|
---|
127 | })
|
---|
128 | res.end('response')
|
---|
129 |
|
---|
130 | fixtures.expectData(req, 'request', next)
|
---|
131 | })
|
---|
132 |
|
---|
133 | var waiting = 2
|
---|
134 | function next () {
|
---|
135 | if (--waiting === 0) {
|
---|
136 | return done()
|
---|
137 | }
|
---|
138 | }
|
---|
139 | })
|
---|
140 |
|
---|
141 | it('should process expect-continue request', function (done) {
|
---|
142 | var stream = client.request({
|
---|
143 | method: 'GET',
|
---|
144 | path: '/get',
|
---|
145 | headers: {
|
---|
146 | Expect: '100-continue'
|
---|
147 | }
|
---|
148 | }, function (err) {
|
---|
149 | assert(!err)
|
---|
150 |
|
---|
151 | stream.on('response', function (status, headers) {
|
---|
152 | assert.strictEqual(status, 100)
|
---|
153 |
|
---|
154 | fixtures.expectData(stream, 'response', done)
|
---|
155 | })
|
---|
156 |
|
---|
157 | stream.end()
|
---|
158 | })
|
---|
159 |
|
---|
160 | server.on('request', function (req, res) {
|
---|
161 | req.on('end', function () {
|
---|
162 | res.end('response')
|
---|
163 | })
|
---|
164 | req.resume()
|
---|
165 | })
|
---|
166 | })
|
---|
167 |
|
---|
168 | it('should emit `checkContinue` request', function (done) {
|
---|
169 | var stream = client.request({
|
---|
170 | method: 'GET',
|
---|
171 | path: '/get',
|
---|
172 | headers: {
|
---|
173 | Expect: '100-continue'
|
---|
174 | }
|
---|
175 | }, function (err) {
|
---|
176 | assert(!err)
|
---|
177 |
|
---|
178 | stream.on('response', function (status, headers) {
|
---|
179 | assert.strictEqual(status, 100)
|
---|
180 |
|
---|
181 | fixtures.expectData(stream, 'response', done)
|
---|
182 | })
|
---|
183 |
|
---|
184 | stream.end()
|
---|
185 | })
|
---|
186 |
|
---|
187 | server.on('checkContinue', function (req, res) {
|
---|
188 | req.on('end', function () {
|
---|
189 | res.writeContinue()
|
---|
190 | res.end('response')
|
---|
191 | })
|
---|
192 | req.resume()
|
---|
193 | })
|
---|
194 | })
|
---|
195 |
|
---|
196 | it('should send PUSH_PROMISE', function (done) {
|
---|
197 | var stream = client.request({
|
---|
198 | method: 'POST',
|
---|
199 | path: '/page'
|
---|
200 | }, function (err) {
|
---|
201 | assert(!err)
|
---|
202 |
|
---|
203 | stream.on('pushPromise', function (push) {
|
---|
204 | assert.strictEqual(push.path, '/push')
|
---|
205 | assert.strictEqual(push.headers.yes, 'push')
|
---|
206 |
|
---|
207 | fixtures.expectData(push, 'push', next)
|
---|
208 | fixtures.expectData(stream, 'response', next)
|
---|
209 | })
|
---|
210 |
|
---|
211 | stream.end('request')
|
---|
212 | })
|
---|
213 |
|
---|
214 | server.on('request', function (req, res) {
|
---|
215 | assert.strictEqual(req.method, 'POST')
|
---|
216 | assert.strictEqual(req.url, '/page')
|
---|
217 |
|
---|
218 | res.writeHead(200, {
|
---|
219 | ok: 'yes'
|
---|
220 | })
|
---|
221 |
|
---|
222 | var push = res.push('/push', {
|
---|
223 | request: {
|
---|
224 | yes: 'push'
|
---|
225 | }
|
---|
226 | })
|
---|
227 | push.end('push')
|
---|
228 |
|
---|
229 | res.end('response')
|
---|
230 |
|
---|
231 | fixtures.expectData(req, 'request', next)
|
---|
232 | })
|
---|
233 |
|
---|
234 | var waiting = 3
|
---|
235 | function next () {
|
---|
236 | if (--waiting === 0) {
|
---|
237 | return done()
|
---|
238 | }
|
---|
239 | }
|
---|
240 | })
|
---|
241 |
|
---|
242 | it('should receive trailing headers', function (done) {
|
---|
243 | var stream = client.request({
|
---|
244 | method: 'POST',
|
---|
245 | path: '/post'
|
---|
246 | }, function (err) {
|
---|
247 | assert(!err)
|
---|
248 |
|
---|
249 | stream.sendHeaders({ trai: 'ler' })
|
---|
250 | stream.end()
|
---|
251 |
|
---|
252 | stream.on('response', function (status, headers) {
|
---|
253 | assert.strictEqual(status, 200)
|
---|
254 | assert.strictEqual(headers.ok, 'yes')
|
---|
255 |
|
---|
256 | fixtures.expectData(stream, 'response', done)
|
---|
257 | })
|
---|
258 | })
|
---|
259 |
|
---|
260 | server.on('request', function (req, res) {
|
---|
261 | var gotHeaders = false
|
---|
262 | req.on('trailers', function (headers) {
|
---|
263 | gotHeaders = true
|
---|
264 | assert.strictEqual(headers.trai, 'ler')
|
---|
265 | })
|
---|
266 |
|
---|
267 | req.on('end', function () {
|
---|
268 | assert(gotHeaders)
|
---|
269 |
|
---|
270 | res.writeHead(200, {
|
---|
271 | ok: 'yes'
|
---|
272 | })
|
---|
273 | res.end('response')
|
---|
274 | })
|
---|
275 | req.resume()
|
---|
276 | })
|
---|
277 | })
|
---|
278 |
|
---|
279 | it('should call .writeHead() automatically', function (done) {
|
---|
280 | var stream = client.request({
|
---|
281 | method: 'POST',
|
---|
282 | path: '/post'
|
---|
283 | }, function (err) {
|
---|
284 | assert(!err)
|
---|
285 |
|
---|
286 | stream.on('response', function (status, headers) {
|
---|
287 | assert.strictEqual(status, 300)
|
---|
288 |
|
---|
289 | fixtures.expectData(stream, 'response', done)
|
---|
290 | })
|
---|
291 | stream.end()
|
---|
292 | })
|
---|
293 |
|
---|
294 | server.on('request', function (req, res) {
|
---|
295 | req.on('end', function () {
|
---|
296 | res.statusCode = 300
|
---|
297 | res.end('response')
|
---|
298 | })
|
---|
299 | req.resume()
|
---|
300 | })
|
---|
301 | })
|
---|
302 |
|
---|
303 | it('should not crash on .writeHead() after socket close', function (done) {
|
---|
304 | var stream = client.request({
|
---|
305 | method: 'POST',
|
---|
306 | path: '/post'
|
---|
307 | }, function (err) {
|
---|
308 | assert(!err)
|
---|
309 |
|
---|
310 | setTimeout(function () {
|
---|
311 | client.socket.destroy()
|
---|
312 | }, 50)
|
---|
313 | stream.on('error', function () {})
|
---|
314 | stream.end()
|
---|
315 | })
|
---|
316 |
|
---|
317 | server.on('request', function (req, res) {
|
---|
318 | req.connection.on('close', function () {
|
---|
319 | assert.doesNotThrow(function () {
|
---|
320 | res.writeHead(200)
|
---|
321 | res.end('response')
|
---|
322 | })
|
---|
323 | done()
|
---|
324 | })
|
---|
325 | })
|
---|
326 | })
|
---|
327 |
|
---|
328 | it('should not crash on .push() after socket close', function (done) {
|
---|
329 | var stream = client.request({
|
---|
330 | method: 'POST',
|
---|
331 | path: '/post'
|
---|
332 | }, function (err) {
|
---|
333 | assert(!err)
|
---|
334 |
|
---|
335 | setTimeout(function () {
|
---|
336 | client.socket.destroy()
|
---|
337 | }, 50)
|
---|
338 | stream.on('error', function () {})
|
---|
339 | stream.end()
|
---|
340 | })
|
---|
341 |
|
---|
342 | server.on('request', function (req, res) {
|
---|
343 | req.connection.on('close', function () {
|
---|
344 | assert.doesNotThrow(function () {
|
---|
345 | assert.strictEqual(res.push('/push', {}), undefined)
|
---|
346 | res.end('response')
|
---|
347 | })
|
---|
348 | done()
|
---|
349 | })
|
---|
350 | })
|
---|
351 | })
|
---|
352 |
|
---|
353 | it('should end response after writing everything down', function (done) {
|
---|
354 | var stream = client.request({
|
---|
355 | method: 'GET',
|
---|
356 | path: '/post'
|
---|
357 | }, function (err) {
|
---|
358 | assert(!err)
|
---|
359 |
|
---|
360 | stream.on('response', function (status, headers) {
|
---|
361 | assert.strictEqual(status, 200)
|
---|
362 |
|
---|
363 | fixtures.expectData(stream, 'hello world, what\'s up?', done)
|
---|
364 | })
|
---|
365 |
|
---|
366 | stream.end()
|
---|
367 | })
|
---|
368 |
|
---|
369 | server.on('request', function (req, res) {
|
---|
370 | req.resume()
|
---|
371 | res.writeHead(200)
|
---|
372 | res.write('hello ')
|
---|
373 | res.write('world')
|
---|
374 | res.write(', what\'s')
|
---|
375 | res.write(' up?')
|
---|
376 | res.end()
|
---|
377 | })
|
---|
378 | })
|
---|
379 |
|
---|
380 | it('should handle x-forwarded-for', function (done) {
|
---|
381 | client.sendXForwardedFor('1.2.3.4')
|
---|
382 |
|
---|
383 | var stream = client.request({
|
---|
384 | method: 'GET',
|
---|
385 | path: '/post'
|
---|
386 | }, function (err) {
|
---|
387 | assert(!err)
|
---|
388 |
|
---|
389 | stream.resume()
|
---|
390 | stream.on('end', done)
|
---|
391 | stream.end()
|
---|
392 | })
|
---|
393 |
|
---|
394 | server.on('request', function (req, res) {
|
---|
395 | assert.strictEqual(req.headers['x-forwarded-for'], '1.2.3.4')
|
---|
396 | req.resume()
|
---|
397 | res.end()
|
---|
398 | })
|
---|
399 | })
|
---|
400 |
|
---|
401 | it('should destroy request after end', function (done) {
|
---|
402 | var stream = client.request({
|
---|
403 | method: 'POST',
|
---|
404 | path: '/post'
|
---|
405 | }, function (err) {
|
---|
406 | assert(!err)
|
---|
407 | })
|
---|
408 | stream.end()
|
---|
409 | stream.on('error', function () {})
|
---|
410 |
|
---|
411 | server.on('request', function (req, res) {
|
---|
412 | res.end()
|
---|
413 | res.destroy()
|
---|
414 | res.socket.on('close', function () {
|
---|
415 | done()
|
---|
416 | })
|
---|
417 | })
|
---|
418 | })
|
---|
419 | })
|
---|
420 |
|
---|
421 | it('should respond to http/1.1', function (done) {
|
---|
422 | var server = spdy.createServer(fixtures.keys, function (req, res) {
|
---|
423 | assert.strictEqual(req.isSpdy, res.isSpdy)
|
---|
424 | assert.strictEqual(req.spdyVersion, res.spdyVersion)
|
---|
425 | assert(!req.isSpdy)
|
---|
426 | assert.strictEqual(req.spdyVersion, 1)
|
---|
427 |
|
---|
428 | res.writeHead(200)
|
---|
429 | res.end()
|
---|
430 | })
|
---|
431 |
|
---|
432 | server.listen(fixtures.port, function () {
|
---|
433 | var req = https.request({
|
---|
434 | agent: false,
|
---|
435 | rejectUnauthorized: false,
|
---|
436 | NPNProtocols: ['http/1.1'],
|
---|
437 | port: fixtures.port,
|
---|
438 | method: 'GET',
|
---|
439 | path: '/'
|
---|
440 | }, function (res) {
|
---|
441 | assert.strictEqual(res.statusCode, 200)
|
---|
442 | res.resume()
|
---|
443 | res.on('end', function () {
|
---|
444 | server.close(done)
|
---|
445 | })
|
---|
446 | })
|
---|
447 |
|
---|
448 | req.end()
|
---|
449 | })
|
---|
450 | })
|
---|
451 |
|
---|
452 | it('should support custom base', function (done) {
|
---|
453 | function Pseuver (options, listener) {
|
---|
454 | https.Server.call(this, options, listener)
|
---|
455 | }
|
---|
456 | util.inherits(Pseuver, https.Server)
|
---|
457 |
|
---|
458 | var server = spdy.createServer(Pseuver, fixtures.keys, function (req, res) {
|
---|
459 | assert.strictEqual(req.isSpdy, res.isSpdy)
|
---|
460 | assert.strictEqual(req.spdyVersion, res.spdyVersion)
|
---|
461 | assert(!req.isSpdy)
|
---|
462 | assert.strictEqual(req.spdyVersion, 1)
|
---|
463 |
|
---|
464 | res.writeHead(200)
|
---|
465 | res.end()
|
---|
466 | })
|
---|
467 |
|
---|
468 | server.listen(fixtures.port, function () {
|
---|
469 | var req = https.request({
|
---|
470 | agent: false,
|
---|
471 | rejectUnauthorized: false,
|
---|
472 | NPNProtocols: ['http/1.1'],
|
---|
473 | port: fixtures.port,
|
---|
474 | method: 'GET',
|
---|
475 | path: '/'
|
---|
476 | }, function (res) {
|
---|
477 | assert.strictEqual(res.statusCode, 200)
|
---|
478 | res.resume()
|
---|
479 | res.on('end', function () {
|
---|
480 | server.close(done)
|
---|
481 | })
|
---|
482 | })
|
---|
483 |
|
---|
484 | req.end()
|
---|
485 | })
|
---|
486 | })
|
---|
487 | })
|
---|