mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Protect against transfer.abort() being called during callback
This was already handled in most cases, but not for a body-less response. It's safe to call transfer.abort() during a callback, so long as the performing flag is set to true. This was set during the normal libcurl callbacks, but for a body-less response, we manually invoke the header_done_callback and were not setting the performing flag.
This commit is contained in:
@@ -252,3 +252,34 @@
|
|||||||
testing.expectEqual(XMLHttpRequest.UNSENT, req.readyState);
|
testing.expectEqual(XMLHttpRequest.UNSENT, req.readyState);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script id=xhr_abort_callback_nobody>
|
||||||
|
testing.async(async (restore) => {
|
||||||
|
const req = new XMLHttpRequest();
|
||||||
|
let abortFired = false;
|
||||||
|
let errorFired = false;
|
||||||
|
let loadEndFired = false;
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
req.onabort = () => { abortFired = true; };
|
||||||
|
req.onerror = () => { errorFired = true; };
|
||||||
|
req.onloadend = () => {
|
||||||
|
loadEndFired = true;
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
req.open('GET', 'http://127.0.0.1:9582/xhr_empty');
|
||||||
|
req.onreadystatechange = (e) => {
|
||||||
|
req.abort();
|
||||||
|
}
|
||||||
|
req.send();
|
||||||
|
});
|
||||||
|
|
||||||
|
restore();
|
||||||
|
testing.expectEqual(true, abortFired);
|
||||||
|
testing.expectEqual(true, errorFired);
|
||||||
|
testing.expectEqual(true, loadEndFired);
|
||||||
|
testing.expectEqual(XMLHttpRequest.UNSENT, req.readyState);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -789,25 +789,30 @@ fn processMessages(self: *Client) !bool {
|
|||||||
if (msg.err) |err| {
|
if (msg.err) |err| {
|
||||||
requestFailed(transfer, err, true);
|
requestFailed(transfer, err, true);
|
||||||
} else blk: {
|
} else blk: {
|
||||||
// In case of request w/o data, we need to call the header done
|
{
|
||||||
// callback now.
|
self.handles.performing = true;
|
||||||
if (!transfer._header_done_called) {
|
defer self.handles.performing = false;
|
||||||
const proceed = transfer.headerDoneCallback(&msg.conn) catch |err| {
|
|
||||||
log.err(.http, "header_done_callback", .{ .err = err });
|
// In case of request w/o data, we need to call the header done
|
||||||
|
// callback now.
|
||||||
|
if (!transfer._header_done_called) {
|
||||||
|
const proceed = transfer.headerDoneCallback(&msg.conn) catch |err| {
|
||||||
|
log.err(.http, "header_done_callback", .{ .err = err });
|
||||||
|
requestFailed(transfer, err, true);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if (!proceed) {
|
||||||
|
requestFailed(transfer, error.Abort, true);
|
||||||
|
break :blk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transfer.req.done_callback(transfer.ctx) catch |err| {
|
||||||
|
// transfer isn't valid at this point, don't use it.
|
||||||
|
log.err(.http, "done_callback", .{ .err = err });
|
||||||
requestFailed(transfer, err, true);
|
requestFailed(transfer, err, true);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if (!proceed) {
|
|
||||||
requestFailed(transfer, error.Abort, true);
|
|
||||||
break :blk;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
transfer.req.done_callback(transfer.ctx) catch |err| {
|
|
||||||
// transfer isn't valid at this point, don't use it.
|
|
||||||
log.err(.http, "done_callback", .{ .err = err });
|
|
||||||
requestFailed(transfer, err, true);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
transfer.req.notification.dispatch(.http_request_done, &.{
|
transfer.req.notification.dispatch(.http_request_done, &.{
|
||||||
.transfer = transfer,
|
.transfer = transfer,
|
||||||
@@ -1041,10 +1046,6 @@ pub const Transfer = struct {
|
|||||||
|
|
||||||
pub fn abort(self: *Transfer, err: anyerror) void {
|
pub fn abort(self: *Transfer, err: anyerror) void {
|
||||||
requestFailed(self, err, true);
|
requestFailed(self, err, true);
|
||||||
if (self._conn == null) {
|
|
||||||
self.deinit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = self.client;
|
const client = self.client;
|
||||||
if (client.handles.performing) {
|
if (client.handles.performing) {
|
||||||
|
|||||||
@@ -561,6 +561,14 @@ fn testHTTPHandler(req: *std.http.Server.Request) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, path, "/xhr_empty")) {
|
||||||
|
return req.respond("", .{
|
||||||
|
.extra_headers = &.{
|
||||||
|
.{ .name = "Content-Type", .value = "text/html; charset=utf-8" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, path, "/xhr/json")) {
|
if (std.mem.eql(u8, path, "/xhr/json")) {
|
||||||
return req.respond("{\"over\":\"9000!!!\",\"updated_at\":1765867200000}", .{
|
return req.respond("{\"over\":\"9000!!!\",\"updated_at\":1765867200000}", .{
|
||||||
.extra_headers = &.{
|
.extra_headers = &.{
|
||||||
|
|||||||
Reference in New Issue
Block a user