You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
12 KiB

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