authorgravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-05-01 12:13:33-05:00
committergravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-05-06 21:35:16-05:00
log7b0962938859a955fa8e057ef34f4abd925bb1ca
tree4e9a27685b5512241f62c8283ddd7f0226a4e63d
parent533049fdd80a4c7bc3098512b4033a60daea745e
signaturelock-open Commit is signed but in an unrecognized format.

std.http: buffer writes


2 files changed, 88 insertions(+), 36 deletions(-)

lib/std/http/Client.zig+44-18
...@@ -254,44 +254,47 @@ pub const BufferedConnection = struct {...@@ -254,44 +254,47 @@ pub const BufferedConnection = struct {
254 pub const buffer_size = 0x2000;254 pub const buffer_size = 0x2000;
255255
256 conn: Connection,256 conn: Connection,
257 buf: [buffer_size]u8 = undefined,257 read_buf: [buffer_size]u8 = undefined,
258 start: u16 = 0,258 read_start: u16 = 0,
259 end: u16 = 0,259 read_end: u16 = 0,
260
261 write_buf: [buffer_size]u8 = undefined,
262 write_end: u16 = 0,
260263
261 pub fn fill(bconn: *BufferedConnection) ReadError!void {264 pub fn fill(bconn: *BufferedConnection) ReadError!void {
262 if (bconn.end != bconn.start) return;265 if (bconn.read_end != bconn.read_start) return;
263266
264 const nread = try bconn.conn.read(bconn.buf[0..]);267 const nread = try bconn.conn.read(bconn.read_buf[0..]);
265 if (nread == 0) return error.EndOfStream;268 if (nread == 0) return error.EndOfStream;
266 bconn.start = 0;269 bconn.read_start = 0;
267 bconn.end = @intCast(u16, nread);270 bconn.read_end = @intCast(u16, nread);
268 }271 }
269272
270 pub fn peek(bconn: *BufferedConnection) []const u8 {273 pub fn peek(bconn: *BufferedConnection) []const u8 {
271 return bconn.buf[bconn.start..bconn.end];274 return bconn.read_buf[bconn.read_start..bconn.read_end];
272 }275 }
273276
274 pub fn clear(bconn: *BufferedConnection, num: u16) void {277 pub fn clear(bconn: *BufferedConnection, num: u16) void {
275 bconn.start += num;278 bconn.read_start += num;
276 }279 }
277280
278 pub fn readAtLeast(bconn: *BufferedConnection, buffer: []u8, len: usize) ReadError!usize {281 pub fn readAtLeast(bconn: *BufferedConnection, buffer: []u8, len: usize) ReadError!usize {
279 var out_index: u16 = 0;282 var out_index: u16 = 0;
280 while (out_index < len) {283 while (out_index < len) {
281 const available = bconn.end - bconn.start;284 const available = bconn.read_end - bconn.read_start;
282 const left = buffer.len - out_index;285 const left = buffer.len - out_index;
283286
284 if (available > 0) {287 if (available > 0) {
285 const can_read = @intCast(u16, @min(available, left));288 const can_read = @intCast(u16, @min(available, left));
286289
287 @memcpy(buffer[out_index..][0..can_read], bconn.buf[bconn.start..][0..can_read]);290 @memcpy(buffer[out_index..][0..can_read], bconn.read_buf[bconn.read_start..][0..can_read]);
288 out_index += can_read;291 out_index += can_read;
289 bconn.start += can_read;292 bconn.read_start += can_read;
290293
291 continue;294 continue;
292 }295 }
293296
294 if (left > bconn.buf.len) {297 if (left > bconn.read_buf.len) {
295 // skip the buffer if the output is large enough298 // skip the buffer if the output is large enough
296 return bconn.conn.read(buffer[out_index..]);299 return bconn.conn.read(buffer[out_index..]);
297 }300 }
...@@ -314,11 +317,33 @@ pub const BufferedConnection = struct {...@@ -314,11 +317,33 @@ pub const BufferedConnection = struct {
314 }317 }
315318
316 pub fn writeAll(bconn: *BufferedConnection, buffer: []const u8) WriteError!void {319 pub fn writeAll(bconn: *BufferedConnection, buffer: []const u8) WriteError!void {
317 return bconn.conn.writeAll(buffer);320 if (bconn.write_buf.len - bconn.write_end <= buffer.len) {
321 @memcpy(bconn.write_buf[bconn.write_end..], buffer);
322 bconn.write_end += @intCast(u16, buffer.len);
323 } else {
324 try bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
325 bconn.write_end = 0;
326
327 try bconn.conn.writeAll(buffer);
328 }
318 }329 }
319330
320 pub fn write(bconn: *BufferedConnection, buffer: []const u8) WriteError!usize {331 pub fn write(bconn: *BufferedConnection, buffer: []const u8) WriteError!usize {
321 return bconn.conn.write(buffer);332 if (bconn.write_buf.len - bconn.write_end <= buffer.len) {
333 @memcpy(bconn.write_buf[bconn.write_end..], buffer);
334 bconn.write_end += @intCast(u16, buffer.len);
335
336 return buffer.len;
337 } else {
338 try bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
339 bconn.write_end = 0;
340
341 return try bconn.conn.write(buffer);
342 }
343 }
344
345 pub fn flush(bconn: *BufferedConnection) WriteError!void {
346 return bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
322 }347 }
323348
324 pub const WriteError = Connection.WriteError;349 pub const WriteError = Connection.WriteError;
...@@ -567,8 +592,7 @@ pub const Request = struct {...@@ -567,8 +592,7 @@ pub const Request = struct {
567592
568 /// Send the request to the server.593 /// Send the request to the server.
569 pub fn start(req: *Request) StartError!void {594 pub fn start(req: *Request) StartError!void {
570 var buffered = std.io.bufferedWriter(req.connection.data.buffered.writer());595 const w = req.connection.data.buffered.writer();
571 const w = buffered.writer();
572596
573 try w.writeAll(@tagName(req.method));597 try w.writeAll(@tagName(req.method));
574 try w.writeByte(' ');598 try w.writeByte(' ');
...@@ -642,7 +666,7 @@ pub const Request = struct {...@@ -642,7 +666,7 @@ pub const Request = struct {
642666
643 try w.writeAll("\r\n");667 try w.writeAll("\r\n");
644668
645 try buffered.flush();669 try req.connection.data.buffered.flush();
646 }670 }
647671
648 pub const TransferReadError = BufferedConnection.ReadError || proto.HeadersParser.ReadError;672 pub const TransferReadError = BufferedConnection.ReadError || proto.HeadersParser.ReadError;
...@@ -868,6 +892,8 @@ pub const Request = struct {...@@ -868,6 +892,8 @@ pub const Request = struct {
868 .content_length => |len| if (len != 0) return error.MessageNotCompleted,892 .content_length => |len| if (len != 0) return error.MessageNotCompleted,
869 .none => {},893 .none => {},
870 }894 }
895
896 try req.connection.data.buffered.flush();
871 }897 }
872};898};
873899
lib/std/http/Server.zig+44-18
...@@ -98,44 +98,47 @@ pub const BufferedConnection = struct {...@@ -98,44 +98,47 @@ pub const BufferedConnection = struct {
98 pub const buffer_size = 0x2000;98 pub const buffer_size = 0x2000;
9999
100 conn: Connection,100 conn: Connection,
101 buf: [buffer_size]u8 = undefined,101 read_buf: [buffer_size]u8 = undefined,
102 start: u16 = 0,102 read_start: u16 = 0,
103 end: u16 = 0,103 read_end: u16 = 0,
104
105 write_buf: [buffer_size]u8 = undefined,
106 write_end: u16 = 0,
104107
105 pub fn fill(bconn: *BufferedConnection) ReadError!void {108 pub fn fill(bconn: *BufferedConnection) ReadError!void {
106 if (bconn.end != bconn.start) return;109 if (bconn.read_end != bconn.read_start) return;
107110
108 const nread = try bconn.conn.read(bconn.buf[0..]);111 const nread = try bconn.conn.read(bconn.read_buf[0..]);
109 if (nread == 0) return error.EndOfStream;112 if (nread == 0) return error.EndOfStream;
110 bconn.start = 0;113 bconn.read_start = 0;
111 bconn.end = @intCast(u16, nread);114 bconn.read_end = @intCast(u16, nread);
112 }115 }
113116
114 pub fn peek(bconn: *BufferedConnection) []const u8 {117 pub fn peek(bconn: *BufferedConnection) []const u8 {
115 return bconn.buf[bconn.start..bconn.end];118 return bconn.read_buf[bconn.read_start..bconn.read_end];
116 }119 }
117120
118 pub fn clear(bconn: *BufferedConnection, num: u16) void {121 pub fn clear(bconn: *BufferedConnection, num: u16) void {
119 bconn.start += num;122 bconn.read_start += num;
120 }123 }
121124
122 pub fn readAtLeast(bconn: *BufferedConnection, buffer: []u8, len: usize) ReadError!usize {125 pub fn readAtLeast(bconn: *BufferedConnection, buffer: []u8, len: usize) ReadError!usize {
123 var out_index: u16 = 0;126 var out_index: u16 = 0;
124 while (out_index < len) {127 while (out_index < len) {
125 const available = bconn.end - bconn.start;128 const available = bconn.read_end - bconn.read_start;
126 const left = buffer.len - out_index;129 const left = buffer.len - out_index;
127130
128 if (available > 0) {131 if (available > 0) {
129 const can_read = @intCast(u16, @min(available, left));132 const can_read = @intCast(u16, @min(available, left));
130133
131 @memcpy(buffer[out_index..][0..can_read], bconn.buf[bconn.start..][0..can_read]);134 @memcpy(buffer[out_index..][0..can_read], bconn.read_buf[bconn.read_start..][0..can_read]);
132 out_index += can_read;135 out_index += can_read;
133 bconn.start += can_read;136 bconn.read_start += can_read;
134137
135 continue;138 continue;
136 }139 }
137140
138 if (left > bconn.buf.len) {141 if (left > bconn.read_buf.len) {
139 // skip the buffer if the output is large enough142 // skip the buffer if the output is large enough
140 return bconn.conn.read(buffer[out_index..]);143 return bconn.conn.read(buffer[out_index..]);
141 }144 }
...@@ -158,11 +161,33 @@ pub const BufferedConnection = struct {...@@ -158,11 +161,33 @@ pub const BufferedConnection = struct {
158 }161 }
159162
160 pub fn writeAll(bconn: *BufferedConnection, buffer: []const u8) WriteError!void {163 pub fn writeAll(bconn: *BufferedConnection, buffer: []const u8) WriteError!void {
161 return bconn.conn.writeAll(buffer);164 if (bconn.write_buf.len - bconn.write_end <= buffer.len) {
165 @memcpy(bconn.write_buf[bconn.write_end..], buffer);
166 bconn.write_end += @intCast(u16, buffer.len);
167 } else {
168 try bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
169 bconn.write_end = 0;
170
171 try bconn.conn.writeAll(buffer);
172 }
162 }173 }
163174
164 pub fn write(bconn: *BufferedConnection, buffer: []const u8) WriteError!usize {175 pub fn write(bconn: *BufferedConnection, buffer: []const u8) WriteError!usize {
165 return bconn.conn.write(buffer);176 if (bconn.write_buf.len - bconn.write_end <= buffer.len) {
177 @memcpy(bconn.write_buf[bconn.write_end..], buffer);
178 bconn.write_end += @intCast(u16, buffer.len);
179
180 return buffer.len;
181 } else {
182 try bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
183 bconn.write_end = 0;
184
185 return try bconn.conn.write(buffer);
186 }
187 }
188
189 pub fn flush(bconn: *BufferedConnection) WriteError!void {
190 return bconn.conn.writeAll(bconn.write_buf[0..bconn.write_end]);
166 }191 }
167192
168 pub const WriteError = Connection.WriteError;193 pub const WriteError = Connection.WriteError;
...@@ -426,8 +451,7 @@ pub const Response = struct {...@@ -426,8 +451,7 @@ pub const Response = struct {
426 .first, .start, .responded, .finished => unreachable,451 .first, .start, .responded, .finished => unreachable,
427 }452 }
428453
429 var buffered = std.io.bufferedWriter(res.connection.writer());454 const w = res.connection.writer();
430 const w = buffered.writer();
431455
432 try w.writeAll(@tagName(res.version));456 try w.writeAll(@tagName(res.version));
433 try w.writeByte(' ');457 try w.writeByte(' ');
...@@ -485,7 +509,7 @@ pub const Response = struct {...@@ -485,7 +509,7 @@ pub const Response = struct {
485509
486 try w.writeAll("\r\n");510 try w.writeAll("\r\n");
487511
488 try buffered.flush();512 try res.connection.flush();
489 }513 }
490514
491 pub const TransferReadError = BufferedConnection.ReadError || proto.HeadersParser.ReadError;515 pub const TransferReadError = BufferedConnection.ReadError || proto.HeadersParser.ReadError;
...@@ -669,6 +693,8 @@ pub const Response = struct {...@@ -669,6 +693,8 @@ pub const Response = struct {
669 .content_length => |len| if (len != 0) return error.MessageNotCompleted,693 .content_length => |len| if (len != 0) return error.MessageNotCompleted,
670 .none => {},694 .none => {},
671 }695 }
696
697 try res.connection.flush();
672 }698 }
673};699};
674700