UniEvent-HTTP
view release on metacpan or search on metacpan
clib/src/panda/unievent/http/Client.cc view on Meta::CPAN
}
void Client::request (const RequestSP& request) {
if (_request) throw HttpError("client supports only one request at a time");
if (request->_client) throw HttpError("request is already in progress");
request->check();
panda_log_info("request:\n" << request->to_string());
request->_client = this;
if (!request->uri->scheme()) request->uri->scheme("http");
auto netloc = request->netloc();
if (!connected() || _netloc != netloc || !request->keep_alive()) {
panda_log_info("connecting to " << netloc);
if (connected()) drop_connection();
filters().clear();
if (request->uri->secure()) {
SslContext ctx = request->ssl_ctx;
if (!ctx) {
ctx = get_default_ssl_context(request->ssl_check_cert);
}
Tcp::use_ssl(ctx);
auto ssl = Tcp::get_ssl();
SSL_set_tlsext_host_name(ssl, request->uri->host().c_str());
if (request->ssl_check_cert) {
string host = request->uri->host();
auto param = SSL_get0_param(ssl);
X509_VERIFY_PARAM_set1_host(param, host.data(), host.size());
}
}
if (request->proxy) {
auto uri = request->proxy;
if (uri->scheme() == "socks5") {
SocksSP socks = new Socks(uri->host(), uri->port(), uri->user(), uri->password());
socks->socks_resolve = request->proxy_resolve;
use_socks(this, socks);
}
else if (uri->scheme() == "http") {
// netloc = NetLoc { uri->host(), uri->port(), nullptr, nullptr, false };
// no-op
}
else throw HttpError("client supports only socks5 protocol for proxy");
}
if (request->tcp_nodelay) set_nodelay(true);
_netloc = std::move(netloc);
auto conn_timeout = request->connect_timeout ? request->connect_timeout : request->timeout;
connect(_netloc.host, _netloc.port, conn_timeout, request->tcp_hints);
}
// this code should be after connect, because in case of connect timeout, timer inside Tcp class must react first to mark multiDNS address as bad
if (request->timeout) request->ensure_timer_active(loop());
Tcp::weak(false);
_request = request;
using namespace panda::protocol::http;
if (request->compression_prefs == static_cast<std::uint8_t>(Compression::IDENTITY) && !request->headers.has("Accept-Encoding")) {
request->allow_compression(Compression::GZIP);
}
auto data = request->to_vector();
_parser.set_context_request(request);
write(data.begin(), data.end());
if (request->form_streaming()) {
_form_field = 0;
send_form();
} else {
if (!request->chunked || request->body.length()) request->_transfer_completed = true;
read_start();
}
}
void Client::send_chunk (const RequestSP& req, const string& chunk) {
assert(_request == req);
if (!chunk) return;
auto v = req->make_chunk(chunk);
write(v.begin(), v.end());
}
void Client::send_final_chunk (const RequestSP& req, const string& chunk) {
assert(_request == req);
req->_transfer_completed = true;
auto v = req->final_chunk(chunk);
write(v.begin(), v.end());
}
void Client::cancel (const ErrorCode& err) {
if (!_request) return;
panda_log_info("cancel with err = " << err);
_parser.reset();
if (_in_redirect) _redirect_canceled = true;
finish_request(err);
}
void Client::on_connect (const ErrorCode& err, const ConnectRequestSP&) {
if (_request && err) cancel(nest_error(errc::connect_error, err));
}
void Client::on_write (const ErrorCode& err, const WriteRequestSP&) {
if (_request && err) cancel(err);
}
void Client::timed_out () {
HOLD_ON(this);
auto err = make_error_code(std::errc::timed_out);
cancel(connecting() ? nest_error(errc::connect_error, err) : err);
}
void Client::on_read (string& buf, const ErrorCode& err) {
if (err) return cancel(err);
panda_log_debug("read (" << buf.size() << " bytes):\n" << buf);
while (buf) {
if (!_parser.context_request()) {
panda_log_notice("unexpected buffer: " << buf);
( run in 1.321 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )