2023-10-07 10:57:35 +00:00
|
|
|
use getopt;
|
2023-02-10 09:13:30 +00:00
|
|
|
use io;
|
2023-02-10 13:09:23 +00:00
|
|
|
use log;
|
2023-02-10 09:13:30 +00:00
|
|
|
use net::dial;
|
2023-02-09 19:54:21 +00:00
|
|
|
use net::http;
|
|
|
|
use net::uri;
|
|
|
|
use os;
|
2023-10-07 10:57:35 +00:00
|
|
|
use strings;
|
2023-02-09 19:54:21 +00:00
|
|
|
|
2023-10-08 09:14:26 +00:00
|
|
|
const usage: [_]getopt::help = [
|
|
|
|
"HTTP client",
|
|
|
|
('H', "Name:value", "Sets an HTTP header"),
|
2023-10-08 09:23:28 +00:00
|
|
|
('X', "method", "Sets the HTTP method verb"),
|
2023-10-08 09:14:26 +00:00
|
|
|
"url"
|
|
|
|
];
|
|
|
|
|
2023-02-09 19:54:21 +00:00
|
|
|
export fn main() void = {
|
2023-10-07 10:43:58 +00:00
|
|
|
const client = http::newclient("Hare net::http test client");
|
2023-02-09 22:23:05 +00:00
|
|
|
defer http::client_finish(&client);
|
|
|
|
|
2023-10-08 09:14:26 +00:00
|
|
|
const cmd = getopt::parse(os::args, usage...);
|
2023-10-07 10:57:35 +00:00
|
|
|
defer getopt::finish(&cmd);
|
|
|
|
|
2023-10-08 09:14:26 +00:00
|
|
|
if (len(cmd.args) != 1) {
|
|
|
|
getopt::printusage(os::stderr, "http", usage)!;
|
|
|
|
os::exit(os::status::FAILURE);
|
|
|
|
};
|
|
|
|
|
|
|
|
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(&targ);
|
|
|
|
|
|
|
|
let req = http::new_request(&client, "GET", &targ)!;
|
2023-10-07 10:57:35 +00:00
|
|
|
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, ":");
|
2023-10-08 09:14:26 +00:00
|
|
|
http::header_add(&req.header, name, val);
|
2023-10-08 09:23:28 +00:00
|
|
|
case 'X' =>
|
|
|
|
req.method = val;
|
2023-10-07 10:57:35 +00:00
|
|
|
case => abort();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-10-08 09:14:26 +00:00
|
|
|
const resp = match (http::do(&client, &req)) {
|
2023-02-10 09:13:30 +00:00
|
|
|
case let err: http::error =>
|
2023-02-10 13:09:23 +00:00
|
|
|
log::fatal("HTTP error:", http::strerror(err));
|
2023-02-10 09:13:30 +00:00
|
|
|
case let resp: http::response =>
|
|
|
|
yield resp;
|
|
|
|
};
|
2023-02-10 13:18:01 +00:00
|
|
|
defer http::response_finish(&resp);
|
2023-02-10 09:13:30 +00:00
|
|
|
|
2023-02-10 13:09:23 +00:00
|
|
|
log::printfln("HTTP/{}.{}: {} {}",
|
|
|
|
resp.version.0, resp.version.1,
|
|
|
|
resp.status, resp.reason);
|
|
|
|
|
|
|
|
for (let i = 0z; i < len(resp.header); i += 1) {
|
|
|
|
const (name, val) = resp.header[i];
|
|
|
|
log::printfln("{}: {}", name, val);
|
|
|
|
};
|
|
|
|
|
2023-10-08 09:23:28 +00:00
|
|
|
const body = match (resp.body) {
|
|
|
|
case let st: *io::stream =>
|
|
|
|
yield st;
|
|
|
|
case null =>
|
|
|
|
return;
|
|
|
|
};
|
2023-02-10 09:13:30 +00:00
|
|
|
io::copy(os::stdout, body)!;
|
2023-10-07 10:43:58 +00:00
|
|
|
io::close(body)!;
|
2023-02-09 19:54:21 +00:00
|
|
|
};
|