488 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			488 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* eslint-env mocha */
 | |
| 
 | |
| var assert = require('assert')
 | |
| var tls = require('tls')
 | |
| var net = require('net')
 | |
| var https = require('https')
 | |
| var transport = require('spdy-transport')
 | |
| var util = require('util')
 | |
| 
 | |
| var fixtures = require('./fixtures')
 | |
| var spdy = require('../')
 | |
| 
 | |
| describe('SPDY Server', function () {
 | |
|   fixtures.everyConfig(function (protocol, alpn, version, plain) {
 | |
|     var server
 | |
|     var client
 | |
| 
 | |
|     beforeEach(function (done) {
 | |
|       server = spdy.createServer(Object.assign({
 | |
|         spdy: {
 | |
|           'x-forwarded-for': true,
 | |
|           plain: plain
 | |
|         }
 | |
|       }, fixtures.keys))
 | |
| 
 | |
|       server.listen(fixtures.port, function () {
 | |
|         var socket = (plain ? net : tls).connect({
 | |
|           rejectUnauthorized: false,
 | |
|           port: fixtures.port,
 | |
|           ALPNProtocols: [alpn]
 | |
|         }, function () {
 | |
|           client = transport.connection.create(socket, {
 | |
|             protocol: protocol,
 | |
|             isServer: false
 | |
|           })
 | |
|           client.start(version)
 | |
|           done()
 | |
|         })
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     afterEach(function (done) {
 | |
|       client.socket.destroy()
 | |
|       server.close(done)
 | |
|     })
 | |
| 
 | |
|     it('should process GET request', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'GET',
 | |
|         path: '/get',
 | |
|         headers: {
 | |
|           a: 'b'
 | |
|         }
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('error', (err) => {
 | |
|           done(err)
 | |
|         })
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 200)
 | |
|           assert.strictEqual(headers.ok, 'yes')
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', done)
 | |
|         })
 | |
| 
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         assert.strictEqual(req.isSpdy, res.isSpdy)
 | |
|         assert.strictEqual(req.spdyVersion, res.spdyVersion)
 | |
|         assert(req.isSpdy)
 | |
|         if (!plain) {
 | |
|           assert(req.socket.encrypted)
 | |
|           assert(req.socket.getPeerCertificate())
 | |
|         }
 | |
| 
 | |
|         // Auto-detection
 | |
|         if (version === 3.1) {
 | |
|           assert(req.spdyVersion >= 3 && req.spdyVersion <= 3.1)
 | |
|         } else {
 | |
|           assert.strictEqual(req.spdyVersion, version)
 | |
|         }
 | |
|         assert(req.spdyStream)
 | |
|         assert(res.spdyStream)
 | |
| 
 | |
|         assert.strictEqual(req.method, 'GET')
 | |
|         assert.strictEqual(req.url, '/get')
 | |
|         assert.deepStrictEqual(req.headers, { a: 'b', host: 'localhost' })
 | |
| 
 | |
|         req.on('end', function () {
 | |
|           res.writeHead(200, {
 | |
|             ok: 'yes'
 | |
|           })
 | |
|           res.end('response')
 | |
|           assert(res.finished, 'res.finished should be set')
 | |
|         })
 | |
|         req.resume()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should process POST request', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 200)
 | |
|           assert.strictEqual(headers.ok, 'yes')
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', next)
 | |
|         })
 | |
| 
 | |
|         stream.end('request')
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         assert.strictEqual(req.method, 'POST')
 | |
|         assert.strictEqual(req.url, '/post')
 | |
| 
 | |
|         res.writeHead(200, {
 | |
|           ok: 'yes'
 | |
|         })
 | |
|         res.end('response')
 | |
| 
 | |
|         fixtures.expectData(req, 'request', next)
 | |
|       })
 | |
| 
 | |
|       var waiting = 2
 | |
|       function next () {
 | |
|         if (--waiting === 0) {
 | |
|           return done()
 | |
|         }
 | |
|       }
 | |
|     })
 | |
| 
 | |
