fix request handling with body

This commit is contained in:
floscodes 2023-05-18 20:44:22 +02:00
parent 25c0ef555a
commit 76f87276b5

View file

@ -33,48 +33,52 @@ pub const Server = struct {
const client_ip = try std.fmt.allocPrint(allocator, "{}", .{conn.address}); const client_ip = try std.fmt.allocPrint(allocator, "{}", .{conn.address});
defer allocator.free(client_ip); defer allocator.free(client_ip);
var header_buffer = std.ArrayList(u8).init(allocator); var buffer = std.ArrayList(u8).init(allocator);
defer header_buffer.deinit(); defer buffer.deinit();
var body_buffer = std.ArrayList(u8).init(allocator); var byte: [1]u8 = undefined;
defer body_buffer.deinit();
var chunk_buf: [4096]u8 = undefined;
var req: Request = undefined; var req: Request = undefined;
req.ip = client_ip; req.ip = client_ip;
// Collect max 4096 bytes of data from the stream into the chunk_buf. Then add it req.body = "";
// Collect bytes of data from the stream. Then add it
// to the ArrayList. Repeat this until all headers of th request end by detecting // to the ArrayList. Repeat this until all headers of th request end by detecting
// appearance of "\r\n\r\n". // appearance of "\r\n\r\n". Then read body if one is sent and if required headers exist and
// method is chosen by the client.
var headers_finished = false;
var content_length: usize = 0;
var header_end: usize = 0;
var header_string: []const u8 = undefined;
while (true) { while (true) {
_ = try conn.stream.read(chunk_buf[0..]); // Read Request stream
try header_buffer.appendSlice(chunk_buf[0..]); _ = try conn.stream.read(&byte);
if (std.mem.indexOf(u8, header_buffer.items, "\r\n\r\n")) |_| break; try buffer.appendSlice(&byte);
} //check if header is finished
// Build headers and cookies of request. if (!headers_finished) {
const header_string = if (olderVersion) header_buffer.toOwnedSlice() else try header_buffer.toOwnedSlice(); if (std.mem.indexOf(u8, buffer.items, "\r\n\r\n")) |header_end_index| {
defer allocator.free(header_string); headers_finished = true;
try buildRequestHeadersAndCookies(&req, header_string, allocator); header_end = header_end_index;
defer allocator.free(req.headers); header_string = buffer.items[0..header_end];
defer allocator.free(req.cookies); try buildRequestHeadersAndCookies(&req, header_string, allocator);
// Checking Request method and if it is one that can send a body.
// If not, exit the loop.
if (req.method == .GET or req.method == .CONNECT or req.method == .HEAD or req.method == .OPTIONS or req.method == .TRACE) break;
// Check if there could be something in the request body, if so, read it. // If Request has a method that can contain a body, check if Content-Length Header is set.
// If the request method is a method with no request body, no body will be accepted. // If not, exit loop. A Request body would not be accepted.
// Otherwise body will be read until the end. if (req.header("Content-Length")) |length| {
if (req.method != .GET and req.method != .CONNECT and req.method != .HEAD and req.method != .OPTIONS and req.method != .TRACE) { content_length = try std.fmt.parseUnsigned(u8, length, 0);
if (req.header("Content-Length")) |index| { } else break;
const end_index = try std.fmt.parseUnsigned(u8, index, 0); }
while (true) { } else {
_ = try conn.stream.read(chunk_buf[0..]); // read body. Check length and add 4 because this is the length of "\r\n\r\n"
try body_buffer.appendSlice(chunk_buf[0..]); if (buffer.items.len - header_end >= content_length + 4) {
if (body_buffer.items.len == @as(usize, end_index + 4)) { req.body = buffer.items[header_end .. header_end + content_length + 4];
req.body = if (olderVersion) body_buffer.toOwnedSlice() else try body_buffer.toOwnedSlice(); break;
break;
}
} }
} }
} else req.body = ""; }
defer allocator.free(req.headers);
defer allocator.free(req.body); defer allocator.free(req.cookies);
// PREPARE FOR BUILDING THE RESPONSE // PREPARE FOR BUILDING THE RESPONSE
// if there ist a path set in the uri trim the trailing slash in order to accept it later during the matching check. // if there ist a path set in the uri trim the trailing slash in order to accept it later during the matching check.