Blame


1 924d1172 2023-12-21 op // This is free and unencumbered software released into the public domain.
2 924d1172 2023-12-21 op //
3 924d1172 2023-12-21 op // Anyone is free to copy, modify, publish, use, compile, sell, or
4 924d1172 2023-12-21 op // distribute this software, either in source code form or as a compiled
5 924d1172 2023-12-21 op // binary, for any purpose, commercial or non-commercial, and by any
6 924d1172 2023-12-21 op // means.
7 924d1172 2023-12-21 op //
8 924d1172 2023-12-21 op // In jurisdictions that recognize copyright laws, the author or authors
9 924d1172 2023-12-21 op // of this software dedicate any and all copyright interest in the
10 924d1172 2023-12-21 op // software to the public domain. We make this dedication for the benefit
11 924d1172 2023-12-21 op // of the public at large and to the detriment of our heirs and
12 924d1172 2023-12-21 op // successors. We intend this dedication to be an overt act of
13 924d1172 2023-12-21 op // relinquishment in perpetuity of all present and future rights to this
14 924d1172 2023-12-21 op // software under copyright law.
15 924d1172 2023-12-21 op //
16 924d1172 2023-12-21 op // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 924d1172 2023-12-21 op // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 924d1172 2023-12-21 op // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 924d1172 2023-12-21 op // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 924d1172 2023-12-21 op // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 924d1172 2023-12-21 op // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 924d1172 2023-12-21 op // OTHER DEALINGS IN THE SOFTWARE.
23 924d1172 2023-12-21 op
24 924d1172 2023-12-21 op use bufio;
25 924d1172 2023-12-21 op use encoding::utf8;
26 924d1172 2023-12-21 op use errors;
27 924d1172 2023-12-21 op use fmt;
28 924d1172 2023-12-21 op use io;
29 924d1172 2023-12-21 op use log;
30 924d1172 2023-12-21 op use net;
31 924d1172 2023-12-21 op use types;
32 924d1172 2023-12-21 op
33 924d1172 2023-12-21 op use strings;
34 924d1172 2023-12-21 op
35 924d1172 2023-12-21 op use ev;
36 924d1172 2023-12-21 op
37 0c267caa 2023-12-21 op type badrequest = !void;
38 0c267caa 2023-12-21 op
39 924d1172 2023-12-21 op export type version = enum {
40 924d1172 2023-12-21 op HTTP_1_0,
41 924d1172 2023-12-21 op HTTP_1_1,
42 924d1172 2023-12-21 op };
43 924d1172 2023-12-21 op
44 924d1172 2023-12-21 op export type method = enum {
45 924d1172 2023-12-21 op GET,
46 ef30005e 2023-12-21 op HEAD,
47 924d1172 2023-12-21 op POST,
48 ef30005e 2023-12-21 op PUT,
49 ef30005e 2023-12-21 op DELETE,
50 ef30005e 2023-12-21 op CONNECT,
51 ef30005e 2023-12-21 op OPTIONS,
52 ef30005e 2023-12-21 op TRACE,
53 ef30005e 2023-12-21 op PATCH,
54 924d1172 2023-12-21 op };
55 924d1172 2023-12-21 op
56 924d1172 2023-12-21 op export type request = struct {
57 924d1172 2023-12-21 op path: str,
58 924d1172 2023-12-21 op method: method,
59 924d1172 2023-12-21 op version: version,
60 924d1172 2023-12-21 op ctype: str,
61 924d1172 2023-12-21 op csize: size,
62 924d1172 2023-12-21 op chunked: bool,
63 924d1172 2023-12-21 op };
64 924d1172 2023-12-21 op
65 0c267caa 2023-12-21 op export type routefn = *fn(*request, *reswriter) (void | io::error);
66 924d1172 2023-12-21 op
67 4ea63b45 2023-12-21 op type connection = struct {
68 924d1172 2023-12-21 op fp: io::file,
69 924d1172 2023-12-21 op in: bufio::scanner,
70 924d1172 2023-12-21 op first_line: bool,
71 d5ea6c0a 2023-12-21 op request_done: bool,
72 924d1172 2023-12-21 op request: request,
73 94eeacc5 2023-12-21 op response: reswriter,
74 d5ea6c0a 2023-12-21 op routefn: routefn,
75 924d1172 2023-12-21 op mux: *mux,
76 924d1172 2023-12-21 op };
77 924d1172 2023-12-21 op
78 924d1172 2023-12-21 op // XXX generic listen would be very handy!
79 924d1172 2023-12-21 op // something like: http::listen("localhost:8080") or maybe even
80 924d1172 2023-12-21 op // http::listen("unix:/run/foo.sock")
81 924d1172 2023-12-21 op
82 ed8cff62 2023-12-21 op export fn listen_sock(f: io::file, mux: nullable *mux) void = {
83 ed8cff62 2023-12-21 op ev::add(f, ev::READ, &acceptconn, match(mux) {
84 ed8cff62 2023-12-21 op case null => yield &global;
85 ed8cff62 2023-12-21 op case => yield mux;
86 ed8cff62 2023-12-21 op });
87 924d1172 2023-12-21 op };
88 924d1172 2023-12-21 op
89 4ea63b45 2023-12-21 op fn acceptconn(f: io::file, ev: ev::event, data: nullable *opaque) void = {
90 924d1172 2023-12-21 op let sock = match(net::accept(f, net::sockflag::NONBLOCK)) {
91 924d1172 2023-12-21 op case let err: net::error =>
92 924d1172 2023-12-21 op log::printfln("accept: {}", net::strerror(err));
93 924d1172 2023-12-21 op return;
94 924d1172 2023-12-21 op case let sock: net::socket =>
95 924d1172 2023-12-21 op yield sock;
96 924d1172 2023-12-21 op };
97 924d1172 2023-12-21 op
98 924d1172 2023-12-21 op let mux = data: *mux;
99 4ea63b45 2023-12-21 op let conn = alloc(connection {
100 924d1172 2023-12-21 op fp = sock,
101 924d1172 2023-12-21 op mux = mux,
102 924d1172 2023-12-21 op in = bufio::newscanner(sock, types::SIZE_MAX),
103 924d1172 2023-12-21 op first_line = true,
104 94eeacc5 2023-12-21 op response = new_reswriter(sock),
105 d5ea6c0a 2023-12-21 op routefn = &route_notfound,
106 924d1172 2023-12-21 op ...
107 924d1172 2023-12-21 op });
108 924d1172 2023-12-21 op
109 4ea63b45 2023-12-21 op ev::add(sock, ev::READ, &handleconn, conn);
110 924d1172 2023-12-21 op };
111 924d1172 2023-12-21 op
112 0c267caa 2023-12-21 op fn parse_req(
113 4ea63b45 2023-12-21 op conn: *connection
114 0c267caa 2023-12-21 op ) (bool | badrequest | io::error | encoding::utf8::invalid) = {
115 4ea63b45 2023-12-21 op let req = &conn.request;
116 4ea63b45 2023-12-21 op let res = &conn.response;
117 4ea63b45 2023-12-21 op
118 924d1172 2023-12-21 op for (true) {
119 4ea63b45 2023-12-21 op let line = match(bufio::scan_string(&conn.in, "\r\n")) {
120 924d1172 2023-12-21 op case io::EOF => return badrequest;
121 924d1172 2023-12-21 op case let err: io::error => return err;
122 924d1172 2023-12-21 op case let line: const str => yield line;
123 924d1172 2023-12-21 op };
124 924d1172 2023-12-21 op
125 4ea63b45 2023-12-21 op if (conn.first_line) {
126 4ea63b45 2023-12-21 op conn.first_line = false;
127 924d1172 2023-12-21 op
128 924d1172 2023-12-21 op let (method, rest) = strings::cut(line, " ");
129 924d1172 2023-12-21 op
130 924d1172 2023-12-21 op switch (method) {
131 4ea63b45 2023-12-21 op case "GET" => req.method = method::GET;
132 4ea63b45 2023-12-21 op case "HEAD" => req.method = method::HEAD;
133 4ea63b45 2023-12-21 op case "POST" => req.method = method::POST;
134 4ea63b45 2023-12-21 op case "PUT" => req.method = method::PUT;
135 4ea63b45 2023-12-21 op case "DELETE" => req.method = method::DELETE;
136 4ea63b45 2023-12-21 op case "CONNECT" => req.method = method::CONNECT;
137 4ea63b45 2023-12-21 op case "OPTIONS" => req.method = method::OPTIONS;
138 4ea63b45 2023-12-21 op case "TRACE" => req.method = method::TRACE;
139 4ea63b45 2023-12-21 op case "PATCH" => req.method = method::PATCH;
140 924d1172 2023-12-21 op case => return badrequest;
141 924d1172 2023-12-21 op };
142 924d1172 2023-12-21 op
143 924d1172 2023-12-21 op let (path, version) = strings::cut(rest, " ");
144 4ea63b45 2023-12-21 op req.path = strings::dup(path);
145 924d1172 2023-12-21 op
146 924d1172 2023-12-21 op switch (version) {
147 924d1172 2023-12-21 op case "HTTP/1.0" =>
148 4ea63b45 2023-12-21 op req.version = version::HTTP_1_0;
149 94eeacc5 2023-12-21 op case "HTTP/1.1" =>
150 4ea63b45 2023-12-21 op req.version = version::HTTP_1_1;
151 4ea63b45 2023-12-21 op res.chunked = true;
152 924d1172 2023-12-21 op case => return badrequest;
153 924d1172 2023-12-21 op };
154 924d1172 2023-12-21 op
155 924d1172 2023-12-21 op continue;
156 924d1172 2023-12-21 op };
157 924d1172 2023-12-21 op
158 924d1172 2023-12-21 op // ignore everything for the time being.
159 924d1172 2023-12-21 op if (line == "") {
160 924d1172 2023-12-21 op return true;
161 924d1172 2023-12-21 op };
162 924d1172 2023-12-21 op
163 924d1172 2023-12-21 op continue;
164 924d1172 2023-12-21 op };
165 924d1172 2023-12-21 op };
166 924d1172 2023-12-21 op
167 4ea63b45 2023-12-21 op fn close_conn(conn: *connection) void = {
168 4ea63b45 2023-12-21 op ev::del(conn.fp);
169 924d1172 2023-12-21 op
170 4ea63b45 2023-12-21 op bufio::finish(&conn.in);
171 4ea63b45 2023-12-21 op match (io::close(conn.fp)) {
172 924d1172 2023-12-21 op case => yield;
173 924d1172 2023-12-21 op };
174 924d1172 2023-12-21 op
175 4ea63b45 2023-12-21 op match (io::close(&conn.response)) {
176 94eeacc5 2023-12-21 op case => yield;
177 94eeacc5 2023-12-21 op };
178 94eeacc5 2023-12-21 op
179 4ea63b45 2023-12-21 op free(conn);
180 924d1172 2023-12-21 op };
181 924d1172 2023-12-21 op
182 4ea63b45 2023-12-21 op fn handleconn(f: io::file, ev: ev::event, data: nullable *opaque) void = {
183 4ea63b45 2023-12-21 op let conn = data: *connection;
184 924d1172 2023-12-21 op
185 4ea63b45 2023-12-21 op match (respond(conn)) {
186 0c267caa 2023-12-21 op case let err: io::error =>
187 0c267caa 2023-12-21 op log::printfln("failure: {}", io::strerror(err));
188 4ea63b45 2023-12-21 op close_conn(conn);
189 924d1172 2023-12-21 op return;
190 924d1172 2023-12-21 op case =>
191 94eeacc5 2023-12-21 op // XXX wait if there is still data pending.
192 4ea63b45 2023-12-21 op if (conn.response.done) {
193 4ea63b45 2023-12-21 op close_conn(conn);
194 94eeacc5 2023-12-21 op return;
195 924d1172 2023-12-21 op };
196 d5ea6c0a 2023-12-21 op
197 4ea63b45 2023-12-21 op ev::add(conn.fp, ev::READ | ev::WRITE, &handleconn, conn);
198 924d1172 2023-12-21 op };
199 924d1172 2023-12-21 op };
200 924d1172 2023-12-21 op
201 4ea63b45 2023-12-21 op fn handle_request(conn: *connection) (void | io::error) = {
202 4ea63b45 2023-12-21 op match (parse_req(conn)) {
203 924d1172 2023-12-21 op case let done: bool =>
204 924d1172 2023-12-21 op if (!done)
205 924d1172 2023-12-21 op return; // try again later
206 924d1172 2023-12-21 op yield;
207 924d1172 2023-12-21 op case errors::again => return; // try again later
208 924d1172 2023-12-21 op case badrequest =>
209 4ea63b45 2023-12-21 op route_badrequest(&conn.request, &conn.response)?;
210 4ea63b45 2023-12-21 op conn.response.done = true;
211 4ea63b45 2023-12-21 op reswriter_flush(&conn.response)?;
212 924d1172 2023-12-21 op return;
213 924d1172 2023-12-21 op case let err: io::error =>
214 924d1172 2023-12-21 op log::printfln("parse_req: {}", io::strerror(err));
215 924d1172 2023-12-21 op return;
216 924d1172 2023-12-21 op };
217 924d1172 2023-12-21 op
218 ed8cff62 2023-12-21 op log::printfln("< GET {}", conn.request.path);
219 924d1172 2023-12-21 op
220 ed8cff62 2023-12-21 op conn.routefn = mux_match(conn.mux, &conn.request, &route_notfound);
221 4ea63b45 2023-12-21 op conn.request_done = true;
222 d5ea6c0a 2023-12-21 op };
223 d5ea6c0a 2023-12-21 op
224 4ea63b45 2023-12-21 op fn respond(conn: *connection) (void | io::error) = {
225 4ea63b45 2023-12-21 op if (!conn.request_done)
226 4ea63b45 2023-12-21 op handle_request(conn)?;
227 4ea63b45 2023-12-21 op if (!conn.request_done)
228 d5ea6c0a 2023-12-21 op return;
229 d5ea6c0a 2023-12-21 op
230 4ea63b45 2023-12-21 op if (!conn.response.done) {
231 4ea63b45 2023-12-21 op conn.response.done = true;
232 4ea63b45 2023-12-21 op conn.routefn(&conn.request, &conn.response)?;
233 924d1172 2023-12-21 op };
234 924d1172 2023-12-21 op
235 4ea63b45 2023-12-21 op reswriter_flush(&conn.response)?;
236 924d1172 2023-12-21 op };
237 924d1172 2023-12-21 op
238 0c267caa 2023-12-21 op fn route_notfound(req: *request, res: *reswriter) (void | io::error) = {
239 94eeacc5 2023-12-21 op reply(req, res, 404, "Not Found")?;
240 94eeacc5 2023-12-21 op header(res, "Content-Type", "text/plain")?;
241 94eeacc5 2023-12-21 op fmt::fprintln(res, "Page not found.")?;
242 924d1172 2023-12-21 op };
243 924d1172 2023-12-21 op
244 0c267caa 2023-12-21 op fn route_badrequest(req: *request, res: *reswriter) (void | io::error) = {
245 94eeacc5 2023-12-21 op reply(req, res, 400, "Bad Request")?;
246 94eeacc5 2023-12-21 op header(res, "Content-Type", "text/plain")?;
247 94eeacc5 2023-12-21 op fmt::fprintln(res, "Bad Request")?;
248 924d1172 2023-12-21 op };