1
Fork 0

Improve error handling

This commit is contained in:
Drew DeVault 2023-02-11 11:03:51 +01:00
parent 4ce86752b3
commit 6b36cfcff5
3 changed files with 44 additions and 14 deletions

View file

@ -1,5 +1,6 @@
use bufio;
use encoding::utf8;
use errors;
use fmt;
use io;
use net::dial;
@ -43,7 +44,6 @@ export fn do(client: *client, req: *request) (response | error) = {
yield;
};
// TODO: Improve error handling
let resp = response { ... };
const scan = bufio::newscanner_static(conn, buf);
read_statusline(&resp, &scan)?;
@ -64,32 +64,52 @@ export fn do(client: *client, req: *request) (response | error) = {
fn read_statusline(
resp: *response,
scan: *bufio::scanner,
) (void | io::error) = {
) (void | error) = {
const status = match (bufio::scan_string(scan, "\r\n")) {
case let line: const str =>
yield line;
case let err: io::error =>
return err;
case utf8::invalid =>
abort(); // TODO
return protoerr;
case io::EOF =>
abort(); // TODO
return protoerr;
};
// TODO: Error handling
const tok = strings::tokenize(status, " ");
const version = strings::next_token(&tok) as str;
const status = strings::next_token(&tok) as str;
const reason = strings::next_token(&tok) as str;
assert(version == "HTTP/1.1"); // TODO
const version = match (strings::next_token(&tok)) {
case let ver: str =>
yield ver;
case void =>
return protoerr;
};
const status = match (strings::next_token(&tok)) {
case let status: str =>
yield status;
case void =>
return protoerr;
};
const reason = match (strings::next_token(&tok)) {
case let reason: str =>
yield reason;
case void =>
return protoerr;
};
const (_, version) = strings::cut(version, "/");
const (major, minor) = strings::cut(version, ".");
resp.version = (
strconv::stou(major)!,
strconv::stou(minor)!,
);
if (resp.version.0 > 1) {
return errors::unsupported;
};
resp.status = strconv::stou(status)!;
resp.reason = strings::dup(reason);
};

View file

@ -4,7 +4,11 @@ use net::dial;
// Errors possible while servicing HTTP requests. Note that these errors are for
// errors related to the processing of the HTTP connection; semantic HTTP errors
// such as [[STATUS_NOTFOUND]] are not handled by this type.
export type error = !(dial::error | io::error);
export type error = !(dial::error | io::error | protoerr);
// An HTTP protocol error occurred, indicating that the remote party is not
// conformant with HTTP semantics.
export type protoerr = void;
// Converts an [[error]] to a string.
export fn strerror(err: error) const str = {
@ -13,5 +17,7 @@ export fn strerror(err: error) const str = {
return dial::strerror(err);
case let err: io::error =>
return io::strerror(err);
case protoerr =>
return "HTTP protocol error";
};
};

View file

@ -64,7 +64,7 @@ export fn write_header(sink: io::handle, head: *header) (size | io::error) = {
return z;
};
fn read_header(head: *header, scan: *bufio::scanner) (void | io::error) = {
fn read_header(head: *header, scan: *bufio::scanner) (void | error) = {
for (true) {
const item = match (bufio::scan_string(scan, "\r\n")) {
case let line: const str =>
@ -74,15 +74,19 @@ fn read_header(head: *header, scan: *bufio::scanner) (void | io::error) = {
case let err: io::error =>
return err;
case utf8::invalid =>
abort(); // TODO
return protoerr;
};
if (item == "") {
break;
};
// TODO: validate field-name
let (name, val) = strings::cut(item, ":");
val = strings::trim(val);
if (val == "") {
return protoerr;
};
// TODO: validate field-name
header_add(head, name, val);
};
};