2023-02-10 09:13:30 +00:00
|
|
|
use io;
|
2023-02-10 13:09:23 +00:00
|
|
|
use os;
|
2024-03-09 11:45:28 +00:00
|
|
|
use fmt;
|
|
|
|
use strconv;
|
|
|
|
|
|
|
|
export type version = (uint, uint);
|
2023-02-10 09:13:30 +00:00
|
|
|
|
|
|
|
// Stores state related to an HTTP response.
|
|
|
|
export type response = struct {
|
2023-02-10 13:09:23 +00:00
|
|
|
// HTTP protocol version (major, minor)
|
2024-03-09 11:45:28 +00:00
|
|
|
version: version,
|
2023-02-10 09:13:30 +00:00
|
|
|
// The HTTP status for this request as an integer.
|
|
|
|
status: uint,
|
|
|
|
// The HTTP status reason phrase.
|
|
|
|
reason: str,
|
|
|
|
// The HTTP headers provided by the server.
|
|
|
|
header: header,
|
|
|
|
// The response body, if any.
|
2023-02-11 10:30:20 +00:00
|
|
|
body: nullable *io::stream,
|
2023-02-10 09:13:30 +00:00
|
|
|
};
|
|
|
|
|
2023-10-07 10:43:58 +00:00
|
|
|
// Frees state associated with an HTTP [[response]]. If the response has a
|
|
|
|
// non-null body, the user must call [[io::close]] prior to calling this
|
|
|
|
// function.
|
2023-02-10 09:13:30 +00:00
|
|
|
export fn response_finish(resp: *response) void = {
|
|
|
|
header_free(&resp.header);
|
2023-02-10 13:09:23 +00:00
|
|
|
free(resp.reason);
|
2023-02-11 10:30:20 +00:00
|
|
|
free(resp.body);
|
2023-02-10 09:13:30 +00:00
|
|
|
};
|
2024-03-09 11:45:28 +00:00
|
|
|
|
|
|
|
export fn response_write(
|
|
|
|
rw: io::handle,
|
|
|
|
status: uint,
|
|
|
|
body: (void | io::handle),
|
|
|
|
header: (str, str)...
|
|
|
|
) (void | io::error) = {
|
|
|
|
fmt::fprintfln(rw, "HTTP/1.1 {} {}", status, status_reason(status))?;
|
|
|
|
|
|
|
|
let header = header_dup(&header);
|
|
|
|
defer header_free(&header);
|
|
|
|
|
|
|
|
match (body) {
|
|
|
|
case void => void;
|
|
|
|
case let body: io::handle =>
|
|
|
|
match (io::tell(body)) {
|
|
|
|
case io::error => void;
|
|
|
|
case let off: io::off =>
|
|
|
|
header_add(&header, "Content-Length", strconv::i64tos(off));
|
|
|
|
io::seek(body, 0, io::whence::SET)!;
|
|
|
|
body = &io::limitreader(body, off: size);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
write_header(rw, &header)?;
|
|
|
|
|
|
|
|
fmt::fprintln(rw)!;
|
|
|
|
|
|
|
|
match (body) {
|
|
|
|
case void => void;
|
|
|
|
case let body: io::handle =>
|
|
|
|
io::copy(rw, body)!;
|
|
|
|
};
|
|
|
|
};
|