Improve support riggings for Transfer-Encoding
This commit is contained in:
parent
8edf406c52
commit
0e4277ded9
|
@ -44,29 +44,7 @@ export fn do(client: *client, req: *request) (response | error) = {
|
|||
const scan = bufio::newscanner_static(conn, buf);
|
||||
read_statusline(&resp, &scan)?;
|
||||
read_header(&resp.header, &scan)?;
|
||||
|
||||
const cl = header_get(&resp.header, "Content-Length");
|
||||
const te = header_get(&resp.header, "Transfer-Encoding");
|
||||
if (len(cl) > 1 || len(te) > 1) {
|
||||
return protoerr;
|
||||
};
|
||||
|
||||
if (len(te) == 1) {
|
||||
abort(); // TODO: Assign transport encoding appropriately
|
||||
} else {
|
||||
let length = types::SIZE_MAX;
|
||||
if (len(cl) == 1) {
|
||||
length = match (strconv::stoz(cl[0])) {
|
||||
case let z: size =>
|
||||
yield z;
|
||||
case =>
|
||||
return protoerr;
|
||||
};
|
||||
};
|
||||
const remain = bufio::scan_buffer(&scan);
|
||||
resp.body = new_identity_reader(conn, remain, length);
|
||||
};
|
||||
|
||||
resp.body = new_reader(conn, &resp, &scan)?;
|
||||
return resp;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use errors;
|
||||
use io;
|
||||
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 | protoerr);
|
||||
export type error = !(dial::error | io::error | errors::unsupported | protoerr);
|
||||
|
||||
// An HTTP protocol error occurred, indicating that the remote party is not
|
||||
// conformant with HTTP semantics.
|
||||
export type protoerr = void;
|
||||
export type protoerr = !void;
|
||||
|
||||
// Converts an [[error]] to a string.
|
||||
export fn strerror(err: error) const str = {
|
||||
|
@ -17,6 +18,8 @@ export fn strerror(err: error) const str = {
|
|||
return dial::strerror(err);
|
||||
case let err: io::error =>
|
||||
return io::strerror(err);
|
||||
case errors::unsupported =>
|
||||
return "Unsupported HTTP feature";
|
||||
case protoerr =>
|
||||
return "HTTP protocol error";
|
||||
};
|
||||
|
|
|
@ -35,16 +35,16 @@ export fn header_del(head: *header, name: str) void = {
|
|||
};
|
||||
};
|
||||
|
||||
// Retrieves a value, or values, from a header. The empty slice indicates the
|
||||
// abscence of a header.
|
||||
export fn header_get(head: *header, name: str) []str = {
|
||||
// Retrieves a value, or values, from a header. An empty string indicates the
|
||||
// absence of a header.
|
||||
export fn header_get(head: *header, name: str) str = {
|
||||
for (let i = 0z; i < len(head); i += 1) {
|
||||
const (key, val) = head[i];
|
||||
if (key == name) {
|
||||
return [val];
|
||||
return val;
|
||||
};
|
||||
};
|
||||
return [];
|
||||
return "";
|
||||
};
|
||||
|
||||
// Frees state associated with an HTTP [[header]].
|
||||
|
|
|
@ -1,5 +1,66 @@
|
|||
use errors;
|
||||
use bufio;
|
||||
use io;
|
||||
use os;
|
||||
use strconv;
|
||||
use strings;
|
||||
use types;
|
||||
|
||||
export fn new_reader(
|
||||
conn: io::handle,
|
||||
resp: *response,
|
||||
scan: *bufio::scanner,
|
||||
) (*io::stream | errors::unsupported | protoerr) = {
|
||||
// TODO: Content-Encoding support
|
||||
const cl = header_get(&resp.header, "Content-Length");
|
||||
const te = header_get(&resp.header, "Transfer-Encoding");
|
||||
|
||||
if (cl != "" || te == "") {
|
||||
let length = types::SIZE_MAX;
|
||||
if (cl != "") {
|
||||
length = match (strconv::stoz(cl)) {
|
||||
case let z: size =>
|
||||
yield z;
|
||||
case =>
|
||||
return protoerr;
|
||||
};
|
||||
};
|
||||
const remain = bufio::scan_buffer(scan);
|
||||
return new_identity_reader(conn, remain, length);
|
||||
};
|
||||
|
||||
let stream: io::handle = conn;
|
||||
let buffer: []u8 = bufio::scan_buffer(scan);
|
||||
const iter = strings::tokenize(te, ",");
|
||||
for (true) {
|
||||
const te = match (strings::next_token(&iter)) {
|
||||
case let tok: str =>
|
||||
yield strings::trim(tok);
|
||||
case void =>
|
||||
break;
|
||||
};
|
||||
|
||||
// XXX: We could add lzw support if someone added it to
|
||||
// hare-compress
|
||||
switch (te) {
|
||||
case "chunked" =>
|
||||
stream = new_chunked_reader(stream, buffer);
|
||||
buffer = [];
|
||||
case "deflate" =>
|
||||
abort(); // TODO
|
||||
case "gzip" =>
|
||||
abort(); // TODO
|
||||
case =>
|
||||
return errors::unsupported;
|
||||
};
|
||||
};
|
||||
|
||||
if (!(stream is *io::stream)) {
|
||||
// Empty Transfer-Encoding header
|
||||
return protoerr;
|
||||
};
|
||||
return stream as *io::stream;
|
||||
};
|
||||
|
||||
export type identity_reader = struct {
|
||||
vtable: io::stream,
|
||||
|
@ -67,3 +128,29 @@ fn identity_read(
|
|||
rd.length -= n;
|
||||
return n;
|
||||
};
|
||||
|
||||
export type chunked_reader = struct {
|
||||
vtable: io::stream,
|
||||
conn: io::handle,
|
||||
buffer: [os::BUFSIZ]u8,
|
||||
pending: size,
|
||||
};
|
||||
|
||||
fn new_chunked_reader(
|
||||
conn: io::handle,
|
||||
buffer: []u8,
|
||||
) *io::stream = {
|
||||
abort(); // TODO
|
||||
};
|
||||
|
||||
const chunked_reader_vtable = io::vtable {
|
||||
reader = &chunked_read,
|
||||
...
|
||||
};
|
||||
|
||||
fn chunked_read(
|
||||
s: *io::stream,
|
||||
buf: []u8,
|
||||
) (size | io::EOF | io::error) = {
|
||||
abort(); // TODO
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue