mirror of https://github.com/lukechilds/node.git
Browse Source
includes parsing improvements to ensure closer HTTP spec conformance PR-URL: https://github.com/nodejs/node-private/pull/26 Reviewed-By: Rod Vagg <r@va.gg> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>process-exit-stdio-flushing
James M Snell
9 years ago
12 changed files with 409 additions and 18 deletions
@ -0,0 +1,28 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const http = require('http'); |
|||
const net = require('net'); |
|||
const assert = require('assert'); |
|||
|
|||
const reqstr = 'HTTP/1.1 200 OK\r\n' + |
|||
'Content-Length: 1\r\n' + |
|||
'Transfer-Encoding: chunked\r\n\r\n'; |
|||
|
|||
const server = net.createServer((socket) => { |
|||
socket.write(reqstr); |
|||
}); |
|||
|
|||
server.listen(common.PORT, () => { |
|||
// The callback should not be called because the server is sending
|
|||
// both a Content-Length header and a Transfer-Encoding: chunked
|
|||
// header, which is a violation of the HTTP spec.
|
|||
const req = http.get({port:common.PORT}, (res) => { |
|||
assert.fail(null, null, 'callback should not be called'); |
|||
}); |
|||
req.on('error', common.mustCall((err) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH'); |
|||
server.close(); |
|||
})); |
|||
}); |
@ -0,0 +1,27 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const http = require('http'); |
|||
const net = require('net'); |
|||
const assert = require('assert'); |
|||
|
|||
const reqstr = 'HTTP/1.1 200 OK\r\n' + |
|||
'Foo: Bar\r' + |
|||
'Content-Length: 1\r\n\r\n'; |
|||
|
|||
const server = net.createServer((socket) => { |
|||
socket.write(reqstr); |
|||
}); |
|||
|
|||
server.listen(common.PORT, () => { |
|||
// The callback should not be called because the server is sending a
|
|||
// header field that ends only in \r with no following \n
|
|||
const req = http.get({port:common.PORT}, (res) => { |
|||
assert.fail(null, null, 'callback should not be called'); |
|||
}); |
|||
req.on('error', common.mustCall((err) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_LF_EXPECTED'); |
|||
server.close(); |
|||
})); |
|||
}); |
@ -0,0 +1,33 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const http = require('http'); |
|||
const assert = require('assert'); |
|||
|
|||
// The callback should never be invoked because the server
|
|||
// should respond with a 400 Client Error when a double
|
|||
// Content-Length header is received.
|
|||
const server = http.createServer((req, res) => { |
|||
assert(false, 'callback should not have been invoked'); |
|||
res.end(); |
|||
}); |
|||
server.on('clientError', common.mustCall((err, socket) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH'); |
|||
socket.destroy(); |
|||
})); |
|||
|
|||
server.listen(common.PORT, () => { |
|||
const req = http.get({ |
|||
port: common.PORT, |
|||
// Send two content-length header values.
|
|||
headers: {'Content-Length': [1, 2]}}, |
|||
(res) => { |
|||
assert.fail(null, null, 'an error should have occurred'); |
|||
server.close(); |
|||
} |
|||
); |
|||
req.on('error', common.mustCall(() => { |
|||
server.close(); |
|||
})); |
|||
}); |
@ -0,0 +1,52 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const http = require('http'); |
|||
const assert = require('assert'); |
|||
|
|||
const MAX_COUNT = 2; |
|||
|
|||
const server = http.createServer((req, res) => { |
|||
const num = req.headers['x-num']; |
|||
// TODO(@jasnell) At some point this should be refactored as the API
|
|||
// should not be allowing users to set multiple content-length values
|
|||
// in the first place.
|
|||
switch (num) { |
|||
case '1': |
|||
res.setHeader('content-length', [2, 1]); |
|||
break; |
|||
case '2': |
|||
res.writeHead(200, {'content-length': [1, 2]}); |
|||
break; |
|||
default: |
|||
assert.fail(null, null, 'should never get here'); |
|||
} |
|||
res.end('ok'); |
|||
}); |
|||
|
|||
var count = 0; |
|||
|
|||
server.listen(common.PORT, common.mustCall(() => { |
|||
for (let n = 1; n <= MAX_COUNT ; n++) { |
|||
// This runs twice, the first time, the server will use
|
|||
// setHeader, the second time it uses writeHead. In either
|
|||
// case, the error handler must be called because the client
|
|||
// is not allowed to accept multiple content-length headers.
|
|||
http.get( |
|||
{port:common.PORT, headers:{'x-num': n}}, |
|||
(res) => { |
|||
assert(false, 'client allowed multiple content-length headers.'); |
|||
} |
|||
).on('error', common.mustCall((err) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH'); |
|||
count++; |
|||
if (count === MAX_COUNT) |
|||
server.close(); |
|||
})); |
|||
} |
|||
})); |
|||
|
|||
process.on('exit', () => { |
|||
assert.equal(count, MAX_COUNT); |
|||
}); |
@ -0,0 +1,31 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const http = require('http'); |
|||
const net = require('net'); |
|||
const assert = require('assert'); |
|||
|
|||
const reqstr = 'POST / HTTP/1.1\r\n' + |
|||
'Content-Length: 1\r\n' + |
|||
'Transfer-Encoding: chunked\r\n\r\n'; |
|||
|
|||
const server = http.createServer((req, res) => { |
|||
assert.fail(null, null, 'callback should not be invoked'); |
|||
}); |
|||
server.on('clientError', common.mustCall((err) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH'); |
|||
server.close(); |
|||
})); |
|||
server.listen(common.PORT, () => { |
|||
const client = net.connect({port: common.PORT}, () => { |
|||
client.write(reqstr); |
|||
client.end(); |
|||
}); |
|||
client.on('data', (data) => { |
|||
// Should not get to this point because the server should simply
|
|||
// close the connection without returning any data.
|
|||
assert.fail(null, null, 'no data should be returned by the server'); |
|||
}); |
|||
client.on('end', common.mustCall(() => {})); |
|||
}); |
@ -0,0 +1,33 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const net = require('net'); |
|||
const http = require('http'); |
|||
const assert = require('assert'); |
|||
|
|||
const str = 'GET / HTTP/1.1\r\n' + |
|||
'Dummy: Header\r' + |
|||
'Content-Length: 1\r\n' + |
|||
'\r\n'; |
|||
|
|||
|
|||
const server = http.createServer((req, res) => { |
|||
assert.fail(null, null, 'this should not be called'); |
|||
}); |
|||
server.on('clientError', common.mustCall((err) => { |
|||
assert(/^Parse Error/.test(err.message)); |
|||
assert.equal(err.code, 'HPE_LF_EXPECTED'); |
|||
server.close(); |
|||
})); |
|||
server.listen(common.PORT, () => { |
|||
const client = net.connect({port:common.PORT}, () => { |
|||
client.on('data', (chunk) => { |
|||
assert.fail(null, null, 'this should not be called'); |
|||
}); |
|||
client.on('end', common.mustCall(() => { |
|||
server.close(); |
|||
})); |
|||
client.write(str); |
|||
client.end(); |
|||
}); |
|||
}); |
Loading…
Reference in new issue