Skip to content

Commit da451fc

Browse files
committed
more
1 parent f20fb28 commit da451fc

File tree

6 files changed

+152
-10
lines changed

6 files changed

+152
-10
lines changed

packages/bun-uws/src/App.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ struct TemplatedApp {
249249
}
250250

251251
static TemplatedApp<SSL>* create(SocketContextOptions options = {}) {
252+
252253
auto* httpContext = HttpContext<SSL>::create(Loop::get(), options);
253254
if (!httpContext) {
254255
return nullptr;

src/js/node/_http_client.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ function ClientRequest(input, options, cb) {
372372
this[kFetchRequest] = null;
373373
this[kClearTimeout]();
374374
handleResponse = undefined;
375+
375376
const prevIsHTTPS = getIsNextIncomingMessageHTTPS();
376377
setIsNextIncomingMessageHTTPS(response.url.startsWith("https:"));
377378
var res = (this.res = new IncomingMessage(response, {
@@ -401,16 +402,16 @@ function ClientRequest(input, options, cb) {
401402
if (self.aborted || !self.emit("response", res)) {
402403
res._dump();
403404
}
405+
maybeEmitClose();
406+
if (res.statusCode === 304) {
407+
res.complete = true;
408+
maybeEmitClose();
409+
return;
410+
}
404411
},
405412
this,
406413
res,
407414
);
408-
maybeEmitClose();
409-
if (res.statusCode === 304) {
410-
res.complete = true;
411-
maybeEmitClose();
412-
return;
413-
}
414415
};
415416

416417
if (!keepOpen) {

src/js/node/_http_server.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ const ServerResponsePrototype = {
509509
if (handle) {
510510
handle.abort();
511511
}
512+
this?.socket?.destroy();
512513
return this;
513514
},
514515

@@ -802,7 +803,31 @@ const ServerPrototype = {
802803
this.listening = false;
803804
server.stop();
804805
},
805-
806+
[EventEmitter.captureRejectionSymbol]: function (err, event, ...args) {
807+
switch (event) {
808+
case "request": {
809+
const { 1: res } = args;
810+
if (!res.headersSent && !res.writableEnded) {
811+
// Don't leak headers.
812+
const names = res.getHeaderNames();
813+
for (let i = 0; i < names.length; i++) {
814+
res.removeHeader(names[i]);
815+
}
816+
res.statusCode = 500;
817+
res.end(STATUS_CODES[500]);
818+
} else {
819+
res.destroy();
820+
}
821+
break;
822+
}
823+
default:
824+
// net.Server.prototype[EventEmitter.captureRejectionSymbol].apply(this, arguments);
825+
// .apply(this, arguments);
826+
const { 1: res } = args;
827+
res?.socket?.destroy();
828+
break;
829+
}
830+
},
806831
[Symbol.asyncDispose]() {
807832
const { resolve, reject, promise } = Promise.withResolvers();
808833
this.close(function (err, ...args) {
@@ -1220,7 +1245,11 @@ const NodeHTTPServerSocket = class Socket extends Duplex {
12201245
if (req && !req.complete && !req[kHandle]?.upgraded) {
12211246
// At this point the socket is already destroyed; let's avoid UAF
12221247
req[kHandle] = undefined;
1223-
req.destroy(new ConnResetException("aborted"));
1248+
if (req.listenerCount("error") > 0) {
1249+
req.destroy(new ConnResetException("aborted"));
1250+
} else {
1251+
req.destroy();
1252+
}
12241253
}
12251254
}
12261255
#onCloseForDestroy(closeCallback) {

src/js/node/events.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ function EventEmitter(opts) {
6767
this[kCapture] = !!opts.captureRejections;
6868
this.emit = emitWithRejectionCapture;
6969
} else {
70-
this[kCapture] = EventEmitterPrototype[kCapture];
70+
const capture = EventEmitterPrototype[kCapture];
71+
this[kCapture] = capture;
72+
this.emit = capture ? emitWithRejectionCapture : emitWithoutRejectionCapture;
7173
}
7274
}
7375
Object.defineProperty(EventEmitter, "name", { value: "EventEmitter", configurable: true });

test/js/node/http/node-http.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,8 +1499,8 @@ it("should emit events in the right order", async () => {
14991499
["req", "response"],
15001500
"STATUS: 200",
15011501
// TODO: not totally right:
1502-
["req", "close"],
15031502
["res", "resume"],
1503+
["req", "close"],
15041504
["res", "readable"],
15051505
["res", "end"],
15061506
["res", "close"],
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const events = require('events');
5+
const { createServer, request } = require('http');
6+
const assert = require('assert');
7+
8+
events.captureRejections = true;
9+
10+
{
11+
const server = createServer(common.mustCall(async (req, res) => {
12+
// We will test that this header is cleaned up before forwarding.
13+
res.setHeader('content-type', 'application/json');
14+
throw new Error('kaboom');
15+
}));
16+
17+
server.listen(0, common.mustCall(() => {
18+
const req = request({
19+
method: 'GET',
20+
host: server.address().host,
21+
port: server.address().port
22+
});
23+
24+
req.end();
25+
26+
req.on('response', common.mustCall((res) => {
27+
assert.strictEqual(res.statusCode, 500);
28+
assert.strictEqual(Object.hasOwn(res.headers, 'content-type'), false);
29+
let data = '';
30+
res.setEncoding('utf8');
31+
res.on('data', common.mustCall((chunk) => {
32+
data += chunk;
33+
}));
34+
res.on('end', common.mustCall(() => {
35+
assert.strictEqual(data, 'Internal Server Error');
36+
server.close();
37+
}));
38+
}));
39+
}));
40+
}
41+
42+
{
43+
let resolve;
44+
const latch = new Promise((_resolve) => {
45+
resolve = _resolve;
46+
});
47+
const server = createServer(common.mustCall(async (req, res) => {
48+
server.close();
49+
50+
// We will test that this header is cleaned up before forwarding.
51+
res.setHeader('content-type', 'application/json');
52+
res.write('{');
53+
req.resume();
54+
55+
// Wait so the data is on the wire
56+
await latch;
57+
58+
throw new Error('kaboom');
59+
}));
60+
61+
server.listen(0, common.mustCall(() => {
62+
const req = request({
63+
method: 'GET',
64+
host: server.address().host,
65+
port: server.address().port
66+
});
67+
68+
req.end();
69+
70+
req.on('response', common.mustCall((res) => {
71+
assert.strictEqual(res.statusCode, 200);
72+
assert.strictEqual(res.headers['content-type'], 'application/json');
73+
resolve();
74+
75+
let data = '';
76+
res.setEncoding('utf8');
77+
res.on('data', common.mustCall((chunk) => {
78+
data += chunk;
79+
}));
80+
81+
req.on('close', common.mustCall(() => {
82+
assert.strictEqual(data, '{');
83+
}));
84+
}));
85+
}));
86+
}
87+
88+
{
89+
const server = createServer(common.mustCall(async (req, res) => {
90+
// We will test that this header is cleaned up before forwarding.
91+
res.writeHead(200);
92+
throw new Error('kaboom');
93+
}));
94+
95+
server.listen(0, common.mustCall(() => {
96+
const req = request({
97+
method: 'GET',
98+
host: server.address().host,
99+
port: server.address().port
100+
});
101+
102+
req.end();
103+
104+
req.on('error', common.mustCall((err) => {
105+
assert.strictEqual(err.code, 'ECONNRESET');
106+
server.close();
107+
}));
108+
}));
109+
}

0 commit comments

Comments
 (0)