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