aboutsummaryrefslogtreecommitdiff
path: root/lib/std/http/Server
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-02-18 20:22:09 -0700
committerAndrew Kelley <andrew@ziglang.org>2024-02-23 02:37:11 -0700
commit6129ecd4fe88e14531db98866c92c4a5660849ee (patch)
treeca8c76c12cbce56e8038bfecaae3590ae037487e /lib/std/http/Server
parentf1565e3d09f4c8a0d5c55a635a7e7f9925eae20f (diff)
downloadzig-6129ecd4fe88e14531db98866c92c4a5660849ee.tar.gz
zig-6129ecd4fe88e14531db98866c92c4a5660849ee.zip
std.net, std.http: simplify
Diffstat (limited to 'lib/std/http/Server')
-rw-r--r--lib/std/http/Server/Connection.zig132
1 files changed, 132 insertions, 0 deletions
diff --git a/lib/std/http/Server/Connection.zig b/lib/std/http/Server/Connection.zig
new file mode 100644
index 0000000000..52b870992a
--- /dev/null
+++ b/lib/std/http/Server/Connection.zig
@@ -0,0 +1,132 @@
+stream: std.net.Stream,
+protocol: Protocol,
+
+closing: bool,
+
+read_buf: [buffer_size]u8,
+read_start: u16,
+read_end: u16,
+
+pub const buffer_size = std.crypto.tls.max_ciphertext_record_len;
+pub const Protocol = enum { plain };
+
+pub fn rawReadAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize {
+ return switch (conn.protocol) {
+ .plain => conn.stream.readAtLeast(buffer, len),
+ // .tls => conn.tls_client.readAtLeast(conn.stream, buffer, len),
+ } catch |err| {
+ switch (err) {
+ error.ConnectionResetByPeer, error.BrokenPipe => return error.ConnectionResetByPeer,
+ else => return error.UnexpectedReadFailure,
+ }
+ };
+}
+
+pub fn fill(conn: *Connection) ReadError!void {
+ if (conn.read_end != conn.read_start) return;
+
+ const nread = try conn.rawReadAtLeast(conn.read_buf[0..], 1);
+ if (nread == 0) return error.EndOfStream;
+ conn.read_start = 0;
+ conn.read_end = @intCast(nread);
+}
+
+pub fn peek(conn: *Connection) []const u8 {
+ return conn.read_buf[conn.read_start..conn.read_end];
+}
+
+pub fn drop(conn: *Connection, num: u16) void {
+ conn.read_start += num;
+}
+
+pub fn readAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize {
+ assert(len <= buffer.len);
+
+ var out_index: u16 = 0;
+ while (out_index < len) {
+ const available_read = conn.read_end - conn.read_start;
+ const available_buffer = buffer.len - out_index;
+
+ if (available_read > available_buffer) { // partially read buffered data
+ @memcpy(buffer[out_index..], conn.read_buf[conn.read_start..conn.read_end][0..available_buffer]);
+ out_index += @as(u16, @intCast(available_buffer));
+ conn.read_start += @as(u16, @intCast(available_buffer));
+
+ break;
+ } else if (available_read > 0) { // fully read buffered data
+ @memcpy(buffer[out_index..][0..available_read], conn.read_buf[conn.read_start..conn.read_end]);
+ out_index += available_read;
+ conn.read_start += available_read;
+
+ if (out_index >= len) break;
+ }
+
+ const leftover_buffer = available_buffer - available_read;
+ const leftover_len = len - out_index;
+
+ if (leftover_buffer > conn.read_buf.len) {
+ // skip the buffer if the output is large enough
+ return conn.rawReadAtLeast(buffer[out_index..], leftover_len);
+ }
+
+ try conn.fill();
+ }
+
+ return out_index;
+}
+
+pub fn read(conn: *Connection, buffer: []u8) ReadError!usize {
+ return conn.readAtLeast(buffer, 1);
+}
+
+pub const ReadError = error{
+ ConnectionTimedOut,
+ ConnectionResetByPeer,
+ UnexpectedReadFailure,
+ EndOfStream,
+};
+
+pub const Reader = std.io.Reader(*Connection, ReadError, read);
+
+pub fn reader(conn: *Connection) Reader {
+ return .{ .context = conn };
+}
+
+pub fn writeAll(conn: *Connection, buffer: []const u8) WriteError!void {
+ return switch (conn.protocol) {
+ .plain => conn.stream.writeAll(buffer),
+ // .tls => return conn.tls_client.writeAll(conn.stream, buffer),
+ } catch |err| switch (err) {
+ error.BrokenPipe, error.ConnectionResetByPeer => return error.ConnectionResetByPeer,
+ else => return error.UnexpectedWriteFailure,
+ };
+}
+
+pub fn write(conn: *Connection, buffer: []const u8) WriteError!usize {
+ return switch (conn.protocol) {
+ .plain => conn.stream.write(buffer),
+ // .tls => return conn.tls_client.write(conn.stream, buffer),
+ } catch |err| switch (err) {
+ error.BrokenPipe, error.ConnectionResetByPeer => return error.ConnectionResetByPeer,
+ else => return error.UnexpectedWriteFailure,
+ };
+}
+
+pub const WriteError = error{
+ ConnectionResetByPeer,
+ UnexpectedWriteFailure,
+};
+
+pub const Writer = std.io.Writer(*Connection, WriteError, write);
+
+pub fn writer(conn: *Connection) Writer {
+ return .{ .context = conn };
+}
+
+pub fn close(conn: *Connection) void {
+ conn.stream.close();
+}
+
+const Connection = @This();
+const std = @import("../../std.zig");
+const assert = std.debug.assert;