41#ifdef USE_ASYNC_RESOLVE
68#ifdef VPN_BINDING_PROFILES
69#ifdef USE_ASYNC_RESOLVE
70#error VPN_BINDING_PROFILES and USE_ASYNC_RESOLVE cannot be used together
73#include <openvpn/dns/dnscli.hpp>
76#ifdef SIMULATE_HTTPCLI_FAILURES
78#include <openvpn/common/periodic_fail.hpp>
81#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING)
82#include <openvpn/asio/alt_routing.hpp>
85#if defined(OPENVPN_PLATFORM_WIN)
126 static const char *error_names[] = {
143 "E_KEEPALIVE_TIMEOUT",
150 static_assert(
N_ERRORS ==
array_size(error_names),
"HTTP error names array inconsistency");
151 if (status >= 0 && status <
N_ERRORS)
152 return error_names[status];
153 else if (status == -1)
174#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
175struct AltRoutingShimFactory :
public RC<thread_unsafe_refcount>
179 virtual AltRouting::Shim::Ptr shim(
const Host &
host) = 0;
180 virtual void report_error(
const Host &
host,
const bool alt_routing)
183 virtual bool is_reset(
const Host &
host,
const bool alt_routing)
187 virtual int connect_timeout()
191 virtual IP::Addr remote_ip()
195 virtual std::vector<IP::Addr> local_addrs()
197 return std::vector<IP::Addr>();
199 virtual int remote_port()
203 virtual int alt_routing_debug_level()
231#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
232 AltRoutingShimFactory::Ptr shim_factory;
249#ifdef VPN_BINDING_PROFILES
350#ifdef USE_ASYNC_RESOLVE
359#ifndef USE_ASYNC_RESOLVE
370 :
Base(std::move(config_arg)),
371#ifdef USE_ASYNC_RESOLVE
375#ifndef USE_ASYNC_RESOLVE
392 to = std::move(to_arg);
409#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
421 throw http_client_exception(
"not ready");
430 { self->handle_request(); });
441 req_timer->async_wait([self =
Ptr(
this)](
const openvpn_io::error_code &error)
444 self->handle_request(); });
464#ifdef USE_ASYNC_RESOLVE
465 async_resolve_cancel();
469#ifdef VPN_BINDING_PROFILES
497 return socket->remote_endpoint_str();
499 catch (
const std::exception &)
502 return "[unknown endpoint]";
565 throw http_client_exception(
"streaming_restart() called when content-out is still in hold state");
614 virtual void http_done(
const int status,
const std::string &description) = 0;
631 throw http_client_exception(
"frame undefined");
634#ifdef SIMULATE_HTTPCLI_FAILURES
635 bool inject_fault(
const char *caller)
637 if (periodic_fail.trigger(
"httpcli", SIMULATE_HTTPCLI_FAILURES))
661 self->general_timeout_handler(error); });
679 throw http_client_exception(
"handle_request called in ready state");
695#ifdef VPN_BINDING_PROFILES
697 Json::Value via_vpn_conf;
699 via_vpn_conf =
host.via_vpn->client_update_host(
host);
702#ifdef ASIO_HAS_LOCAL_SOCKETS
707 AsioPolySock::Unix *s =
new AsioPolySock::Unix(
io_context, 0);
709 s->socket.async_connect(ep,
710 [self =
Ptr(
this)](
const openvpn_io::error_code &error)
712 self->handle_unix_connect(error);
718#ifdef OPENVPN_PLATFORM_WIN
723 const HANDLE h = ::CreateFileA(
725 GENERIC_READ | GENERIC_WRITE,
729 FILE_FLAG_OVERLAPPED,
734 OPENVPN_THROW(http_client_exception,
"failed to open existing named pipe: " << ht <<
" : " << err.message());
742#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING)
746 AltRouting::Shim::Ptr shim =
config->shim_factory->shim(
host);
749 alt_routing_connect(std::move(shim));
777#ifdef USE_ASYNC_RESOLVE
780#ifdef VPN_BINDING_PROFILES
783 DNSClient::ResolverList::Ptr resolver_list(
new DNSClient::ResolverList(via_vpn_conf));
784 alt_resolve = DNSClient::async_resolve(
io_context,
785 std::move(resolver_list),
789 [self =
Ptr(
this)](
const openvpn_io::error_code &error,
791 { self->resolve_callback(error, std::move(results)); });
797 [self =
Ptr(
this)](
const openvpn_io::error_code &error,
799 { self->resolve_callback(error, std::move(results)); });
804 catch (
const std::exception &e)
816#ifdef SIMULATE_HTTPCLI_FAILURES
817 if (inject_fault(
"resolve_callback"))
837 if (
config->debug_level >= 2)
840 openvpn_io::async_connect(s->
socket,
842 [self =
Ptr(
this)](
const openvpn_io::error_code &error_,
const openvpn_io::ip::tcp::endpoint &endpoint)
843 { self->handle_tcp_connect(error_, endpoint); });
845 catch (
const std::exception &e)
852 const openvpn_io::ip::tcp::endpoint &endpoint)
857#ifdef SIMULATE_HTTPCLI_FAILURES
858 if (inject_fault(
"handle_tcp_connect"))
872 catch (
const std::exception &e)
878#ifdef ASIO_HAS_LOCAL_SOCKETS
879 void handle_unix_connect(
const openvpn_io::error_code &error)
884#ifdef SIMULATE_HTTPCLI_FAILURES
885 if (inject_fault(
"handle_unix_connect"))
899 catch (
const std::exception &e)
906#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING)
907 void alt_routing_connect(AltRouting::Shim::Ptr shim)
909 AltRoutingShimFactory &sf = *
config->shim_factory;
912 AsioPolySock::TCP *s =
new AsioPolySock::TCP(
io_context, 0);
916 const std::vector<IP::Addr> local_addrs = sf.local_addrs();
917 for (
const auto &la : local_addrs)
918 s->
socket.bind_local(la, 0);
921 s->socket.shim = std::move(shim);
924 int port = sf.remote_port();
927 IP::Addr addr = sf.remote_ip();
931 results_type results = results_type::create(openvpn_io::ip::tcp::endpoint(addr.to_asio(),
932 static_cast<asio::ip::port_type
>(
port)),
936 if (sf.alt_routing_debug_level() >= 2)
940 openvpn_io::async_connect(s->socket,
942 [self =
Ptr(
this)](
const openvpn_io::error_code &error,
const openvpn_io::ip::tcp::endpoint &endpoint)
943 { self->handle_tcp_connect(error, endpoint); });
947 int ct = sf.connect_timeout();
949 ct =
config->connect_timeout;
971 link->set_raw_mode(
true);
984 if (
config->connect_timeout)
992 self->connect_timeout_handler(error); });
1001#if defined(OPENVPN_POLYSOCK_SUPPORTS_BIND) || defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING)
1003 unsigned short local_port = 0;
1006 s->
socket.bind_local(local_addr, local_port);
1012 throw Exception(
"local bind addresses having the same IP version don't make sense: " + local_addr.
to_string() +
' ' + local_addr_alt.
to_string());
1013 s->
socket.bind_local(local_addr_alt, local_port);
1016 throw Exception(
"httpcli must be built with OPENVPN_POLYSOCK_SUPPORTS_BIND or OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING to support local bind");
1025 const Time::Duration dur = Time::Duration::seconds(
to.
keepalive >= 0
1027 :
config->keepalive_timeout);
1033 if (!self->halt && !error && self->ready)
1047 const bool register_activity_on_input_only_arg)
1109 os << req.
method <<
' ' << req.
uri <<
" HTTP/1.1\r\n";
1113 if (!
config->user_agent.empty())
1114 os <<
"User-Agent: " <<
config->user_agent <<
"\r\n";
1120 os <<
"Content-Length: " <<
content_info.length <<
"\r\n";
1122 os <<
"Transfer-Encoding: chunked"
1127 os <<
"Content-Encoding: " <<
content_info.content_encoding <<
"\r\n";
1129 os <<
"Connection: keep-alive\r\n";
1131 os <<
"Accept: */*\r\n";
1137 os << req.
method <<
' ' << req.
uri <<
" HTTP/1.1\r\n";
1139 if (!
config->user_agent.empty())
1140 os <<
"User-Agent: " <<
config->user_agent <<
"\r\n";
1154 os <<
"Authorization: Basic "
1163 error_handler(errcode, std::string(
"HTTPCore Asio ") + func_name +
": " + error.message());
1173 const bool in_transaction = !
ready;
1174 const bool keepalive =
alive;
1176#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING)
1177 if (
config->shim_factory && error && in_transaction &&
socket)
1196#ifdef SIMULATE_HTTPCLI_FAILURES
1197 if (inject_fault(
"tcp_read_handler"))
1204 catch (
const std::exception &e)
1220 catch (
const std::exception &e)
1236 catch (
const std::exception &e)
1288#ifdef SIMULATE_HTTPCLI_FAILURES
1289 if (inject_fault(
"base_link_send"))
1297 return link->send(buf);
1299 catch (
const std::exception &e)
1311 return link->send_queue_empty();
1315 const bool parent_handoff)
1355 std::ostringstream os;
1390 unsigned int &keepalive_timeout)
override
1405#ifndef USE_ASYNC_RESOLVE
1408#ifdef VPN_BINDING_PROFILES
1409 DNSClient::Context::Ptr alt_resolve;
1429#ifdef SIMULATE_HTTPCLI_FAILURES
1430 PeriodicFail periodic_fail;
1434template <
typename PARENT>
1455 void detach(
const bool keepalive,
const bool shutdown)
1473 return parent_->http_host(*
this);
1475 throw http_delegate_error(
"http_host");
1481 return parent_->http_request(*
this);
1483 throw http_delegate_error(
"http_request");
1489 return parent_->http_content_info(*
this);
1491 throw http_delegate_error(
"http_content_info");
1497 return parent_->http_content_out(*
this);
1499 throw http_delegate_error(
"http_content_out");
1505 parent_->http_content_out_needed(*
this);
1507 throw http_delegate_error(
"http_content_out_needed");
1513 parent_->http_headers_received(*
this);
1519 parent_->http_headers_sent(*
this, buf);
1525 parent_->http_mutate_resolver_results(*
this, results);
1531 parent_->http_content_in(*
this, buf);
1534 void http_done(
const int status,
const std::string &description)
override
1537 parent_->http_done(*
this, status, description);
1543 parent_->http_keepalive_close(*
this, status, description);
1549 parent_->http_post_connect(*
this, sock);
std::size_t expires_at(const Time &t)
std::size_t expires_after(const Time::Duration &d)
void async_wait(F &&func)
std::string encode(const V &data) const
bool similar(const Time &t) const
void reset(const Time &t)
std::string to_string() const
Reference count base class for objects tracked by RCPtr. Allows copying and assignment.
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
virtual void start_handshake()=0
LinkCommon< Protocol, ReadHandler, RAW_MODE_ONLY > Base
void start_request_after(const Time::Duration dur)
void transport_needs_send() override
void handle_tcp_connect(const openvpn_io::error_code &error, const openvpn_io::ip::tcp::endpoint &endpoint)
void stop(const bool shutdown)
openvpn_io::io_context & io_context
virtual void http_content_in(BufferAllocated &buf)=0
virtual Host http_host()=0
HTTPCore(openvpn_io::io_context &io_context_arg, Config::Ptr config_arg)
bool is_streaming_hold() const
virtual void http_headers_sent(const Buffer &buf)
openvpn_io::ip::tcp::resolver::results_type results_type
virtual void http_post_connect(AsioPolySock::Base &sock)
void override_timeouts(TimeoutOverride to_arg)
void transport_error(const Error::Type fatal_err, const std::string &err_text) override
openvpn_io::ip::tcp::resolver resolver
void base_http_content_out_needed()
std::string err_fmt(const Error::Type fatal_err, const std::string &err_text)
AsioTimerSafe general_timer
bool is_streaming_restartable() const
void set_connect_timeout(unsigned int connect_timeout)
BufferPtr base_http_content_out()
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout) override
void schedule_keepalive_timer()
void base_http_content_in(BufferAllocated &buf)
void base_error_handler(const int errcode, const std::string &err)
void reset_general_timeout(const unsigned int seconds, const bool register_activity_on_input_only_arg)
void tcp_write_queue_needs_send()
virtual Request http_request()=0
void transport_recv(BufferAllocated &buf) override
bool is_keepalive_enabled() const override
TCPTransport::TCPLink< AsioProtocol, HTTPCore *, false > LinkImpl
void generate_basic_auth_headers(std::ostream &os, const Request &req)
void connect_timeout_handler(const openvpn_io::error_code &e)
void base_http_done_handler(BufferAllocated &residual, const bool parent_handoff)
virtual void http_content_out_needed()
void general_timeout_handler(const openvpn_io::error_code &e)
bool remote_ip_port(IP::Addr &addr, unsigned int &port) const
void tcp_error_handler(const char *error)
bool tcp_read_handler(BufferAllocated &b)
CoarseTime general_timeout_coarse
void transport_wait_proxy() override
void proxy_error(const Error::Type fatal_err, const std::string &err_text) override
void transport_pre_resolve() override
virtual void http_headers_received()
void handle_exception(const char *func_name, const std::exception &e)
void alter_general_timeout_for_streaming()
void cancel_keepalive_timer()
void bind_local_addr(AsioPolySock::TCP *s)
void asio_error_handler(int errcode, const char *func_name, const openvpn_io::error_code &error)
std::string remote_endpoint_str() const
void error_handler(const int errcode, const std::string &err)
bool host_match(const std::string &host_arg) const
virtual void http_keepalive_close(const int status, const std::string &description)
bool base_http_headers_received()
void activity(const bool init)
virtual void http_mutate_resolver_results(results_type &results)
bool base_link_send(BufferAllocated &buf)
virtual BufferPtr http_content_out()
const HTTP::Reply & reply() const
Time::Duration general_timeout_duration
bool register_activity_on_input_only
AsioTimerSafe connect_timer
void transport_wait() override
TransportClient::Ptr transcli
void generate_request_websocket(std::ostream &os, const Request &req)
virtual void http_done(const int status, const std::string &description)=0
void cancel_general_timeout()
std::unique_ptr< AsioTimerSafe > keepalive_timer
bool is_alt_routing_reset() const
virtual ContentInfo http_content_info()
bool transport_is_openvpn_protocol() override
std::unique_ptr< AsioTimerSafe > req_timer
void do_connect(const bool use_link)
void generate_request_http(std::ostream &os, const Request &req)
AsioPolySock::Base * get_socket()
void resolve_callback(const openvpn_io::error_code &error, results_type results)
void abort(const std::string &message, const int status=Status::E_ABORTED)
AsioPolySock::Base::Ptr socket
void transport_connecting() override
bool base_send_queue_empty()
Host http_host() override
OPENVPN_EXCEPTION(http_delegate_error)
void http_headers_received() override
void http_content_in(BufferAllocated &buf) override
void http_headers_sent(const Buffer &buf) override
void http_done(const int status, const std::string &description) override
void http_post_connect(AsioPolySock::Base &sock) override
BufferPtr http_content_out() override
RCPtr< HTTPDelegate > Ptr
void detach(const bool keepalive, const bool shutdown)
ContentInfo http_content_info() override
void http_mutate_resolver_results(results_type &results) override
HTTPDelegate(openvpn_io::io_context &io_context, WS::Client::Config::Ptr config, PARENT *parent)
Request http_request() override
void http_content_out_needed() override
void attach(PARENT *parent)
void http_keepalive_close(const int status, const std::string &description) override
void tcp_in(BufferAllocated &b)
CONTENT_INFO content_info
const REQUEST_REPLY::State & request_reply() const
#define OPENVPN_THROW_EXCEPTION(stuff)
#define OPENVPN_EXCEPTION(C)
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_LOG(args)
const char * name(const size_t type)
unsigned short parse_port(const std::string &port, const std::string &title)
HTTPBase< HTTPCore, Config, Status, HTTP::ReplyType, ContentInfo, olong, RC< thread_unsafe_refcount > > Base
bool defined(HANDLE handle)
std::string to_string(T value)
constexpr std::size_t array_size(T(&)[N])
std::string asio_resolver_results_to_string(const EPRANGE &endpoint_range)
RCPtr< BufferAllocatedRc > BufferPtr
Implementation of the base classes for random number generators.
openvpn_io::ip::tcp::socket socket
std::string remote_endpoint_str() const override
@ GROW
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
virtual void transport_start()=0
virtual bool transport_send_queue_empty()=0
virtual bool transport_send(BufferAllocated &buf)=0
unsigned int websocket_timeout
SSLFactoryAPI::Ptr ssl_factory
unsigned int keepalive_timeout
unsigned int max_header_bytes
TransportClientFactory::Ptr transcli
unsigned int general_timeout
unsigned int msg_overhead_bytes
unsigned int connect_timeout
WebSocket::Client::PerRequest::Ptr websocket
std::vector< std::string > extra_headers
static constexpr olong CHUNKED
std::string content_encoding
AsioPolySock::Base socket
std::string cache_key() const
const std::string & host_head() const
std::string host_port_str() const
const std::string & host_cn() const
const std::string * host_cn_ptr() const
std::string local_addr_alt
const std::string & host_transport() const
bool creds_defined() const
void set_creds(const Creds &creds)
static bool is_error(const int status)
static std::string error_str(const int status)