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()
|
||
|
})
|
||
|
})
|
||
|
})
|