Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/proxy/ProxySession.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class ProxySession : public VConnection, public PluginUserArgs<TS_USER_ARGS_SSN>

IpAllow::ACL acl; ///< IpAllow based method ACL.

HttpSessionAccept::Options const *accept_options{nullptr}; ///< connection info
HttpSessionAcceptBase const *acceptor{nullptr}; ///< Acceptor with the connection properties.

protected:
// Hook dispatching state
Expand Down
57 changes: 44 additions & 13 deletions include/proxy/http/HttpSessionAccept.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include "iocore/net/Net.h"
#include "iocore/net/SessionAccept.h"

#include <memory>
#include <utility>

namespace detail
{
/** Options for @c HttpSessionAccept.
Expand Down Expand Up @@ -154,36 +157,64 @@ HttpSessionAcceptOptions::setSessionProtocolPreference(SessionProtocolSet const
}
} // namespace detail

/**
The continuation mutex is NULL to allow parellel accepts in NT. No
state is recorded by the handler and values are required to be set
during construction via the @c Options struct and never changed. So
a NULL mutex is safe.
/** Common state for protocol-specific HTTP acceptors.
*
* A proxy port can dispatch connections to several HTTP protocol acceptors.
* This base keeps one shared, immutable set of connection properties for all
* of those acceptors and provides access to the complete proxy port. Sessions
* retain a pointer to their acceptor so the properties remain available
* without protocol-specific copies.
*
* The continuation mutex is @c NULL because the acceptors do not mutate their
* shared state after construction.
*/
class HttpSessionAcceptBase : public SessionAccept
{
public:
using Options = detail::HttpSessionAcceptOptions;
using OptionsHandle = std::shared_ptr<Options const>;

HttpSessionAcceptBase(OptionsHandle options, HttpProxyPort *proxy_port = nullptr)
: SessionAccept(nullptr), _options(std::move(options))
{
ink_release_assert(_options != nullptr);
proxyPort = proxy_port;
}

~HttpSessionAcceptBase() override = default;

Most of the state is simply passed on to the @c ClientSession after
an accept. It is done here because this is the least bad pathway
from the top level configuration to the HTTP session.
*/
Options const &
options() const
{
return *_options;
}

class HttpSessionAccept : public SessionAccept, private detail::HttpSessionAcceptOptions
private:
OptionsHandle _options;
};

class HttpSessionAccept : public HttpSessionAcceptBase
{
private:
using self = HttpSessionAccept; ///< Self reference type.
public:
/** Construction options.
Provide an easier to remember typedef for clients.
*/
using Options = detail::HttpSessionAcceptOptions;
using Options = HttpSessionAcceptBase::Options;
using OptionsHandle = HttpSessionAcceptBase::OptionsHandle;

/** Default constructor.
@internal We don't use a static default options object because of
initialization order issues. It is important to pick up data that is read
from the config file and a static is initialized long before that point.
*/
HttpSessionAccept(Options const &opt = Options()) : SessionAccept(nullptr), detail::HttpSessionAcceptOptions(opt) // copy these.
HttpSessionAccept(Options const &opt = Options()) : HttpSessionAccept(std::make_shared<Options>(opt)) {}

HttpSessionAccept(OptionsHandle options, HttpProxyPort *proxy_port = nullptr)
: HttpSessionAcceptBase(std::move(options), proxy_port)
{
SET_HANDLER(&HttpSessionAccept::mainEvent);
return;
}

~HttpSessionAccept() override { return; }
Expand Down
9 changes: 2 additions & 7 deletions include/proxy/http2/Http2SessionAccept.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
#include "tscore/ink_platform.h"
#include "iocore/net/Net.h"

// XXX HttpSessionAccept::Options needs to be refactored and separated from HttpSessionAccept so that
// it can generically apply to all protocol implementations.
#include "proxy/http/HttpSessionAccept.h"

// HTTP/2 Session Accept.
Expand All @@ -38,8 +36,8 @@
//
// CONFIG proxy.config.http.server_ports STRING 80:proto=http2 443:ssl:proto=h2-12

struct Http2SessionAccept : public SessionAccept {
explicit Http2SessionAccept(const HttpSessionAccept::Options &);
struct Http2SessionAccept : public HttpSessionAcceptBase {
explicit Http2SessionAccept(OptionsHandle options, HttpProxyPort *proxy_port = nullptr);
~Http2SessionAccept() override;

bool accept(NetVConnection *, MIOBuffer *, IOBufferReader *) override;
Expand All @@ -48,7 +46,4 @@ struct Http2SessionAccept : public SessionAccept {
// noncopyable
Http2SessionAccept(const Http2SessionAccept &) = delete;
Http2SessionAccept &operator=(const Http2SessionAccept &) = delete;

private:
HttpSessionAccept::Options options;
};
2 changes: 1 addition & 1 deletion include/proxy/http3/Http09App.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Http09Session;
class Http09App : public QUICApplication
{
public:
Http09App(NetVConnection *client_vc, QUICConnection *qc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options);
Http09App(NetVConnection *client_vc, QUICConnection *qc, IpAllow::ACL &&session_acl, HttpSessionAcceptBase const *acceptor);
~Http09App();

void on_stream_open(QUICStream &stream) override;
Expand Down
2 changes: 1 addition & 1 deletion include/proxy/http3/Http3App.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Http3Session;
class Http3App : public QUICApplication
{
public:
Http3App(NetVConnection *client_vc, QUICConnection *qc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options);
Http3App(NetVConnection *client_vc, QUICConnection *qc, IpAllow::ACL &&session_acl, HttpSessionAcceptBase const *acceptor);
virtual ~Http3App();

void on_stream_open(QUICStream &stream) override;
Expand Down
8 changes: 2 additions & 6 deletions include/proxy/http3/Http3SessionAccept.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
#include "tscore/ink_platform.h"
#include "iocore/net/Net.h"

// XXX HttpSessionAccept::Options needs to be refactored and separated from HttpSessionAccept so that
// it can generically apply to all protocol implementations.
#include "proxy/http/HttpSessionAccept.h"

// HTTP/QUIC Session Accept.
Expand All @@ -37,10 +35,10 @@
//
// CONFIG proxy.config.http.server_ports STRING 443:quic

class Http3SessionAccept : public SessionAccept
class Http3SessionAccept : public HttpSessionAcceptBase
{
public:
explicit Http3SessionAccept(const HttpSessionAccept::Options &);
explicit Http3SessionAccept(OptionsHandle options, HttpProxyPort *proxy_port = nullptr);
~Http3SessionAccept();

bool accept(NetVConnection *, MIOBuffer *, IOBufferReader *) override;
Expand All @@ -49,6 +47,4 @@ class Http3SessionAccept : public SessionAccept
private:
Http3SessionAccept(const Http3SessionAccept &);
Http3SessionAccept &operator=(const Http3SessionAccept &);

HttpSessionAccept::Options options;
};
10 changes: 9 additions & 1 deletion src/proxy/ProxyTransaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ DbgCtl dbg_ctl_http_txn{"http_txn"};

extern ClassAllocator<HttpSM> httpSMAllocator;

ProxyTransaction::ProxyTransaction(ProxySession *session) : VConnection(nullptr), _proxy_ssn(session) {}
ProxyTransaction::ProxyTransaction(ProxySession *session) : VConnection(nullptr), _proxy_ssn(session)
{
if (_proxy_ssn != nullptr && _proxy_ssn->acceptor != nullptr) {
upstream_outbound_options = _proxy_ssn->acceptor->options();
}
}

ProxyTransaction::~ProxyTransaction()
{
Expand All @@ -55,6 +60,9 @@ ProxyTransaction::new_transaction(bool from_early_data)
// connection re-use

ink_release_assert(_proxy_ssn != nullptr);
if (_proxy_ssn->acceptor != nullptr) {
upstream_outbound_options = _proxy_ssn->acceptor->options();
}
_sm = THREAD_ALLOC(httpSMAllocator, this_thread());
_sm->init(from_early_data);
HttpTxnDebug("[%" PRId64 "] Starting transaction %d using sm [%" PRId64 "]", _proxy_ssn->connection_id(),
Expand Down
1 change: 0 additions & 1 deletion src/proxy/http/Http1ClientSession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ Http1ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB
_reader = reader ? reader : read_buffer->alloc_reader();

trans.set_reader(_reader);
trans.upstream_outbound_options = *accept_options;

_handle_if_ssl(new_vc);

Expand Down
34 changes: 17 additions & 17 deletions src/proxy/http/HttpProxyServerMain.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,19 +173,19 @@ make_net_accept_options(const HttpProxyPort *port, unsigned nthreads)
static void
MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned nthreads)
{
NetProcessor::AcceptOptions &net_opt = acceptor._net_opt;
HttpSessionAccept::Options accept_opt;
NetProcessor::AcceptOptions &net_opt = acceptor._net_opt;
auto accept_opt = std::make_shared<HttpSessionAccept::Options>();

net_opt = make_net_accept_options(&port, nthreads);

accept_opt.f_outbound_transparent = port.m_outbound_transparent_p;
accept_opt.transport_type = port.m_type;
accept_opt.setHostResPreference(port.m_host_res_preference);
accept_opt.setTransparentPassthrough(port.m_transparent_passthrough);
accept_opt.setSessionProtocolPreference(port.m_session_protocol_preference);
accept_opt->f_outbound_transparent = port.m_outbound_transparent_p;
accept_opt->transport_type = port.m_type;
accept_opt->setHostResPreference(port.m_host_res_preference);
accept_opt->setTransparentPassthrough(port.m_transparent_passthrough);
accept_opt->setSessionProtocolPreference(port.m_session_protocol_preference);

accept_opt.outbound += HttpConfig::m_master.outbound;
accept_opt.outbound += port.m_outbound; // top priority, override master and base options.
accept_opt->outbound += HttpConfig::m_master.outbound;
accept_opt->outbound += port.m_outbound; // top priority, override master and base options.

// OK the way this works is that the fallback for each port is a protocol
// probe acceptor. For SSL ports, we can stack a NPN+ALPN acceptor in front
Expand All @@ -200,12 +200,12 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned
probe->proxy_protocol_ipmap = &HttpConfig::m_master.config_proxy_protocol_ip_addrs;

if (port.m_session_protocol_preference.intersects(HTTP_PROTOCOL_SET)) {
http = new HttpSessionAccept(accept_opt);
http = new HttpSessionAccept(accept_opt, &port);
probe->registerEndpoint(ProtocolProbeSessionAccept::ProtoGroupKey::HTTP, http);
}

if (port.m_session_protocol_preference.intersects(HTTP2_PROTOCOL_SET)) {
probe->registerEndpoint(ProtocolProbeSessionAccept::ProtoGroupKey::HTTP2, new Http2SessionAccept(accept_opt));
probe->registerEndpoint(ProtocolProbeSessionAccept::ProtoGroupKey::HTTP2, new Http2SessionAccept(accept_opt, &port));
}
ProtocolSessionCreateMap.insert({TS_ALPN_PROTOCOL_INDEX_HTTP_1_0, create_h1_server_session});
ProtocolSessionCreateMap.insert({TS_ALPN_PROTOCOL_INDEX_HTTP_1_1, create_h1_server_session});
Expand All @@ -224,9 +224,9 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned
ssl->enableProtocols(port.m_session_protocol_preference);
ssl->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_1_0, http);
ssl->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_1_1, http);
ssl->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, new Http2SessionAccept(accept_opt));
ssl->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, new Http2SessionAccept(accept_opt, &port));
#if TS_USE_QMUX
ssl->registerEndpoint(TS_ALPN_PROTOCOL_H3QX, new Http3SessionAccept(accept_opt));
ssl->registerEndpoint(TS_ALPN_PROTOCOL_H3QX, new Http3SessionAccept(accept_opt, &port));
#endif

SCOPED_MUTEX_LOCK(lock, ssl_plugin_mutex, this_ethread());
Expand All @@ -240,16 +240,16 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned
quic->enableProtocols(port.m_session_protocol_preference);

// HTTP/0.9 over QUIC draft-29 (for interop only, will be removed)
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC_D29, new Http3SessionAccept(accept_opt));
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC_D29, new Http3SessionAccept(accept_opt, &port));

// HTTP/3 draft-29
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3_D29, new Http3SessionAccept(accept_opt));
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3_D29, new Http3SessionAccept(accept_opt, &port));

