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 )