• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23require('../common');
24const http = require('http');
25const net = require('net');
26
27// Check that our HTTP server correctly handles HTTP/1.0 keep-alive requests.
28check([{
29  name: 'keep-alive, no TE header',
30  requests: [{
31    expectClose: true,
32    data: 'POST / HTTP/1.0\r\n' +
33          'Connection: keep-alive\r\n' +
34          '\r\n'
35  }, {
36    expectClose: true,
37    data: 'POST / HTTP/1.0\r\n' +
38          'Connection: keep-alive\r\n' +
39          '\r\n'
40  }],
41  responses: [{
42    headers: { 'Connection': 'keep-alive' },
43    chunks: ['OK']
44  }, {
45    chunks: []
46  }]
47}, {
48  name: 'keep-alive, with TE: chunked',
49  requests: [{
50    expectClose: false,
51    data: 'POST / HTTP/1.0\r\n' +
52          'Connection: keep-alive\r\n' +
53          'TE: chunked\r\n' +
54          '\r\n'
55  }, {
56    expectClose: true,
57    data: 'POST / HTTP/1.0\r\n' +
58          '\r\n'
59  }],
60  responses: [{
61    headers: { 'Connection': 'keep-alive' },
62    chunks: ['OK']
63  }, {
64    chunks: []
65  }]
66}, {
67  name: 'keep-alive, with Transfer-Encoding: chunked',
68  requests: [{
69    expectClose: false,
70    data: 'POST / HTTP/1.0\r\n' +
71          'Connection: keep-alive\r\n' +
72          '\r\n'
73  }, {
74    expectClose: true,
75    data: 'POST / HTTP/1.0\r\n' +
76          '\r\n'
77  }],
78  responses: [{
79    headers: { 'Connection': 'keep-alive',
80               'Transfer-Encoding': 'chunked' },
81    chunks: ['OK']
82  }, {
83    chunks: []
84  }]
85}, {
86  name: 'keep-alive, with Content-Length',
87  requests: [{
88    expectClose: false,
89    data: 'POST / HTTP/1.0\r\n' +
90          'Connection: keep-alive\r\n' +
91          '\r\n'
92  }, {
93    expectClose: true,
94    data: 'POST / HTTP/1.0\r\n' +
95          '\r\n'
96  }],
97  responses: [{
98    headers: { 'Connection': 'keep-alive',
99               'Content-Length': '2' },
100    chunks: ['OK']
101  }, {
102    chunks: []
103  }]
104}]);
105
106function check(tests) {
107  const test = tests[0];
108  let server;
109  if (test) {
110    server = http.createServer(serverHandler).listen(0, '127.0.0.1', client);
111  }
112  let current = 0;
113
114  function next() {
115    check(tests.slice(1));
116  }
117
118  function serverHandler(req, res) {
119    if (current + 1 === test.responses.length) this.close();
120    const ctx = test.responses[current];
121    console.error('<  SERVER SENDING RESPONSE', ctx);
122    res.writeHead(200, ctx.headers);
123    ctx.chunks.slice(0, -1).forEach(function(chunk) { res.write(chunk); });
124    res.end(ctx.chunks[ctx.chunks.length - 1]);
125  }
126
127  function client() {
128    if (current === test.requests.length) return next();
129    const port = server.address().port;
130    const conn = net.createConnection(port, '127.0.0.1', connected);
131
132    function connected() {
133      const ctx = test.requests[current];
134      console.error(' > CLIENT SENDING REQUEST', ctx);
135      conn.setEncoding('utf8');
136      conn.write(ctx.data);
137
138      function onclose() {
139        console.error(' > CLIENT CLOSE');
140        if (!ctx.expectClose) throw new Error('unexpected close');
141        client();
142      }
143      conn.on('close', onclose);
144
145      function ondata(s) {
146        console.error(' > CLIENT ONDATA %j %j', s.length, s.toString());
147        current++;
148        if (ctx.expectClose) return;
149        conn.removeListener('close', onclose);
150        conn.removeListener('data', ondata);
151        connected();
152      }
153      conn.on('data', ondata);
154    }
155  }
156}
157