// HTTP/0.9 over QUIC (for interop only, will be removed)
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt));
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt, &port));

// HTTP/3
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3, new Http3SessionAccept(accept_opt));
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3, new Http3SessionAccept(accept_opt, &port));

quic->proxyPort = &port;
acceptor._accept = quic;
Expand Down
4 changes: 2 additions & 2 deletions src/proxy/http/HttpSM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -439,10 +439,10 @@ HttpSM::attach_client_session(ProxyTransaction *txn)
t_state.api_skip_all_remapping = netvc->get_is_unmanaged_request();

ink_assert(_ua.get_txn()->get_proxy_ssn());
ink_assert(_ua.get_txn()->get_proxy_ssn()->accept_options);
ink_assert(_ua.get_txn()->get_proxy_ssn()->acceptor);

// default the upstream IP style host resolution order from inbound
t_state.my_txn_conf().host_res_data.order = _ua.get_txn()->get_proxy_ssn()->accept_options->host_res_preference;
t_state.my_txn_conf().host_res_data.order = _ua.get_txn()->get_proxy_ssn()->acceptor->options().host_res_preference;

start_sub_sm();

Expand Down
6 changes: 3 additions & 3 deletions src/proxy/http/HttpSessionAccept.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ HttpSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReade

// Set the transport type if not already set
if (HttpProxyPort::TRANSPORT_NONE == netvc->attributes) {
netvc->attributes = transport_type;
netvc->attributes = options().transport_type;
}

