Skip to content

Commit f86dbd2

Browse files
authored
Merge pull request #444 from cristiklein/fix-redirect-with-head-with-body
Fix redirect with head with body
2 parents 9454d7b + a52baad commit f86dbd2

File tree

4 files changed

+118
-6
lines changed

4 files changed

+118
-6
lines changed

.editorconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_style = space
7+
indent_size = 2

lib/needle.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,20 +455,25 @@ Needle.prototype.send_request = function(count, method, uri, config, post_data,
455455
protocol = request_opts.protocol == 'https:' ? https : http,
456456
signal = request_opts.signal;
457457

458-
function done(err, resp) {
459-
if (returned++ > 0)
460-
return debug('Already finished, stopping here.');
461-
462-
if (timer) clearTimeout(timer);
458+
function unlisten_errors() {
463459
request.removeListener('error', had_error);
464-
out.done = true;
465460

466461
// An error can still be fired after closing. In particular, on macOS.
467462
// See also:
468463
// - https://github.com/tomas/needle/issues/391
469464
// - https://github.com/less/less.js/issues/3693
470465
// - https://github.com/nodejs/node/issues/27916
471466
request.once('error', function() {});
467+
}
468+
469+
function done(err, resp) {
470+
if (returned++ > 0)
471+
return debug('Already finished, stopping here.');
472+
473+
if (timer) clearTimeout(timer);
474+
out.done = true;
475+
476+
unlisten_errors();
472477

473478
if (callback)
474479
return callback(err, resp, resp ? resp.body : undefined);
@@ -559,6 +564,7 @@ Needle.prototype.send_request = function(count, method, uri, config, post_data,
559564

560565
var redirect_url = utils.resolve_url(headers.location, uri);
561566
debug('Redirecting to ' + redirect_url.toString());
567+
unlisten_errors();
562568
return self.send_request(++count, method, redirect_url.toString(), config, post_data, out, callback);
563569
} else if (config.follow_max > 0) {
564570
return done(new Error('Max redirects reached. Possible loop in: ' + headers.location));
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
var helpers = require('./helpers'),
2+
should = require('should'),
3+
sinon = require('sinon'),
4+
http = require('http'),
5+
needle = require('./../');
6+
7+
const port = 1234;
8+
9+
describe('redirects with bad redirector', function() {
10+
11+
var spies = {},
12+
servers = {};
13+
14+
before(function(done) {
15+
servers.http = http.createServer(function(req, res) {
16+
if (req.url == '/foo/bar') {
17+
res.end('Redirected successfully!');
18+
return;
19+
}
20+
21+
/* Don't judge me. I found at least one server on the
22+
* Internet doing this and it triggered a bug. */
23+
const body = 'Let me send you a body, although you only asked for a HEAD.';
24+
25+
const headers =
26+
'HTTP/1.1 302 Found\r\n' +
27+
'Connection: close\r\n' +
28+
'Location: /foo/bar\r\n' +
29+
`Content-Length: ${Buffer.byteLength(body)}\r\n` +
30+
'\r\n';
31+
32+
res.socket.write(headers + body);
33+
res.socket.destroy();
34+
}).listen(port, done);
35+
})
36+
37+
after(function(done) {
38+
servers.http.close(done);
39+
})
40+
41+
it('calls back exactly once', function (done) {
42+
const opts = {
43+
follow: 5,
44+
}
45+
46+
const url = `http://localhost:${port}`
47+
needle.head(url, opts, function (err, resp, body) {
48+
//should(body && body.toString()).eql('Redirected successfully!');
49+
done();
50+
});
51+
});
52+
53+
it('calls back exactly once with follow_keep_method', function (done) {
54+
const opts = {
55+
follow: 5,
56+
follow_keep_method: true,
57+
}
58+
59+
const url = `http://localhost:${port}`
60+
needle.head(url, opts, function (err, resp, body) {
61+
//should(body && body.toString()).eql('Redirected successfully!');
62+
done();
63+
});
64+
});
65+
});

test/utils/bad-redirector.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
var http = require('http'),
2+
https = require('https'),
3+
url = require('url');
4+
5+
var port = 1234,
6+
log = true,
7+
request_auth = false;
8+
9+
http.createServer(function(req, res) {
10+
11+
console.log(req.headers);
12+
console.log("Got request: " + req.method + " " + req.url);
13+
14+
/* Don't judge me. I found at least one server on the
15+
* Internet doing this and it triggered a bug. */
16+
const body = 'Let me send you a body, although you only asked for a HEAD.';
17+
18+
const headers =
19+
'HTTP/1.1 302 Found\r\n' +
20+
'Connection: close\r\n' +
21+
'Location: /foo/bar\r\n' +
22+
`Content-Length: ${Buffer.byteLength(body)}\r\n` +
23+
'\r\n';
24+
25+
res.socket.write(headers + body);
26+
res.socket.destroy();
27+
}).listen(port);
28+
29+
process.on('uncaughtException', function(err){
30+
console.log('Uncaught exception!');
31+
console.log(err);
32+
});
33+
34+
console.log("Bad redirector listening on port " + port);

0 commit comments

Comments
 (0)