|     it('should process expect-continue request', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'GET',
 | |
|         path: '/get',
 | |
|         headers: {
 | |
|           Expect: '100-continue'
 | |
|         }
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 100)
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', done)
 | |
|         })
 | |
| 
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         req.on('end', function () {
 | |
|           res.end('response')
 | |
|         })
 | |
|         req.resume()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should emit `checkContinue` request', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'GET',
 | |
|         path: '/get',
 | |
|         headers: {
 | |
|           Expect: '100-continue'
 | |
|         }
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 100)
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', done)
 | |
|         })
 | |
| 
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('checkContinue', function (req, res) {
 | |
|         req.on('end', function () {
 | |
|           res.writeContinue()
 | |
|           res.end('response')
 | |
|         })
 | |
|         req.resume()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should send PUSH_PROMISE', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/page'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('pushPromise', function (push) {
 | |
|           assert.strictEqual(push.path, '/push')
 | |
|           assert.strictEqual(push.headers.yes, 'push')
 | |
| 
 | |
|           fixtures.expectData(push, 'push', next)
 | |
|           fixtures.expectData(stream, 'response', next)
 | |
|         })
 | |
| 
 | |
|         stream.end('request')
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         assert.strictEqual(req.method, 'POST')
 | |
|         assert.strictEqual(req.url, '/page')
 | |
| 
 | |
|         res.writeHead(200, {
 | |
|           ok: 'yes'
 | |
|         })
 | |
| 
 | |
|         var push = res.push('/push', {
 | |
|           request: {
 | |
|             yes: 'push'
 | |
|           }
 | |
|         })
 | |
|         push.end('push')
 | |
| 
 | |
|         res.end('response')
 | |
| 
 | |
|         fixtures.expectData(req, 'request', next)
 | |
|       })
 | |
| 
 | |
|       var waiting = 3
 | |
|       function next () {
 | |
|         if (--waiting === 0) {
 | |
|           return done()
 | |
|         }
 | |
|       }
 | |
|     })
 | |
| 
 | |
|     it('should receive trailing headers', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.sendHeaders({ trai: 'ler' })
 | |
|         stream.end()
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 200)
 | |
|           assert.strictEqual(headers.ok, 'yes')
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', done)
 | |
|         })
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         var gotHeaders = false
 | |
|         req.on('trailers', function (headers) {
 | |
|           gotHeaders = true
 | |
|           assert.strictEqual(headers.trai, 'ler')
 | |
|         })
 | |
| 
 | |
|         req.on('end', function () {
 | |
|           assert(gotHeaders)
 | |
| 
 | |
|           res.writeHead(200, {
 | |
|             ok: 'yes'
 | |
|           })
 | |
|           res.end('response')
 | |
|         })
 | |
|         req.resume()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should call .writeHead() automatically', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 300)
 | |
| 
 | |
|           fixtures.expectData(stream, 'response', done)
 | |
|         })
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         req.on('end', function () {
 | |
|           res.statusCode = 300
 | |
|           res.end('response')
 | |
|         })
 | |
|         req.resume()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should not crash on .writeHead() after socket close', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         setTimeout(function () {
 | |
|           client.socket.destroy()
 | |
|         }, 50)
 | |
|         stream.on('error', function () {})
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         req.connection.on('close', function () {
 | |
|           assert.doesNotThrow(function () {
 | |
|             res.writeHead(200)
 | |
|             res.end('response')
 | |
|           })
 | |
|           done()
 | |
|         })
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should not crash on .push() after socket close', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         setTimeout(function () {
 | |
|           client.socket.destroy()
 | |
|         }, 50)
 | |
|         stream.on('error', function () {})
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         req.connection.on('close', function () {
 | |
|           assert.doesNotThrow(function () {
 | |
|             assert.strictEqual(res.push('/push', {}), undefined)
 | |
|             res.end('response')
 | |
|           })
 | |
|           done()
 | |
|         })
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should end response after writing everything down', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'GET',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.on('response', function (status, headers) {
 | |
|           assert.strictEqual(status, 200)
 | |
