Skip to content

Commit 1315545

Browse files
authoredJul 24, 2018
Merge pull request #223 from ggoodman/fix-pipe-after-socket-connect
Defer piping of options.payload until socket connection
2 parents 576ce9d + 0122d11 commit 1315545

File tree

2 files changed

+88
-18
lines changed

2 files changed

+88
-18
lines changed
 

‎lib/index.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ internals.Client.prototype._request = function (method, url, options, relay, _tr
314314
stream = options.payload.pipe(collector);
315315
}
316316

317-
stream.pipe(req);
317+
internals.deferPipeUntilSocketConnects(req, stream);
318318
return req;
319319
}
320320

@@ -328,6 +328,21 @@ internals.Client.prototype._request = function (method, url, options, relay, _tr
328328
};
329329

330330

331+
internals.deferPipeUntilSocketConnects = function (req, stream) {
332+
333+
const onSocket = (socket) => {
334+
335+
socket.on('connect', onSocketConnect);
336+
};
337+
const onSocketConnect = () => {
338+
339+
stream.pipe(req);
340+
};
341+
342+
req.on('socket', onSocket);
343+
};
344+
345+
331346
internals.redirectMethod = function (code, method, options) {
332347

333348
switch (code) {

‎test/index.js

+72-17
Original file line numberDiff line numberDiff line change
@@ -958,57 +958,57 @@ describe('options.baseUrl', () => {
958958

959959
it('uses baseUrl option without trailing slash and uri is prefixed with a slash', async () => {
960960

961-
const promise = Wreck.request('get', '/foo', { baseUrl: 'http://localhost' });
961+
const promise = Wreck.request('get', '/foo', { baseUrl: 'http://localhost:0' });
962962
await expect(promise).to.reject();
963-
expect(promise.req._headers.host).to.equal('localhost');
963+
expect(promise.req._headers.host).to.equal('localhost:0');
964964
expect(promise.req.path).to.equal('/foo');
965965
});
966966

967967
it('uses baseUrl option with trailing slash and uri is prefixed without a slash', async () => {
968968

969-
const promise = Wreck.request('get', 'foo', { baseUrl: 'http://localhost/' });
969+
const promise = Wreck.request('get', 'foo', { baseUrl: 'http://localhost:0/' });
970970
await expect(promise).to.reject();
971-
expect(promise.req._headers.host).to.equal('localhost');
971+
expect(promise.req._headers.host).to.equal('localhost:0');
972972
expect(promise.req.path).to.equal('/foo');
973973
});
974974

975975
it('uses baseUrl option without trailing slash and uri is prefixed without a slash', async () => {
976976

977-
const promise = Wreck.request('get', 'foo', { baseUrl: 'http://localhost' });
977+
const promise = Wreck.request('get', 'foo', { baseUrl: 'http://localhost:0' });
978978
await expect(promise).to.reject();
979-
expect(promise.req._headers.host).to.equal('localhost');
979+
expect(promise.req._headers.host).to.equal('localhost:0');
980980
expect(promise.req.path).to.equal('/foo');
981981
});
982982

983983
it('uses baseUrl option when uri is an empty string', async () => {
984984

985-
const promise = Wreck.request('get', '', { baseUrl: 'http://localhost' });
985+
const promise = Wreck.request('get', '', { baseUrl: 'http://localhost:0' });
986986
await expect(promise).to.reject();
987-
expect(promise.req._headers.host).to.equal('localhost');
987+
expect(promise.req._headers.host).to.equal('localhost:0');
988988
expect(promise.req.path).to.equal('/');
989989
});
990990

991991
it('uses baseUrl option with a path', async () => {
992992

993-
const promise = Wreck.request('get', '/bar', { baseUrl: 'http://localhost/foo' });
993+
const promise = Wreck.request('get', '/bar', { baseUrl: 'http://localhost:0/foo' });
994994
await expect(promise).to.reject();
995-
expect(promise.req._headers.host).to.equal('localhost');
995+
expect(promise.req._headers.host).to.equal('localhost:0');
996996
expect(promise.req.path).to.equal('/foo/bar');
997997
});
998998

999999
it('uses baseUrl option with a path and removes extra slashes', async () => {
10001000

1001-
const promise = Wreck.request('get', '/bar', { baseUrl: 'http://localhost/foo/' });
1001+
const promise = Wreck.request('get', '/bar', { baseUrl: 'http://localhost:0/foo/' });
10021002
await expect(promise).to.reject();
1003-
expect(promise.req._headers.host).to.equal('localhost');
1003+
expect(promise.req._headers.host).to.equal('localhost:0');
10041004
expect(promise.req.path).to.equal('/foo/bar');
10051005
});
10061006

10071007
it('uses baseUrl option with a url that has a querystring', async () => {
10081008

1009-
const promise = Wreck.request('get', '/bar?test=hello', { baseUrl: 'http://localhost/foo' });
1009+
const promise = Wreck.request('get', '/bar?test=hello', { baseUrl: 'http://localhost:0/foo' });
10101010
await expect(promise).to.reject();
1011-
expect(promise.req._headers.host).to.equal('localhost');
1011+
expect(promise.req._headers.host).to.equal('localhost:0');
10121012
expect(promise.req.path).to.equal('/foo/bar?test=hello');
10131013
});
10141014
});
@@ -1121,6 +1121,47 @@ describe('read()', () => {
11211121
expect(err.isBoom).to.equal(true);
11221122
});
11231123

1124+
it('will not pipe the stream if no socket can be established', async () => {
1125+
1126+
const agent = new internals.SlowAgent();
1127+
const stream = new Stream.Readable({
1128+
read() {
1129+
1130+
piped = true;
1131+
this.push(null);
1132+
}
1133+
});
1134+
const onPiped = () => {
1135+
1136+
piped = true;
1137+
};
1138+
let piped = false;
1139+
1140+
stream.on('pipe', onPiped);
1141+
1142+
const promiseA = Wreck.request('post', 'http://localhost:0', {
1143+
agent,
1144+
payload: stream
1145+
});
1146+
1147+
await expect(promiseA).to.reject(Error, /Unable to obtain socket/);
1148+
expect(piped).to.equal(false);
1149+
1150+
const handler = (req, res) => {
1151+
1152+
res.writeHead(200);
1153+
res.end(internals.payload);
1154+
};
1155+
1156+
const server = await internals.server(handler);
1157+
const res = await Wreck.request('post', 'http://localhost:' + server.address().port, {
1158+
payload: stream
1159+
});
1160+
expect(res.statusCode).to.equal(200);
1161+
expect(piped).to.equal(true);
1162+
server.close();
1163+
});
1164+
11241165
it('times out when stream read takes too long', async () => {
11251166

11261167
const TestStream = function () {
@@ -1759,7 +1800,7 @@ describe('Events', () => {
17591800
once = true;
17601801
});
17611802

1762-
await expect(wreck.get('http://127.0.0.1', { timeout: 10 })).to.reject();
1803+
await expect(wreck.get('http://localhost:0', { timeout: 10 })).to.reject();
17631804
expect(once).to.be.true();
17641805
});
17651806

@@ -1777,8 +1818,8 @@ describe('Events', () => {
17771818
const wreck = Wreck.defaults({ events: true });
17781819
wreck.events.on('response', handler);
17791820

1780-
await expect(wreck.get('http://127.0.0.1', { timeout: 10 })).to.reject();
1781-
await expect(wreck.get('http://127.0.0.1', { timeout: 10 })).to.reject();
1821+
await expect(wreck.get('http://localhost:0', { timeout: 10 })).to.reject();
1822+
await expect(wreck.get('http://localhost:0', { timeout: 10 })).to.reject();
17821823
expect(count).to.equal(2);
17831824
});
17841825

@@ -1973,6 +2014,12 @@ internals.server = function (handler, socket) {
19732014
req.pipe(res);
19742015
};
19752016
}
2017+
else if (handler === 'fail') {
2018+
handler = (req, res) => {
2019+
2020+
res.socket.destroy();
2021+
};
2022+
}
19762023
else if (handler === 'ok') {
19772024
handler = (req, res) => {
19782025

@@ -2020,6 +2067,14 @@ internals.https = function (handler) {
20202067
};
20212068

20222069

2070+
internals.SlowAgent = class SlowAgent extends Http.Agent {
2071+
createConnection(options, cb) {
2072+
2073+
setTimeout(cb, 200, new Error('Unable to obtain socket'));
2074+
}
2075+
};
2076+
2077+
20232078
internals.wait = function (timeout) {
20242079

20252080
return new Promise((resolve) => setTimeout(resolve, timeout));

0 commit comments

Comments
 (0)