if (dbg_ctl_http_seq.on()) {
Expand All @@ -80,8 +80,8 @@ HttpSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReade

Http1ClientSession *new_session = THREAD_ALLOC_INIT(http1ClientSessionAllocator, this_ethread());

new_session->accept_options = static_cast<Options *>(this);
new_session->acl = std::move(acl);
new_session->acceptor = this;
new_session->acl = std::move(acl);

// Pin session to current ET_NET thread
new_session->setThreadAffinity(this_ethread());
Expand Down
26 changes: 25 additions & 1 deletion src/proxy/http/unit_tests/test_HttpUserAgent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ TEST_CASE("tcp_reused should be set correctly when a session is attached.")
SSLNetVConnection netvc;
ssn.set_vc(&netvc);
HttpSessionAccept::Options options;
ssn.accept_options = &options;
HttpSessionAccept acceptor{options};
ssn.acceptor = &acceptor;
Http1ClientTransaction txn{&ssn};

SECTION("When a transaction is the first one, "
Expand All @@ -91,3 +92,26 @@ TEST_CASE("tcp_reused should be set correctly when a session is attached.")
CHECK(user_agent.get_client_tcp_reused() == true);
}
}

TEST_CASE("Transactions inherit shared acceptor properties")
{
HttpSessionAccept::Options options;
HttpProxyPort proxy_port;

options.setOutboundPort(8080);
options.setOutboundTransparent(true);
options.setTransparentPassthrough(true);

auto options_handle = std::make_shared<HttpSessionAccept::Options>(options);
HttpSessionAccept acceptor{options_handle, &proxy_port};
Http1ClientTestSession ssn;

ssn.acceptor = &acceptor;
Http1ClientTransaction txn{&ssn};

CHECK(&acceptor.options() == options_handle.get());
CHECK(ssn.acceptor->proxyPort == &proxy_port);
CHECK(txn.get_outbound_port() == 8080);
CHECK(txn.is_outbound_transparent());
CHECK(txn.is_transparent_passthrough_allowed());
}
7 changes: 4 additions & 3 deletions src/proxy/http2/Http2SessionAccept.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ DbgCtl dbg_ctl_http2_seq{"http2_seq"};

} // end anonymous namespace

Http2SessionAccept::Http2SessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o)
Http2SessionAccept::Http2SessionAccept(OptionsHandle options, HttpProxyPort *proxy_port)
: HttpSessionAcceptBase(std::move(options), proxy_port)
{
SET_HANDLER(&Http2SessionAccept::mainEvent);
}
Expand Down Expand Up @@ -67,7 +68,7 @@ Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead
return false;
}

netvc->attributes = this->options.transport_type;
netvc->attributes = this->options().transport_type;

if (dbg_ctl_http2_seq.on()) {
ip_port_text_buffer ipb;
Expand All @@ -78,7 +79,7 @@ Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead

Http2ClientSession *new_session = THREAD_ALLOC_INIT(http2ClientSessionAllocator, this_ethread());
new_session->acl = std::move(session_acl);
new_session->accept_options = &options;
new_session->acceptor = this;

// Pin session to current ET_NET thread
new_session->setThreadAffinity(this_ethread());
Expand Down
1 change: 0 additions & 1 deletion src/proxy/http2/Http2Stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ Http2Stream::Http2Stream(ProxySession *session, Http2StreamId sid, ssize_t initi
_receive_header.create(HTTPType::RESPONSE);
_send_header.create(HTTPType::REQUEST, HTTP_2_0);
} else {
this->upstream_outbound_options = *(session->accept_options);
_receive_header.create(HTTPType::REQUEST);
_send_header.create(HTTPType::RESPONSE, HTTP_2_0);
}
Expand Down
Loading