transport: improve identity transport lifetime
This commit is contained in:
parent
159dd0d06f
commit
396d6caa76
|
@ -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)!;
|
||||
};
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
return io::read(&rd.src, buf)?;
|
||||
};
|
||||
|
||||
if (rd.length <= 0) {
|
||||
return io::EOF;
|
||||
};
|
||||
fn identity_close(s: *io::stream) (void | io::error) = {
|
||||
let rd = s: *identity_reader;
|
||||
assert(rd.vtable == &identity_reader_vtable);
|
||||
|
||||
if (rd.pending == 0) {
|
||||
let nread = rd.length;
|
||||
if (nread > len(rd.buffer)) {
|
||||
nread = len(rd.buffer);
|
||||
};
|
||||
// Flush the remainder of the response in case the caller did not read
|
||||
// it out entirely
|
||||
io::copy(io::empty, &rd.src)?;
|
||||
|
||||
match (io::read(rd.conn, rd.buffer[..nread])?) {
|
||||
case let n: size =>
|
||||
rd.pending = n;
|
||||
case io::EOF =>
|
||||
return io::EOF;
|
||||
};
|
||||
};
|
||||
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue