1
Fork 0

transport: improve identity transport lifetime

This commit is contained in:
Drew DeVault 2023-10-07 12:43:58 +02:00
parent 159dd0d06f
commit 396d6caa76
4 changed files with 32 additions and 42 deletions

View file

@ -6,7 +6,7 @@ use net::uri;
use os;
export fn main() void = {
const client = http::newclient("Hare test client");
const client = http::newclient("Hare net::http test client");
defer http::client_finish(&client);
const target = match (uri::parse(os::args[1])) {
@ -36,4 +36,5 @@ export fn main() void = {
const body = resp.body as *io::stream;
io::copy(os::stdout, body)!;
io::close(body)!;
};

View file

@ -14,6 +14,9 @@ use types;
// Performs an HTTP [[request]] with the given [[client]]. The request is
// performed synchronously; this function blocks until the server has returned
// the response status and all HTTP headers associated with the response.
//
// If the provided [[response]] has a non-null body, the user must pass it to
// [[io::close]] before calling [[response_finish]].
export fn do(client: *client, req: *request) (response | error) = {
assert(req.target.scheme == "http"); // TODO: https
const conn = dial::dial_uri("tcp", req.target)?;
@ -53,7 +56,7 @@ export fn do(client: *client, req: *request) (response | error) = {
};
let resp = response { ... };
const scan = bufio::newscanner_static(conn, buf);
const scan = bufio::newscanner(conn, 512);
read_statusline(&resp, &scan)?;
read_header(&resp.header, &scan)?;
resp.body = new_reader(conn, &resp, &scan)?;

View file

@ -15,7 +15,9 @@ export type response = struct {
body: nullable *io::stream,
};
// Frees state associated with an HTTP [[response]].
// 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.
export fn response_finish(resp: *response) void = {
header_free(&resp.header);
free(resp.reason);

View file

@ -50,7 +50,7 @@ export type transport = struct {
};
fn new_reader(
conn: io::handle,
conn: io::file,
resp: *response,
scan: *bufio::scanner,
) (*io::stream | errors::unsupported | protoerr) = {
@ -68,8 +68,7 @@ fn new_reader(
return protoerr;
};
};
const remain = bufio::scan_buffer(scan);
return new_identity_reader(conn, remain, length);
return new_identity_reader(conn, scan, length);
};
// TODO: Figure out the semantics for closing the stream
@ -115,33 +114,32 @@ fn new_reader(
type identity_reader = struct {
vtable: io::stream,
conn: io::handle,
buffer: [os::BUFSZ]u8,
pending: size,
length: size,
conn: io::file,
scan: *bufio::scanner,
src: io::limitstream,
};
const identity_reader_vtable = io::vtable {
reader = &identity_read,
closer = &identity_close,
...
};
// Creates a new reader that reads data until the response's Content-Length is
// reached; i.e. the null Transport-Encoding.
fn new_identity_reader(
conn: io::handle,
buffer: []u8,
conn: io::file,
scan: *bufio::scanner,
content_length: size,
) *io::stream = {
let rd = alloc(identity_reader {
const scan = alloc(*scan);
return alloc(identity_reader {
vtable = &identity_reader_vtable,
conn = conn,
length = content_length,
scan = scan,
src = io::limitreader(scan, content_length),
...
});
rd.buffer[..len(buffer)] = buffer[..];
rd.pending = len(buffer);
return rd;
};
fn identity_read(
@ -150,34 +148,20 @@ fn identity_read(
) (size | io::EOF | io::error) = {
let rd = s: *identity_reader;
assert(rd.vtable == &identity_reader_vtable);
if (rd.length <= 0) {
return io::EOF;
return io::read(&rd.src, buf)?;
};
if (rd.pending == 0) {
let nread = rd.length;
if (nread > len(rd.buffer)) {
nread = len(rd.buffer);
};
fn identity_close(s: *io::stream) (void | io::error) = {
let rd = s: *identity_reader;
assert(rd.vtable == &identity_reader_vtable);
match (io::read(rd.conn, rd.buffer[..nread])?) {
case let n: size =>
rd.pending = n;
case io::EOF =>
return io::EOF;
};
};
// Flush the remainder of the response in case the caller did not read
// it out entirely
io::copy(io::empty, &rd.src)?;
let n = len(buf);
if (n > rd.pending) {
n = rd.pending;
};
buf[..n] = rd.buffer[..n];
rd.buffer[..len(rd.buffer) - n] = rd.buffer[n..];
rd.pending -= n;
rd.length -= n;
return n;
bufio::finish(rd.scan);
free(rd.scan);
io::close(rd.conn)?;
};
type chunk_state = enum {