Improve error handling
This commit is contained in:
parent
4ce86752b3
commit
6b36cfcff5
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue