diff --git a/src/browser/tests/net/xhr.html b/src/browser/tests/net/xhr.html
index b7132f6e..61cfb1ee 100644
--- a/src/browser/tests/net/xhr.html
+++ b/src/browser/tests/net/xhr.html
@@ -222,3 +222,34 @@
testing.expectEqual(XMLHttpRequest.UNSENT, req.readyState);
});
+
+
+ -->
diff --git a/src/http/Client.zig b/src/http/Client.zig
index 3cce2ddb..4072b548 100644
--- a/src/http/Client.zig
+++ b/src/http/Client.zig
@@ -1092,6 +1092,8 @@ pub const Transfer = struct {
// the headers, and the [encoded] body.
bytes_received: usize = 0,
+ aborted: bool = false,
+
max_response_size: ?usize = null,
// We'll store the response header here
@@ -1224,10 +1226,18 @@ pub const Transfer = struct {
pub fn abort(self: *Transfer, err: anyerror) void {
requestFailed(self, err, true);
- if (self._handle != null) {
- self.client.endTransfer(self);
+ if (self._handle == null) {
+ self.deinit();
+ return;
}
- self.deinit();
+
+ // abort can be called from a libcurl callback, e.g. we get data, we
+ // do the header done callback, the client aborts.
+ // libcurl doesn't support re-entrant calls. We can't remove the
+ // handle from the multi during a callback. Instead, we flag this as
+ // aborted, which will signal the callbacks to stop processing the
+ // transfer
+ self.aborted = true;
}
pub fn terminate(self: *Transfer) void {
@@ -1359,7 +1369,7 @@ pub const Transfer = struct {
.transfer = transfer,
});
- return proceed;
+ return proceed and transfer.aborted == false;
}
// headerCallback is called by curl on each request's header line read.
@@ -1519,6 +1529,10 @@ pub const Transfer = struct {
.transfer = transfer,
});
+ if (transfer.aborted) {
+ return -1;
+ }
+
return @intCast(chunk_len);
}