Skip to documentation
SLOP

tiny.http.Router

Reference tiny.http Router

Defined in tiny.http.

Called byCallsNo direct callersRequestparseResponsedeinitResponseinitResponseserializeResponseserializeForMethod+6 moretiny.httpRouter
Static calls · unresolved targets: 8 · external targets: 30.

Source

Source: lib/http/src/router/runtime.zig:39

zig
pub fn Router(comptime Context: type) type {    return struct {        allocator: std.mem.Allocator,        routes: RouteMap,        not_found_handler: ?Handler,        context: Context,        const Self = @This();        pub const Handler = *const fn (Context, *Request, *Response) anyerror!void;        pub const WsHandler = *const fn (Context, *WebSocket) anyerror!void;        const RouteEntry: type = RouterRouteEntryType(Handler, WsHandler);        const RouteMap: type = std.HashMap(RouterRouteKey, RouteEntry, RouterRouteKeyContext, 80);        const WebSocketSession = struct {            allocator: std.mem.Allocator,            websocket: WebSocket,            context: Context,            handler: WsHandler,            fn drive(self: *WebSocketSession) !void {                self.handler(self.context, &self.websocket) catch |err| switch (err) {                    error.WouldBlock => return,                    else => {                        self.websocket.close(WebSocketCloseCode.internal_error, "Handler error") catch |close_err| {                            log.warn("failed to send websocket close after handler error: {s}", .{@errorName(close_err)});                        };                        self.websocket.connection.markClosing();                        return err;                    },                };                if (self.websocket.state == .closed) self.websocket.connection.markClosing();            }            fn destroy(self: *WebSocketSession) void {                self.websocket.deinit(self.allocator);                self.allocator.destroy(self);            }        };        pub fn init(allocator: std.mem.Allocator, context: Context) Self {            return .{                .allocator = allocator,                .routes = RouteMap.init(allocator),                .not_found_handler = null,                .context = context,            };        }        pub fn deinit(self: *Self) void {            self.routes.deinit();        }        pub fn route(self: *Self, method: Request.Method, path: []const u8, handler: Handler) !void {            try self.routes.put(.{ .method = method, .path = path }, .{                .handler = handler,                .is_websocket = false,                .ws_handler = null,                .websocket_limits = null,            });        }        pub fn get(self: *Self, path: []const u8, handler: Handler) !void {            try self.route(.GET, path, handler);        }        pub fn head(self: *Self, path: []const u8, handler: Handler) !void {            try self.route(.HEAD, path, handler);        }        pub fn post(self: *Self, path: []const u8, handler: Handler) !void {            try self.route(.POST, path, handler);        }        pub fn put(self: *Self, path: []const u8, handler: Handler) !void {            try self.route(.PUT, path, handler);        }        pub fn delete(self: *Self, path: []const u8, handler: Handler) !void {            try self.route(.DELETE, path, handler);        }        pub fn websocket(            self: *Self,            path: []const u8,            limits: WebSocket.Limits,            upgrade_handler: Handler,            ws_handler: WsHandler,        ) !void {            try self.routes.put(.{ .method = .GET, .path = path }, .{                .handler = upgrade_handler,                .is_websocket = true,                .ws_handler = ws_handler,                .websocket_limits = limits,            });        }        pub fn notFound(self: *Self, handler: Handler) void {            self.not_found_handler = handler;        }        pub fn handleRequest(self: *Self, conn: *Connection) !bool {            switch (conn.currentState()) {                .http => {},                .websocket => {                    conn.driveProtocol() catch |err| {                        conn.markClosing();                        return err;                    };                    if (conn.currentState() == .websocket) conn.waitForInput();                    return false;                },                .closing, .closed => return false,            }            const parse_result = while (true) {                if (conn.hasBufferedInput()) {                    if (Request.parse(                        conn.requestScratch(),                        conn.bufferedInput(),                    )) |result| {                        break result;                    } else |err| {                        if (err != ParseError.IncompleteRequest) {                            try sendBadRequest(conn);                            conn.markClosing();                            return false;                        }                    }                }                _ = conn.bufferInput() catch |err| switch (err) {                    error.ConnectionClosed => return false,                    error.WouldBlock => {                        conn.waitForRead();                        return false;                    },                    error.InputCapacityExceeded => {                        try sendBadRequest(conn);                        conn.markClosing();                        return false;                    },                    else => return err,                };            };            defer conn.consumeBufferedInput(parse_result.consumed);            var req = parse_result.request;            var res = Response.init(conn.responseScratch());            defer res.deinit();            const key = RouterRouteKey{ .method = req.method, .path = req.pathOnly() };            if (self.routes.get(key)) |entry| {                if (entry.is_websocket and req.isWebSocketUpgrade()) {                    return self.handleWebSocketUpgrade(conn, &req, entry);                } else {                    entry.handler(self.context, &req, &res) catch |err| {                        try sendInternalError(conn, req.method);                        conn.markClosing();                        return err;                    };                }            } else if (self.not_found_handler) |handler| {                handler(self.context, &req, &res) catch |err| {                    try sendInternalError(conn, req.method);                    conn.markClosing();                    return err;                };            } else {                res.status = 404;                res.status_text = "Not Found";                res.body = "Not Found";            }            try writeResponse(conn, try res.serializeForMethod(req.method));            const connection_header = req.headers.get("Connection") orelse "";            const keep_alive = connectionWantsKeepAlive(req.version, connection_header);            if (keep_alive) {                conn.waitForInput();            } else {                conn.markClosing();            }            return keep_alive;        }        fn handleWebSocketUpgrade(self: *Self, conn: *Connection, req: *Request, entry: RouteEntry) !bool {            const handshake = WebSocket.validateClientHandshake(req) catch {                try sendBadRequest(conn);                conn.markClosing();                return false;            };            var res = Response.init(conn.responseScratch());            defer res.deinit();            entry.handler(self.context, req, &res) catch |err| {                try sendInternalError(conn, req.method);                conn.markClosing();                return err;            };            if (res.status != 200 and res.status != 0) {                try writeResponse(conn, try res.serializeForMethod(req.method));                conn.markClosing();                return false;            }            const session = try self.allocator.create(WebSocketSession);            errdefer self.allocator.destroy(session);            session.* = .{                .allocator = self.allocator,                .websocket = try WebSocket.init(                    self.allocator,                    entry.websocket_limits.?,                    conn,                ),                .context = self.context,                .handler = entry.ws_handler.?,            };            errdefer session.websocket.deinit(self.allocator);            const accept_key = handshake.accept();            var ws_res = try Response.switchingProtocols(conn.responseScratch(), &accept_key);            defer ws_res.deinit();            try writeResponse(conn, try ws_res.serialize());            session.websocket.activate();            conn.installProtocol(session, WebSocketSession.drive, WebSocketSession.destroy);            return false;        }        fn sendBadRequest(conn: *Connection) !void {            var res = Response.init(conn.responseScratch());            defer res.deinit();            res.status = 400;            res.status_text = "Bad Request";            res.body = "Bad Request";            try writeResponse(conn, try res.serialize());        }        fn sendInternalError(conn: *Connection, method: Request.Method) !void {            var res = Response.init(conn.responseScratch());            defer res.deinit();            res.status = 500;            res.status_text = "Internal Server Error";            res.body = "Internal Server Error";            try writeResponse(conn, try res.serializeForMethod(method));        }    };}

Source: lib/http/src/root.zig:75

zig
pub const Router = router.Router;

Complete call list

11 direct calls.

Audit

Definitions1
Public names1
Members0
Version26.7.0
Revisiondaab053ee433