aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/http/Client.zig105
1 files changed, 38 insertions, 67 deletions
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
index 8a4a771416..b6be5cee10 100644
--- a/lib/std/http/Client.zig
+++ b/lib/std/http/Client.zig
@@ -9,9 +9,8 @@ const net = std.net;
const Client = @This();
const Url = std.Url;
+/// TODO: remove this field (currently required due to tcpConnectToHost)
allocator: std.mem.Allocator,
-headers: std.ArrayListUnmanaged(u8) = .{},
-active_requests: usize = 0,
ca_bundle: std.crypto.Certificate.Bundle = .{},
/// TODO: emit error.UnexpectedEndOfStream or something like that when the read
@@ -20,44 +19,23 @@ ca_bundle: std.crypto.Certificate.Bundle = .{},
pub const Request = struct {
client: *Client,
stream: net.Stream,
- headers: std.ArrayListUnmanaged(u8) = .{},
tls_client: std.crypto.tls.Client,
protocol: Protocol,
response_headers: http.Headers = .{},
- pub const Protocol = enum { http, https };
-
- pub const Options = struct {
+ pub const Headers = struct {
method: http.Method = .GET,
- };
+ connection: Connection,
- pub fn deinit(req: *Request) void {
- req.client.active_requests -= 1;
- req.headers.deinit(req.client.allocator);
- req.* = undefined;
- }
+ pub const Connection = enum {
+ close,
+ @"keep-alive",
+ };
+ };
- pub fn addHeader(req: *Request, name: []const u8, value: []const u8) !void {
- const gpa = req.client.allocator;
- // Ensure an extra +2 for the \r\n in end()
- try req.headers.ensureUnusedCapacity(gpa, name.len + value.len + 6);
- req.headers.appendSliceAssumeCapacity(name);
- req.headers.appendSliceAssumeCapacity(": ");
- req.headers.appendSliceAssumeCapacity(value);
- req.headers.appendSliceAssumeCapacity("\r\n");
- }
+ pub const Protocol = enum { http, https };
- pub fn end(req: *Request) !void {
- req.headers.appendSliceAssumeCapacity("\r\n");
- switch (req.protocol) {
- .http => {
- try req.stream.writeAll(req.headers.items);
- },
- .https => {
- try req.tls_client.writeAll(req.stream, req.headers.items);
- },
- }
- }
+ pub const Options = struct {};
pub fn readAll(req: *Request, buffer: []u8) !usize {
return readAtLeast(req, buffer, buffer.len);
@@ -113,13 +91,14 @@ pub const Request = struct {
}
};
-pub fn deinit(client: *Client) void {
- assert(client.active_requests == 0);
- client.headers.deinit(client.allocator);
+pub fn deinit(client: *Client, gpa: std.mem.Allocator) void {
+ client.ca_bundle.deinit(gpa);
client.* = undefined;
}
-pub fn request(client: *Client, url: Url, options: Request.Options) !Request {
+pub fn request(client: *Client, url: Url, headers: Request.Headers, options: Request.Options) !Request {
+ _ = options; // we have no options yet
+
const protocol = std.meta.stringToEnum(Request.Protocol, url.scheme) orelse
return error.UnsupportedUrlScheme;
const port: u16 = url.port orelse switch (protocol) {
@@ -133,8 +112,6 @@ pub fn request(client: *Client, url: Url, options: Request.Options) !Request {
.protocol = protocol,
.tls_client = undefined,
};
- client.active_requests += 1;
- errdefer req.deinit();
switch (protocol) {
.http => {},
@@ -146,36 +123,30 @@ pub fn request(client: *Client, url: Url, options: Request.Options) !Request {
},
}
- try req.headers.ensureUnusedCapacity(
- client.allocator,
- @tagName(options.method).len +
- 1 +
- url.path.len +
- " HTTP/1.1\r\nHost: ".len +
- url.host.len +
- "\r\nUpgrade-Insecure-Requests: 1\r\n".len +
- client.headers.items.len +
- 2, // for the \r\n at the end of headers
- );
- req.headers.appendSliceAssumeCapacity(@tagName(options.method));
- req.headers.appendSliceAssumeCapacity(" ");
- req.headers.appendSliceAssumeCapacity(url.path);
- req.headers.appendSliceAssumeCapacity(" HTTP/1.1\r\nHost: ");
- req.headers.appendSliceAssumeCapacity(url.host);
- switch (protocol) {
- .https => req.headers.appendSliceAssumeCapacity("\r\nUpgrade-Insecure-Requests: 1\r\n"),
- .http => req.headers.appendSliceAssumeCapacity("\r\n"),
+ {
+ var h = try std.BoundedArray(u8, 1000).init(0);
+ try h.appendSlice(@tagName(headers.method));
+ try h.appendSlice(" ");
+ try h.appendSlice(url.path);
+ try h.appendSlice(" HTTP/1.1\r\nHost: ");
+ try h.appendSlice(url.host);
+ switch (protocol) {
+ .https => try h.appendSlice("\r\nUpgrade-Insecure-Requests: 1\r\n"),
+ .http => try h.appendSlice("\r\n"),
+ }
+ try h.writer().print("Connection: {s}\r\n", .{@tagName(headers.connection)});
+ try h.appendSlice("\r\n");
+
+ const header_bytes = h.slice();
+ switch (req.protocol) {
+ .http => {
+ try req.stream.writeAll(header_bytes);
+ },
+ .https => {
+ try req.tls_client.writeAll(req.stream, header_bytes);
+ },
+ }
}
- req.headers.appendSliceAssumeCapacity(client.headers.items);
return req;
}
-
-pub fn addHeader(client: *Client, name: []const u8, value: []const u8) !void {
- const gpa = client.allocator;
- try client.headers.ensureUnusedCapacity(gpa, name.len + value.len + 4);
- client.headers.appendSliceAssumeCapacity(name);
- client.headers.appendSliceAssumeCapacity(": ");
- client.headers.appendSliceAssumeCapacity(value);
- client.headers.appendSliceAssumeCapacity("\r\n");
-}