| 
 | |
|           fixtures.expectData(stream, 'hello world, what\'s up?', done)
 | |
|         })
 | |
| 
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         req.resume()
 | |
|         res.writeHead(200)
 | |
|         res.write('hello ')
 | |
|         res.write('world')
 | |
|         res.write(', what\'s')
 | |
|         res.write(' up?')
 | |
|         res.end()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should handle x-forwarded-for', function (done) {
 | |
|       client.sendXForwardedFor('1.2.3.4')
 | |
| 
 | |
|       var stream = client.request({
 | |
|         method: 'GET',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
| 
 | |
|         stream.resume()
 | |
|         stream.on('end', done)
 | |
|         stream.end()
 | |
|       })
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         assert.strictEqual(req.headers['x-forwarded-for'], '1.2.3.4')
 | |
|         req.resume()
 | |
|         res.end()
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     it('should destroy request after end', function (done) {
 | |
|       var stream = client.request({
 | |
|         method: 'POST',
 | |
|         path: '/post'
 | |
|       }, function (err) {
 | |
|         assert(!err)
 | |
|       })
 | |
|       stream.end()
 | |
|       stream.on('error', function () {})
 | |
| 
 | |
|       server.on('request', function (req, res) {
 | |
|         res.end()
 | |
|         res.destroy()
 | |
|         res.socket.on('close', function () {
 | |
|           done()
 | |
|         })
 | |
|       })
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   it('should respond to http/1.1', function (done) {
 | |
|     var server = spdy.createServer(fixtures.keys, function (req, res) {
 | |
|       assert.strictEqual(req.isSpdy, res.isSpdy)
 | |
|       assert.strictEqual(req.spdyVersion, res.spdyVersion)
 | |
|       assert(!req.isSpdy)
 | |
|       assert.strictEqual(req.spdyVersion, 1)
 | |
| 
 | |
|       res.writeHead(200)
 | |
|       res.end()
 | |
|     })
 | |
| 
 | |
|     server.listen(fixtures.port, function () {
 | |
|       var req = https.request({
 | |
|         agent: false,
 | |
|         rejectUnauthorized: false,
 | |
|         NPNProtocols: ['http/1.1'],
 | |
|         port: fixtures.port,
 | |
|         method: 'GET',
 | |
|         path: '/'
 | |
|       }, function (res) {
 | |
|         assert.strictEqual(res.statusCode, 200)
 | |
|         res.resume()
 | |
|         res.on('end', function () {
 | |
|           server.close(done)
 | |
|         })
 | |
|       })
 | |
| 
 | |
|       req.end()
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   it('should support custom base', function (done) {
 | |
|     function Pseuver (options, listener) {
 | |
|       https.Server.call(this, options, listener)
 | |
|     }
 | |
|     util.inherits(Pseuver, https.Server)
 | |
| 
 | |
|     var server = spdy.createServer(Pseuver, fixtures.keys, function (req, res) {
 | |
|       assert.strictEqual(req.isSpdy, res.isSpdy)
 | |
|       assert.strictEqual(req.spdyVersion, res.spdyVersion)
 | |
|       assert(!req.isSpdy)
 | |
|       assert.strictEqual(req.spdyVersion, 1)
 | |
| 
 | |
|       res.writeHead(200)
 | |
|       res.end()
 | |
|     })
 | |
| 
 | |
|     server.listen(fixtures.port, function () {
 | |
|       var req = https.request({
 | |
|         agent: false,
 | |
|         rejectUnauthorized: false,
 | |
|         NPNProtocols: ['http/1.1'],
 | |
|         port: fixtures.port,
 | |
|         method: 'GET',
 | |
|         path: '/'
 | |
|       }, function (res) {
 | |
|         assert.strictEqual(res.statusCode, 200)
 | |
|         res.resume()
 | |
|         res.on('end', function () {
 | |
|           server.close(done)
 | |
|         })
 | |
|       })
 | |
| 
 | |
|       req.end()
 | |
|     })
 | |
|   })
 | |
| })
 |