X-Git-Url: https://gitweb.ps.run/zighttp/blobdiff_plain/9a88fec57f4fa87cae6769ee0f992fbf00b8becd..d2215f174d1c9c8a66c62094d99e1c8d2305b1c1:/src/http.zig diff --git a/src/http.zig b/src/http.zig index c14f16d..378bca7 100644 --- a/src/http.zig +++ b/src/http.zig @@ -59,10 +59,10 @@ pub const Server = struct { errdefer posix.close(client_socket); var event = linux.epoll_event{ .events = linux.EPOLL.IN, .data = .{ .fd = client_socket } }; try posix.epoll_ctl(self.efd, linux.EPOLL.CTL_ADD, client_socket, &event); - var addr: std.c.sockaddr = undefined; + var addr: std.os.linux.sockaddr = undefined; var addr_size: std.c.socklen_t = @sizeOf(std.c.sockaddr); _ = std.c.getpeername(client_socket, &addr, &addr_size); - std.debug.print("new connection from {}\n", .{addr}); + // std.debug.print("new connection from {} [{}/{}]\n", .{ addr, @sizeOf(std.os.linux.sockaddr), addr_size }); } else { var closed = false; var req = Request{ .fd = ready_socket }; @@ -73,6 +73,8 @@ pub const Server = struct { read += newly_read; if (newly_read == 0) break; + // std.debug.print("[[{}/{}]]\n", .{ newly_read, read }); + // std.time.sleep(100000000); } if (read == 0) { closed = true; @@ -114,16 +116,16 @@ pub const Request = struct { method: Method = undefined, target: []const u8 = undefined, + query: ?[]const u8 = null, version: ?[]const u8 = null, head: ?[]const u8 = null, body: ?[]u8 = null, pub fn parse(self: *Request, buf: []u8) bool { - std.debug.print("buf: {s}\n", .{buf}); + // std.debug.print("buf: {s}\n", .{buf}); var state: u8 = 0; var start: u32 = 0; - // var end: u32 = 0; var index: u32 = 0; while (index < buf.len) { @@ -136,25 +138,36 @@ pub const Request = struct { if (c == ' ') { self.method = @enumFromInt(Method.parse(buf[start..index])); start = index + 1; - state += 1; + state = 1; } }, 1 => { - if (c == ' ') { + if (c == '?') { + self.target = buf[start..index]; + start = index + 1; + state = 2; + } else if (c == ' ') { self.target = buf[start..index]; start = index + 1; - state += 1; + state = 3; } }, 2 => { + if (c == ' ') { + self.query = buf[start..index]; + start = index + 1; + state = 3; + } + }, + 3 => { if (c == '\r') { self.version = buf[start..index]; start = index + 2; index += 1; - state += 1; + state = 4; } }, - 3 => { + 4 => { if (c == '\r' and (index + 2) < buf.len and buf[index + 2] == '\r') { self.head = buf[start .. index + 2]; @@ -171,53 +184,97 @@ pub const Request = struct { return true; } - pub fn get_header1(self: Request, name: []const u8) ?[]const u8 { - const head = self.head orelse return null; + pub fn get_cookie(self: Request, name: []const u8) ?[]const u8 { + const cookie = self.get_header("Cookie") orelse return null; var start: usize = 0; var matching: usize = 0; - for (0..head.len) |i| { - const c = head[i]; + for (0..cookie.len) |i| { + const c = cookie[i]; if (matching < name.len) { if (c == name[matching]) { - // if (matching == 0) start = i; + if (matching == 0) start = i; matching += 1; } else { - start = i; matching = 0; } } else { - if (c == '\r') { - return head[start..i]; + if (c == '=') { + if (std.mem.indexOfScalarPos(u8, cookie, i, ';')) |semi_index| { + return cookie[i + 1 .. semi_index]; + } else { + return cookie[i + 1 .. cookie.len]; + } + } else { + matching = 0; } } } return null; } - pub fn get_cookie(self: Request, name: []const u8) ?[]const u8 { + pub fn get_header(self: Request, name: []const u8) ?[]const u8 { + const head = self.head orelse return null; + const header_start = std.mem.indexOf(u8, head, name) orelse return null; + const colon_index = std.mem.indexOfPos(u8, head, header_start, ": ") orelse return null; + const header_end = std.mem.indexOfPos(u8, head, colon_index, "\r\n") orelse return null; + return head[colon_index + 2 .. header_end]; + } + + pub fn get_param(self: Request, name: []const u8) ?[]const u8 { + const query = self.query orelse return null; + const name_index = std.mem.indexOf(u8, query, name) orelse return null; + const eql_index = std.mem.indexOfScalarPos(u8, query, name_index, '=') orelse return null; + if (std.mem.indexOfScalarPos(u8, query, name_index, '&')) |amp_index| { + const result = query[eql_index + 1 .. amp_index]; + return result; + } else { + const result = query[eql_index + 1 .. query.len]; + return result; + } + } + + pub fn get_value(self: Request, name: []const u8) ?[]const u8 { + const body = self.body orelse return null; + const name_index = std.mem.indexOf(u8, body, name) orelse return null; + const eql_index = std.mem.indexOfScalarPos(u8, body, name_index, '=') orelse return null; + if (std.mem.indexOfScalarPos(u8, body, name_index, '&')) |amp_index| { + const result = body[eql_index + 1 .. amp_index]; + return result; + } else { + const result = body[eql_index + 1 .. body.len]; + return result; + } + } + + pub fn get_cookie1(self: Request, name: []const u8) ?[]const u8 { const cookie = self.get_header("Cookie") orelse return null; + const name_index = std.mem.indexOf(u8, cookie, name) orelse return null; + const eql_index = std.mem.indexOfScalarPos(u8, cookie, name_index, '=') orelse return null; + if (std.mem.indexOfScalarPos(u8, cookie, eql_index, ';')) |semi_index| { + return cookie[eql_index + 1 .. semi_index]; + } else { + return cookie[eql_index + 1 .. cookie.len]; + } + } + pub fn get_header1(self: Request, name: []const u8) ?[]const u8 { + const head = self.head orelse return null; var start: usize = 0; var matching: usize = 0; - for (0..cookie.len) |i| { - const c = cookie[i]; + for (0..head.len) |i| { + const c = head[i]; if (matching < name.len) { if (c == name[matching]) { - if (matching == 0) start = i; + // if (matching == 0) start = i; matching += 1; } else { + start = i; matching = 0; } } else { - if (c == '=') { - if (std.mem.indexOfScalarPos(u8, cookie, i, ';')) |semi_index| { - return cookie[i + 1 .. semi_index]; - } else { - return cookie[i + 1 .. cookie.len]; - } - } else { - matching = 0; + if (c == '\r') { + return head[start..i]; } } } @@ -251,53 +308,21 @@ pub const Request = struct { return true; } - - pub fn get_header(self: Request, name: []const u8) ?[]const u8 { - const head = self.head orelse return null; - const header_start = std.mem.indexOf(u8, head, name) orelse return null; - const colon_index = std.mem.indexOfPos(u8, head, header_start, ": ") orelse return null; - const header_end = std.mem.indexOfPos(u8, head, colon_index, "\r\n") orelse return null; - return head[colon_index + 2 .. header_end]; - } - - pub fn get_cookie1(self: Request, name: []const u8) ?[]const u8 { - const cookie = self.get_header("Cookie") orelse return null; - const name_index = std.mem.indexOf(u8, cookie, name) orelse return null; - const eql_index = std.mem.indexOfScalarPos(u8, cookie, name_index, '=') orelse return null; - if (std.mem.indexOfScalarPos(u8, cookie, eql_index, ';')) |semi_index| { - return cookie[eql_index + 1 .. semi_index]; - } else { - return cookie[eql_index + 1 .. cookie.len]; - } - } - - pub fn get_value(self: Request, name: []const u8) ?[]const u8 { - const body = self.body orelse return null; - const name_index = std.mem.indexOf(u8, body, name) orelse return null; - const eql_index = std.mem.indexOfScalarPos(u8, body, name_index, '=') orelse return null; - if (std.mem.indexOfScalarPos(u8, body, name_index, '&')) |amp_index| { - const result = body[eql_index + 1 .. amp_index]; - return result; - } else { - const result = body[eql_index + 1 .. body.len]; - return result; - } - } }; pub const Response = struct { const ExtraHeadersMax = 16; const HeaderList = std.BoundedArray(Header, ExtraHeadersMax); - fd: posix.fd_t, + req: Request, stream_head: std.io.FixedBufferStream([]u8), stream_body: std.io.FixedBufferStream([]u8), status: Status = .ok, extra_headers: HeaderList = HeaderList.init(0) catch unreachable, - pub fn init(fd: posix.fd_t, buf_head: []u8, buf_body: []u8) Response { + pub fn init(req: Request, buf_head: []u8, buf_body: []u8) Response { return .{ - .fd = fd, + .req = req, .stream_head = std.io.fixedBufferStream(buf_head), .stream_body = std.io.fixedBufferStream(buf_body), }; @@ -308,10 +333,11 @@ pub const Response = struct { try self.add_header("Location", .{ "{s}", .{location} }); } + /// value can be a "string" or a struct .{ "fmt", .{ args }} pub fn add_header(self: *Response, name: []const u8, value: anytype) !void { const header = try self.extra_headers.addOne(); try header.name.writer().writeAll(name); - if (@typeInfo(@TypeOf(value)).Struct.fields.len < 2 or @sizeOf(@TypeOf(value[1])) == 0) { + if (@typeInfo(@TypeOf(value)).@"struct".fields.len < 2 or @sizeOf(@TypeOf(value[1])) == 0) { try header.value.writer().writeAll(value[0]); } else { try std.fmt.format(header.value.writer(), value[0], value[1]); @@ -330,7 +356,7 @@ pub const Response = struct { pub fn write(self: *Response, comptime fmt: []const u8, args: anytype) !void { const writer = self.stream_body.writer(); - if (@sizeOf(@TypeOf(args)) == 0) { + if (@typeInfo(@TypeOf(args)).@"struct".fields.len == 0) { try writer.writeAll(fmt); } else { try std.fmt.format(writer, fmt, args); @@ -340,20 +366,23 @@ pub const Response = struct { pub fn send(self: *Response) !void { // TODO: Provisorium const compress = false; - var compress_buffer = try std.BoundedArray(u8, 1024 * 32).init(0); + const CompressBuffer = struct { + var compress_buffer: std.BoundedArray(u8, 1024 * 32) = undefined; + }; + try CompressBuffer.compress_buffer.resize(0); // write head const writer = self.stream_head.writer(); if (compress) { var cfbs = std.io.fixedBufferStream(self.stream_body.getWritten()); - var compressor = try std.compress.gzip.compressor(compress_buffer.writer(), .{ .level = .default }); + var compressor = try std.compress.gzip.compressor(CompressBuffer.compress_buffer.writer(), .{ .level = .default }); try compressor.compress(cfbs.reader()); // try compressor.flush(); try compressor.finish(); try std.fmt.format(writer, "HTTP/1.1 {} {?s}\r\n" ++ "Content-Length: {}\r\n" ++ - "Content-Encoding: gzip\r\n", .{ @intFromEnum(self.status), self.status.phrase(), compress_buffer.constSlice().len }); + "Content-Encoding: gzip\r\n", .{ @intFromEnum(self.status), self.status.phrase(), CompressBuffer.compress_buffer.constSlice().len }); } else { try std.fmt.format(writer, "HTTP/1.1 {} {?s}\r\n" ++ "Content-Length: {}\r\n", .{ @intFromEnum(self.status), self.status.phrase(), self.stream_body.pos }); @@ -367,16 +396,16 @@ pub const Response = struct { // write body to head if (compress) { - try std.fmt.format(writer, "{s}", .{compress_buffer.constSlice()}); + try writer.writeAll(CompressBuffer.compress_buffer.constSlice()); } else { - try std.fmt.format(writer, "{s}", .{self.stream_body.getWritten()}); + try writer.writeAll(self.stream_body.getWritten()); } // send const res = self.stream_head.getWritten(); var written: usize = 0; while (written < res.len) { - written += posix.write(self.fd, res[written..res.len]) catch |err| { + written += posix.write(self.req.fd, res[written..res.len]) catch |err| { std.debug.print("posix.write: {}\n", .{err}); continue; };