aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ciro Spaciari <ciro.spaciari@gmail.com> 2023-09-16 21:55:41 -0700
committerGravatar GitHub <noreply@github.com> 2023-09-16 21:55:41 -0700
commit383d5b55d611b62492178eae4833bf3c134de246 (patch)
tree2abd5a03b05939c4c5f80608e5a0a0b5250e9146
parent80e1f32ca1236dcf6f7ed559c596afbced0f8f3a (diff)
downloadbun-383d5b55d611b62492178eae4833bf3c134de246.tar.gz
bun-383d5b55d611b62492178eae4833bf3c134de246.tar.zst
bun-383d5b55d611b62492178eae4833bf3c134de246.zip
fix(fetch) handle 100 continue (#5496)
* handle 100 continue * move comment * cleanup * fmt
-rw-r--r--src/http_client_async.zig10
-rw-r--r--test/js/web/fetch/fetch.test.ts60
2 files changed, 69 insertions, 1 deletions
diff --git a/src/http_client_async.zig b/src/http_client_async.zig
index 79fe74899..b3c06df56 100644
--- a/src/http_client_async.zig
+++ b/src/http_client_async.zig
@@ -2637,6 +2637,14 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u
this.state.pending_response = response;
var body_buf = to_read[@min(@as(usize, @intCast(response.bytes_read)), to_read.len)..];
+ // handle the case where we have a 100 Continue
+ if (response.status_code == 100) {
+ // we still can have the 200 OK in the same buffer sometimes
+ if (body_buf.len > 0) {
+ this.onData(is_ssl, body_buf, ctx, socket);
+ }
+ return;
+ }
var deferred_redirect: ?*URLBufferPool.Node = null;
const can_continue = this.handleResponseMetadata(
@@ -3399,6 +3407,7 @@ pub fn handleResponseMetadata(
this.proxy_tunneling = false;
}
+ // if is no redirect or if is redirect == "manual" just proceed
const is_redirect = response.status_code >= 300 and response.status_code <= 399;
if (is_redirect) {
if (this.redirect_type == FetchRedirect.follow and location.len > 0 and this.remaining_redirect_count > 0) {
@@ -3513,7 +3522,6 @@ pub fn handleResponseMetadata(
}
}
- // if is no redirect or if is redirect == "manual" just proceed
this.state.response_stage = if (this.state.transfer_encoding == .chunked) .body_chunk else .body;
const content_length = this.state.content_length orelse 0;
// if no body is expected we should stop processing
diff --git a/test/js/web/fetch/fetch.test.ts b/test/js/web/fetch/fetch.test.ts
index 4ef5d7bba..fc4ce7a18 100644
--- a/test/js/web/fetch/fetch.test.ts
+++ b/test/js/web/fetch/fetch.test.ts
@@ -5,6 +5,7 @@ import { mkfifo } from "mkfifo";
import { tmpdir } from "os";
import { join } from "path";
import { gc, withoutAggressiveGC, gcTick } from "harness";
+import net from "net";
const tmp_dir = mkdtempSync(join(realpathSync(tmpdir()), "fetch.test"));
@@ -1415,3 +1416,62 @@ it("cloned response headers are independent after accessing", () => {
cloned.headers.set("content-type", "text/plain");
expect(response.headers.get("content-type")).toBe("text/html; charset=utf-8");
});
+
+it("should work with http 100 continue", async () => {
+ let server: net.Server | undefined;
+ try {
+ server = net.createServer(socket => {
+ socket.on("data", data => {
+ const lines = data.toString().split("\r\n");
+ for (const line of lines) {
+ if (line.length == 0) {
+ socket.write("HTTP/1.1 100 Continue\r\n\r\n");
+ socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\nHello, World!");
+ break;
+ }
+ }
+ });
+ });
+
+ const { promise: start, resolve } = Promise.withResolvers();
+ server.listen(8080, resolve);
+
+ await start;
+
+ const address = server.address() as net.AddressInfo;
+ const result = await fetch(`http://localhost:${address.port}`).then(r => r.text());
+ expect(result).toBe("Hello, World!");
+ } finally {
+ server?.close();
+ }
+});
+
+it("should work with http 100 continue on the same buffer", async () => {
+ let server: net.Server | undefined;
+ try {
+ server = net.createServer(socket => {
+ socket.on("data", data => {
+ const lines = data.toString().split("\r\n");
+ for (const line of lines) {
+ if (line.length == 0) {
+ socket.write(
+ "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\nHello, World!",
+ );
+ break;
+ }
+ }
+ });
+ });
+
+ const { promise: start, resolve } = Promise.withResolvers();
+ server.listen(8080, resolve);
+
+ await start;
+
+ const address = server.address() as net.AddressInfo;
+ const result = await fetch(`http://localhost:${address.port}`).then(r => r.text());
+ expect(result).toBe("Hello, World!");
+ } finally {
+ server?.close();
+ }
+});