Skip to content

Instantly share code, notes, and snippets.

@niansa
Created July 25, 2021 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niansa/1cd2b593471a377bf7b3a54c10039606 to your computer and use it in GitHub Desktop.
Save niansa/1cd2b593471a377bf7b3a54c10039606 to your computer and use it in GitHub Desktop.
class HttpClient {
std::shared_ptr<coro::io_scheduler> scheduler;
coro::net::ip_address addr;
std::string host;
uint16_t port = 80;
std::chrono::milliseconds timeout = std::chrono::milliseconds(5000);
public:
HttpClient(std::weak_ptr<coro::io_scheduler> sched) : scheduler(sched) {}
void set_addr(const std::string& addrStr) {
addr = coro::net::ip_address::from_string(addrStr);
}
void set_addr(const coro::net::ip_address& addr) {
this->addr = addr;
}
coro::generator<bool> set_host(const std::string& host) {
this->host = host;
// Resolve host
coro::net::dns_resolver resolver(scheduler, timeout);
auto ips = (co_await resolver.host_by_name(coro::net::hostname(host)))->ip_addresses();
if (ips.empty()) {
co_return false;
} else {
addr = ips[0];
co_return true;
}
}
void set_port(uint16_t port) {
this->port = port;
}
void set_timeout(std::chrono::milliseconds timeout) {
this->timeout = timeout;
}
void set_timeout(time_t timeout) {
this->timeout = std::chrono::milliseconds(timeout);
}
coro::generator<std::span<const char>> send(std::string_view path, std::function<coro::task<bool> (std::span<const char>)> cb) {
co_await scheduler->schedule();
// Connect
coro::net::tcp_client client{scheduler, {
.address = {addr},
.port = port
}
};
std::cout << addr.to_string() << std::endl;
co_await client.connect(timeout);
if (!client.socket().is_valid()) {
co_return;
}
// Build request
std::string reqStr;
{
std::ostringstream req;
req << "GET " << path << " HTTP/1.1\n"
"Host: " << (host.empty()?addr.to_string():host) << "\n\n";
reqStr = req.str();
}
// Send Request
std::span<const char> remaining = reqStr;
while (true) {
auto [send_status, r] = client.send(remaining);
if (send_status != coro::net::send_status::ok) {
co_return;
}
if (r.empty()) {
break;
}
remaining = r;
auto pstatus = co_await client.poll(coro::poll_op::write, timeout);
if (pstatus != coro::poll_status::event) {
co_return;
}
}
// Receive response
std::vector<char> response(256);
while (true) {
co_await client.poll(coro::poll_op::read, timeout);
auto [recv_status, recv_bytes] = client.recv(response);
if (recv_status != coro::net::recv_status::ok) {
co_return; // Connection closed
} else {
co_yield recv_bytes;
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment