net::http: export new_request{,_body}
This commit is contained in:
parent
380d174beb
commit
2acf7fa873
|
@ -7,37 +7,44 @@ use net::uri;
|
|||
use os;
|
||||
use strings;
|
||||
|
||||
const usage: [_]getopt::help = [
|
||||
"HTTP client",
|
||||
('H', "Name:value", "Sets an HTTP header"),
|
||||
"url"
|
||||
];
|
||||
|
||||
export fn main() void = {
|
||||
const client = http::newclient("Hare net::http test client");
|
||||
defer http::client_finish(&client);
|
||||
|
||||
const cmd = getopt::parse(os::args,
|
||||
"HTTP client",
|
||||
('H', "Name:value", "Sets an HTTP header"),
|
||||
"url");
|
||||
const cmd = getopt::parse(os::args, usage...);
|
||||
defer getopt::finish(&cmd);
|
||||
|
||||
let head = http::client_default_header(&client);
|
||||
for (let i = 0z; i < len(cmd.opts); i += 1) {
|
||||
const (opt, val) = cmd.opts[i];
|
||||
switch (opt) {
|
||||
case 'H' =>
|
||||
const (name, val) = strings::cut(val, ":");
|
||||
http::header_add(head, name, val);
|
||||
case => abort();
|
||||
};
|
||||
if (len(cmd.args) != 1) {
|
||||
getopt::printusage(os::stderr, "http", usage)!;
|
||||
os::exit(os::status::FAILURE);
|
||||
};
|
||||
|
||||
const target = cmd.args[0];
|
||||
const target = match (uri::parse(target)) {
|
||||
const targ = match (uri::parse(cmd.args[0])) {
|
||||
case let u: uri::uri =>
|
||||
yield u;
|
||||
case uri::invalid =>
|
||||
log::fatal("Invalid URI");
|
||||
};
|
||||
defer uri::finish(&target);
|
||||
defer uri::finish(&targ);
|
||||
|
||||
const resp = match (http::get(&client, &target)) {
|
||||
let req = http::new_request(&client, "GET", &targ)!;
|
||||
for (let i = 0z; i < len(cmd.opts); i += 1) {
|
||||
const (opt, val) = cmd.opts[i];
|
||||
switch (opt) {
|
||||
case 'H' =>
|
||||
const (name, val) = strings::cut(val, ":");
|
||||
http::header_add(&req.header, name, val);
|
||||
case => abort();
|
||||
};
|
||||
};
|
||||
|
||||
const resp = match (http::do(&client, &req)) {
|
||||
case let err: http::error =>
|
||||
log::fatal("HTTP error:", http::strerror(err));
|
||||
case let resp: http::response =>
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
use errors;
|
||||
use fmt;
|
||||
use io;
|
||||
use net::ip;
|
||||
use net::uri;
|
||||
use strconv;
|
||||
use strings;
|
||||
|
||||
export type client = struct {
|
||||
default_header: header,
|
||||
|
@ -44,76 +39,6 @@ export fn client_default_transport(client: *client) *transport = {
|
|||
return &client.default_transport;
|
||||
};
|
||||
|
||||
fn new_request(
|
||||
client: *client,
|
||||
method: str,
|
||||
target: *uri::uri,
|
||||
) (request | errors::unsupported) = {
|
||||
let req = request {
|
||||
method = method,
|
||||
target = alloc(uri::dup(target)),
|
||||
header = header_dup(&client.default_header),
|
||||
transport = null,
|
||||
body = void,
|
||||
};
|
||||
switch (req.target.scheme) {
|
||||
case "http" =>
|
||||
if (req.target.port == 0) {
|
||||
req.target.port = 80;
|
||||
};
|
||||
case "https" =>
|
||||
if (req.target.port == 0) {
|
||||
req.target.port = 443;
|
||||
};
|
||||
case =>
|
||||
return errors::unsupported;
|
||||
};
|
||||
|
||||
let host = match (req.target.host) {
|
||||
case let host: str =>
|
||||
yield host;
|
||||
case let ip: ip::addr4 =>
|
||||
yield ip::string(ip);
|
||||
case let ip: ip::addr6 =>
|
||||
static let buf: [64 + 2]u8 = [0...];
|
||||
yield fmt::bsprintf(buf, "[{}]", ip::string(ip));
|
||||
};
|
||||
|
||||
if (req.target.scheme == "http" && req.target.port != 80) {
|
||||
host = fmt::asprintf("{}:{}", host, req.target.port);
|
||||
} else if (target.scheme == "https" && target.port != 443) {
|
||||
host = fmt::asprintf("{}:{}", host, req.target.port);
|
||||
} else {
|
||||
host = strings::dup(host);
|
||||
};
|
||||
defer free(host);
|
||||
header_add(&req.header, "Host", host);
|
||||
|
||||
return req;
|
||||
};
|
||||
|
||||
fn new_request_body(
|
||||
client: *client,
|
||||
method: str,
|
||||
target: *uri::uri,
|
||||
body: io::handle,
|
||||
) (request | errors::unsupported) = {
|
||||
let req = new_request(client, method, target)?;
|
||||
req.body = body;
|
||||
|
||||
const offs = match (io::seek(body, 0, io::whence::CUR)) {
|
||||
case let off: io::off =>
|
||||
yield off;
|
||||
case io::error =>
|
||||
header_add(&req.header, "Transfer-Encoding", "chunked");
|
||||
return req;
|
||||
};
|
||||
const ln = io::seek(body, 0, io::whence::END)!;
|
||||
io::seek(body, offs, io::whence::SET)!;
|
||||
header_add(&req.header, "Content-Length", strconv::ztos(ln: size));
|
||||
return req;
|
||||
};
|
||||
|
||||
fn uri_origin_form(target: *uri::uri) uri::uri = {
|
||||
let target = *target;
|
||||
target.scheme = "";
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
use errors;
|
||||
use fmt;
|
||||
use io;
|
||||
use net::ip;
|
||||
use net::uri;
|
||||
use strconv;
|
||||
use strings;
|
||||
|
||||
// Stores state related to an HTTP request.
|
||||
//
|
||||
|
@ -33,3 +38,78 @@ export fn request_finish(req: *request) void = {
|
|||
uri::finish(req.target);
|
||||
free(req.target);
|
||||
};
|
||||
|
||||
// Creates a new HTTP [[request]] using the given HTTP [[client]] defaults.
|
||||
export fn new_request(
|
||||
client: *client,
|
||||
method: str,
|
||||
target: *uri::uri,
|
||||
) (request | errors::unsupported) = {
|
||||
let req = request {
|
||||
method = method,
|
||||
target = alloc(uri::dup(target)),
|
||||
header = header_dup(&client.default_header),
|
||||
transport = null,
|
||||
body = void,
|
||||
};
|
||||
switch (req.target.scheme) {
|
||||
case "http" =>
|
||||
if (req.target.port == 0) {
|
||||
req.target.port = 80;
|
||||
};
|
||||
case "https" =>
|
||||
if (req.target.port == 0) {
|
||||
req.target.port = 443;
|
||||
};
|
||||
case =>
|
||||
return errors::unsupported;
|
||||
};
|
||||
|
||||
let host = match (req.target.host) {
|
||||
case let host: str =>
|
||||
yield host;
|
||||
case let ip: ip::addr4 =>
|
||||
yield ip::string(ip);
|
||||
case let ip: ip::addr6 =>
|
||||
static let buf: [64 + 2]u8 = [0...];
|
||||
yield fmt::bsprintf(buf, "[{}]", ip::string(ip));
|
||||
};
|
||||
|
||||
if (req.target.scheme == "http" && req.target.port != 80) {
|
||||
host = fmt::asprintf("{}:{}", host, req.target.port);
|
||||
} else if (target.scheme == "https" && target.port != 443) {
|
||||
host = fmt::asprintf("{}:{}", host, req.target.port);
|
||||
} else {
|
||||
host = strings::dup(host);
|
||||
};
|
||||
defer free(host);
|
||||
header_add(&req.header, "Host", host);
|
||||
return req;
|
||||
};
|
||||
|
||||
// Creates a new HTTP [[request]] using the given HTTP [[client]] defaults and
|
||||
// the provided request body.
|
||||
//
|
||||
// If the provided I/O handle is seekable, the Content-Length header is added
|
||||
// automatically. Otherwise, Transfer-Encoding: chunked will be used.
|
||||
export fn new_request_body(
|
||||
client: *client,
|
||||
method: str,
|
||||
target: *uri::uri,
|
||||
body: io::handle,
|
||||
) (request | errors::unsupported) = {
|
||||
let req = new_request(client, method, target)?;
|
||||
req.body = body;
|
||||
|
||||
const offs = match (io::seek(body, 0, io::whence::CUR)) {
|
||||
case let off: io::off =>
|
||||
yield off;
|
||||
case io::error =>
|
||||
header_add(&req.header, "Transfer-Encoding", "chunked");
|
||||
return req;
|
||||
};
|
||||
const ln = io::seek(body, 0, io::whence::END)!;
|
||||
io::seek(body, offs, io::whence::SET)!;
|
||||
header_add(&req.header, "Content-Length", strconv::ztos(ln: size));
|
||||
return req;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue