aboutsummaryrefslogtreecommitdiff
path: root/lib/std/http
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2024-02-26 17:04:28 +0100
committerAndrew Kelley <andrew@ziglang.org>2024-02-26 20:11:43 -0800
commit4e2570baafb587c679ee0fc5e113ddeb36522a5d (patch)
treee74f607290693900c9e863d427e9a78ee5f03826 /lib/std/http
parent8775d8bbcef347640c6ae7e73da02ca6eff1d669 (diff)
downloadzig-4e2570baafb587c679ee0fc5e113ddeb36522a5d.tar.gz
zig-4e2570baafb587c679ee0fc5e113ddeb36522a5d.zip
http: fix fetching a github release
* Support different keep alive defaults with different http versions. * Fix incorrect usage of `copyBackwards`, which copies in a backwards direction allowing data to be moved forward in a buffer, not backwards in a buffer.
Diffstat (limited to 'lib/std/http')
-rw-r--r--lib/std/http/Client.zig12
-rw-r--r--lib/std/http/Server.zig24
-rw-r--r--lib/std/http/test.zig21
3 files changed, 31 insertions, 26 deletions
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
index 1ffe1e8ea3..49843fb405 100644
--- a/lib/std/http/Client.zig
+++ b/lib/std/http/Client.zig
@@ -430,7 +430,7 @@ pub const Response = struct {
/// Points into the user-provided `server_header_buffer`.
content_disposition: ?[]const u8 = null,
- keep_alive: bool = false,
+ keep_alive: bool,
/// If present, the number of bytes in the response body.
content_length: ?u64 = null,
@@ -477,6 +477,10 @@ pub const Response = struct {
res.version = version;
res.status = status;
res.reason = reason;
+ res.keep_alive = switch (version) {
+ .@"HTTP/1.0" => false,
+ .@"HTTP/1.1" => true,
+ };
while (it.next()) |line| {
if (line.len == 0) return;
@@ -684,9 +688,10 @@ pub const Request = struct {
req.response.parser.reset();
req.response = .{
+ .version = undefined,
.status = undefined,
.reason = undefined,
- .version = undefined,
+ .keep_alive = undefined,
.parser = req.response.parser,
};
}
@@ -1564,9 +1569,10 @@ pub fn open(
.redirect_behavior = options.redirect_behavior,
.handle_continue = options.handle_continue,
.response = .{
+ .version = undefined,
.status = undefined,
.reason = undefined,
- .version = undefined,
+ .keep_alive = undefined,
.parser = proto.HeadersParser.init(options.server_header_buffer),
},
.headers = options.headers,
diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig
index a2e3a8060c..bfc97157f6 100644
--- a/lib/std/http/Server.zig
+++ b/lib/std/http/Server.zig
@@ -25,7 +25,7 @@ pub const State = enum {
/// The client is uploading something to this Server.
receiving_body,
/// The connection is eligible for another HTTP request, however the client
- /// and server did not negotiate connection: keep-alive.
+ /// and server did not negotiate a persistent connection.
closing,
};
@@ -197,7 +197,10 @@ pub const Request = struct {
.content_length = null,
.transfer_encoding = .none,
.transfer_compression = .identity,
- .keep_alive = false,
+ .keep_alive = switch (version) {
+ .@"HTTP/1.0" => false,
+ .@"HTTP/1.1" => true,
+ },
.compression = .none,
};
@@ -330,7 +333,7 @@ pub const Request = struct {
// reader() and hence discardBody() above sets expect to null if it
// is handled. So the fact that it is not null here means unhandled.
h.appendSliceAssumeCapacity("HTTP/1.1 417 Expectation Failed\r\n");
- if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n");
+ if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n");
h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");
try request.server.connection.stream.writeAll(h.items);
return;
@@ -339,7 +342,10 @@ pub const Request = struct {
@tagName(options.version), @intFromEnum(options.status), phrase,
}) catch unreachable;
- if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n");
+ switch (options.version) {
+ .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
+ .@"HTTP/1.1" => if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n"),
+ }
if (options.transfer_encoding) |transfer_encoding| switch (transfer_encoding) {
.none => {},
@@ -480,14 +486,18 @@ pub const Request = struct {
// reader() and hence discardBody() above sets expect to null if it
// is handled. So the fact that it is not null here means unhandled.
h.appendSliceAssumeCapacity("HTTP/1.1 417 Expectation Failed\r\n");
- if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n");
+ if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n");
h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");
break :eb true;
} else eb: {
h.fixedWriter().print("{s} {d} {s}\r\n", .{
@tagName(o.version), @intFromEnum(o.status), phrase,
}) catch unreachable;
- if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n");
+
+ switch (o.version) {
+ .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
+ .@"HTTP/1.1" => if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n"),
+ }
if (o.transfer_encoding) |transfer_encoding| switch (transfer_encoding) {
.chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
@@ -694,7 +704,7 @@ pub const Request = struct {
}
}
- /// Returns whether the connection: keep-alive header should be sent to the client.
+ /// Returns whether the connection should remain persistent.
/// If it would fail, it instead sets the Server state to `receiving_body`
/// and returns false.
fn discardBody(request: *Request, keep_alive: bool) bool {
diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig
index ff0dfe6634..15e7542d19 100644
--- a/lib/std/http/test.zig
+++ b/lib/std/http/test.zig
@@ -76,12 +76,6 @@ test "trailers" {
{
const header = it.next().?;
try expect(!it.is_trailer);
- try expectEqualStrings("connection", header.name);
- try expectEqualStrings("keep-alive", header.value);
- }
- {
- const header = it.next().?;
- try expect(!it.is_trailer);
try expectEqualStrings("transfer-encoding", header.name);
try expectEqualStrings("chunked", header.value);
}
@@ -143,15 +137,15 @@ test "HTTP server handles a chunked transfer coding request" {
defer stream.close();
try stream.writeAll(request_bytes);
- const response = try stream.reader().readAllAlloc(gpa, 100);
- defer gpa.free(response);
-
const expected_response =
"HTTP/1.1 200 OK\r\n" ++
+ "connection: close\r\n" ++
"content-length: 21\r\n" ++
"content-type: text/plain\r\n" ++
"\r\n" ++
"message from server!\n";
+ const response = try stream.reader().readAllAlloc(gpa, expected_response.len);
+ defer gpa.free(response);
try expectEqualStrings(expected_response, response);
}
@@ -285,7 +279,7 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" {
var expected_response = std.ArrayList(u8).init(gpa);
defer expected_response.deinit();
- try expected_response.appendSlice("HTTP/1.1 200 OK\r\n\r\n");
+ try expected_response.appendSlice("HTTP/1.1 200 OK\r\nconnection: close\r\n\r\n");
{
var total: usize = 0;
@@ -349,6 +343,7 @@ test "receiving arbitrary http headers from the client" {
defer expected_response.deinit();
try expected_response.appendSlice("HTTP/1.1 200 OK\r\n");
+ try expected_response.appendSlice("connection: close\r\n");
try expected_response.appendSlice("content-length: 0\r\n\r\n");
try expectEqualStrings(expected_response.items, response);
}
@@ -703,12 +698,6 @@ test "general client/server API coverage" {
{
const header = it.next().?;
try expect(!it.is_trailer);
- try expectEqualStrings("connection", header.name);
- try expectEqualStrings("keep-alive", header.value);
- }
- {
- const header = it.next().?;
- try expect(!it.is_trailer);
try expectEqualStrings("content-length", header.name);
try expectEqualStrings("0", header.value);
}