diff --git a/cmd/http/main.ha b/cmd/http/main.ha index ee5005c..c7de44e 100644 --- a/cmd/http/main.ha +++ b/cmd/http/main.ha @@ -17,14 +17,13 @@ export fn main() void = { }; defer uri::finish(&target); - const req = http::get(&client, &target); - const resp = match (http::do(&client, &req)) { + const resp = match (http::get(&client, &target)) { case let err: http::error => log::fatal("HTTP error:", http::strerror(err)); case let resp: http::response => yield resp; }; - defer http::request_finish(&req); + defer http::response_finish(&resp); log::printfln("HTTP/{}.{}: {} {}", resp.version.0, resp.version.1, diff --git a/net/http/client.ha b/net/http/client.ha index ec138e1..338a077 100644 --- a/net/http/client.ha +++ b/net/http/client.ha @@ -33,7 +33,7 @@ fn new_request(client: *client, method: str, target: *uri::uri) request = { let req = request { method = method, target = alloc(uri::dup(target)), - header = alloc(client.default_header...), + header = header_dup(&client.default_header), body = void, }; if (req.target.port == 0) { @@ -62,8 +62,8 @@ fn new_request(client: *client, method: str, target: *uri::uri) request = { } else { host = strings::dup(host); }; - - append(req.header, ("Host", host)); + defer free(host); + add_header(&req.header, "Host", host); return req; }; @@ -105,52 +105,44 @@ fn uri_origin_form(target: *uri::uri) uri::uri = { return target; }; -// Prepares a new HTTP GET request for the given client and fills in the default -// headers, such as User-Agent and Host. Provide the return value to [[do]] to -// execute the request and free associated resources, or use [[request_finish]] -// to free resources without executing the request. -// -// The URI parameter is borrowed from the caller for the lifetime of the request -// object. -export fn get(client: *client, target: *uri::uri) request = { - return new_request(client, GET, target); +// Performs a synchronous HTTP GET request with the given client. +export fn get(client: *client, target: *uri::uri) (response | error) = { + const req = new_request(client, GET, target); + defer request_finish(&req); + return do(client, &req); }; -// Prepares a new HTTP HEAD request for the given client and fills in the -// default headers, such as User-Agent and Host. Provide the return value to -// [[do]] to execute the request and free associated resources, or use -// [[request_finish]] to free resources without executing the request. -// -// The URI parameter is borrowed from the caller for the lifetime of the request -// object. -export fn head(client: *client, target: *uri::uri) request = { - return new_request(client, HEAD, target); +// Performs a synchronous HTTP HEAD request with the given client. +export fn head(client: *client, target: *uri::uri) (response | error) = { + const req = new_request(client, HEAD, target); + defer request_finish(&req); + return do(client, &req); }; -// Prepares a new HTTP POST request for the given client and fills in the -// default headers, such as User-Agent and Host. Provide the return value to -// [[do]] to execute the request and free associated resources, or use -// [[request_finish]] to free resources without executing the request. +// Performs a synchronous HTTP POST request with the given client. // // If the provided I/O handle is seekable, the Content-Length header is added // automatically. Otherwise, Transfer-Encoding: chunked will be used. -// -// The URI parameter is borrowed from the caller for the lifetime of the request -// object. -export fn post(client: *client, target: *uri::uri, body: io::handle) request = { - return new_request_body(client, POST, target, body); +export fn post( + client: *client, + target: *uri::uri, + body: io::handle, +) (response | error) = { + const req = new_request_body(client, POST, target, body); + defer request_finish(&req); + return do(client, &req); }; -// Prepares a new HTTP PUT request for the given client and fills in the -// default headers, such as User-Agent and Host. Provide the return value to -// [[do]] to execute the request and free associated resources, or use -// [[request_finish]] to free resources without executing the request. +// Performs a synchronous HTTP PUT request with the given client. // // If the provided I/O handle is seekable, the Content-Length header is added // automatically. Otherwise, Transfer-Encoding: chunked will be used. -// -// The URI parameter is borrowed from the caller for the lifetime of the request -// object. -export fn put(client: *client, target: *uri::uri, body: io::handle) request = { - return new_request_body(client, POST, target, body); +export fn put( + client: *client, + target: *uri::uri, + body: io::handle, +) (response | error) = { + const req = new_request_body(client, PUT, target, body); + defer request_finish(&req); + return do(client, &req); }; diff --git a/net/http/header.ha b/net/http/header.ha index f973c7a..a690399 100644 --- a/net/http/header.ha +++ b/net/http/header.ha @@ -6,6 +6,7 @@ use strings; // List of HTTP headers. // TODO: [](str, []str) +// s/add_header/header_add/ et al export type header = [](str, str); // Adds a given HTTP header, which may be added more than once. The name should @@ -43,6 +44,16 @@ export fn header_free(head: *header) void = { free(*head); }; +// Duplicates a set of HTTP headers. +export fn header_dup(head: *header) header = { + let new: header = []; + for (let i = 0z; i < len(head); i += 1) { + const (key, val) = head[i]; + add_header(&new, key, val); + }; + return new; +}; + // Writes a list of HTTP headers to the provided I/O handle in the HTTP wire // format. export fn write_header(sink: io::handle, head: *header) (size | io::error) = {