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 bufio;
use encoding::utf8; use encoding::utf8;
use errors;
use fmt; use fmt;
use io; use io;
use net::dial; use net::dial;
@ -43,7 +44,6 @@ export fn do(client: *client, req: *request) (response | error) = {
yield; yield;
}; };
// TODO: Improve error handling
let resp = response { ... }; let resp = response { ... };
const scan = bufio::newscanner_static(conn, buf); const scan = bufio::newscanner_static(conn, buf);
read_statusline(&resp, &scan)?; read_statusline(&resp, &scan)?;
@ -64,32 +64,52 @@ export fn do(client: *client, req: *request) (response | error) = {
fn read_statusline( fn read_statusline(
resp: *response, resp: *response,
scan: *bufio::scanner, scan: *bufio::scanner,
) (void | io::error) = { ) (void | error) = {
const status = match (bufio::scan_string(scan, "\r\n")) { const status = match (bufio::scan_string(scan, "\r\n")) {
case let line: const str => case let line: const str =>
yield line; yield line;
case let err: io::error => case let err: io::error =>
return err; return err;
case utf8::invalid => case utf8::invalid =>
abort(); // TODO return protoerr;
case io::EOF => case io::EOF =>
abort(); // TODO return protoerr;
}; };
// TODO: Error handling
const tok = strings::tokenize(status, " "); 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 (_, version) = strings::cut(version, "/");
const (major, minor) = strings::cut(version, "."); const (major, minor) = strings::cut(version, ".");
resp.version = ( resp.version = (
strconv::stou(major)!, strconv::stou(major)!,
strconv::stou(minor)!, strconv::stou(minor)!,
); );
if (resp.version.0 > 1) {
return errors::unsupported;
};
resp.status = strconv::stou(status)!; resp.status = strconv::stou(status)!;
resp.reason = strings::dup(reason); 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 possible while servicing HTTP requests. Note that these errors are for
// errors related to the processing of the HTTP connection; semantic HTTP errors // errors related to the processing of the HTTP connection; semantic HTTP errors
// such as [[STATUS_NOTFOUND]] are not handled by this type. // 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. // Converts an [[error]] to a string.
export fn strerror(err: error) const str = { export fn strerror(err: error) const str = {
@ -13,5 +17,7 @@ export fn strerror(err: error) const str = {
return dial::strerror(err); return dial::strerror(err);
case let err: io::error => case let err: io::error =>
return io::strerror(err); 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; 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) { for (true) {
const item = match (bufio::scan_string(scan, "\r\n")) { const item = match (bufio::scan_string(scan, "\r\n")) {
case let line: const str => 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 => case let err: io::error =>
return err; return err;
case utf8::invalid => case utf8::invalid =>
abort(); // TODO return protoerr;
}; };
if (item == "") { if (item == "") {
break; break;
}; };
// TODO: validate field-name
let (name, val) = strings::cut(item, ":"); let (name, val) = strings::cut(item, ":");
val = strings::trim(val); val = strings::trim(val);
if (val == "") {
return protoerr;
};
// TODO: validate field-name
header_add(head, name, val); header_add(head, name, val);
}; };
}; };