From e52a9879bbe0b6a125454cbc86d26015904909a1 Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Thu, 13 May 2021 16:23:43 +0000 Subject: [PATCH 1/6] Make HttpSM server reference a Transaction instead of a Session --- include/tscore/IntrusiveHashMap.h | 31 +- iocore/net/libinknet_stub.cc | 4 +- proxy/PoolableSession.h | 59 ++- proxy/ProxySession.h | 11 +- proxy/ProxyTransaction.cc | 24 +- proxy/ProxyTransaction.h | 37 +- proxy/http/Http1ClientSession.cc | 43 +- proxy/http/Http1ClientSession.h | 8 +- ...ansaction.cc => Http1ClientTransaction.cc} | 32 +- proxy/http/Http1ClientTransaction.h | 50 ++ proxy/http/Http1ServerSession.cc | 150 +++--- proxy/http/Http1ServerSession.h | 36 +- proxy/http/Http1ServerTransaction.cc | 53 +++ proxy/http/Http1ServerTransaction.h | 53 +++ proxy/http/Http1Transaction.h | 30 +- proxy/http/HttpConfig.cc | 19 + proxy/http/HttpConfig.h | 10 + proxy/http/HttpSM.cc | 444 +++++++++--------- proxy/http/HttpSM.h | 34 +- proxy/http/HttpSessionManager.cc | 92 +++- proxy/http/HttpSessionManager.h | 3 + proxy/http/HttpTransactHeaders.cc | 2 +- proxy/http/Makefile.am | 5 +- proxy/http2/Http2ClientSession.cc | 2 +- proxy/http2/Http2Stream.cc | 6 +- proxy/http2/Http2Stream.h | 6 +- src/traffic_server/InkAPI.cc | 86 ++-- 27 files changed, 868 insertions(+), 462 deletions(-) rename proxy/http/{Http1Transaction.cc => Http1ClientTransaction.cc} (67%) create mode 100644 proxy/http/Http1ClientTransaction.h create mode 100644 proxy/http/Http1ServerTransaction.cc create mode 100644 proxy/http/Http1ServerTransaction.h diff --git a/include/tscore/IntrusiveHashMap.h b/include/tscore/IntrusiveHashMap.h index f8dd340aff2..f741340d391 100644 --- a/include/tscore/IntrusiveHashMap.h +++ b/include/tscore/IntrusiveHashMap.h @@ -572,20 +572,37 @@ IntrusiveHashMap::erase(iterator const &loc) -> iterator --b->_count; } } - _list.erase(loc); + _list.erase(v); return zret; } template bool -IntrusiveHashMap::erase(value_type *value) +IntrusiveHashMap::erase(value_type *v) { - auto loc = this->find(value); - if (loc != this->end()) { - this->erase(loc); - return true; + ++(this->iterator_for(v)); // get around no const_iterator -> iterator. + Bucket *b = this->bucket_for(H::key_of(v)); + value_type *nv = H::next_ptr(v); + value_type *limit = b->limit(); + if (b->_v == v) { // removed first element in bucket, update bucket + if (limit == nv) { // that was also the only element, deactivate bucket + _active_buckets.erase(b); + b->clear(); + } else { + b->_v = nv; + --b->_count; + } } - return false; + _list.erase(v); + return true; + /* + auto loc = this->find(v); + if (loc != this->end()) { + this->erase(loc); + return true; + } + return false; + */ } template diff --git a/iocore/net/libinknet_stub.cc b/iocore/net/libinknet_stub.cc index 11fee253e2f..4722daaab87 100644 --- a/iocore/net/libinknet_stub.cc +++ b/iocore/net/libinknet_stub.cc @@ -21,11 +21,11 @@ limitations under the License. */ -#include "HttpSessionManager.h" +class EThread; +class Continuation; void initialize_thread_for_http_sessions(EThread *, int) { - ink_assert(false); } #include "P_UnixNet.h" diff --git a/proxy/PoolableSession.h b/proxy/PoolableSession.h index 802ddb3eaa1..7545440b753 100644 --- a/proxy/PoolableSession.h +++ b/proxy/PoolableSession.h @@ -33,9 +33,11 @@ class PoolableSession : public ProxySession public: enum PooledState { INIT, - SSN_IN_USE, // actively in use - KA_RESERVED, // stuck to client - KA_POOLED, // free for reuse + SSN_IN_USE, // actively in use + KA_RESERVED, // stuck to client + KA_POOLED, // free for reuse + SSN_CLOSED, // Session ready to be freed + SSN_TO_RELEASE // Session reaady to be released }; /// Hash map descriptor class for IP map. @@ -72,16 +74,28 @@ class PoolableSession : public ProxySession TSServerSessionSharingMatchMask sharing_match = TS_SERVER_SESSION_SHARING_MATCH_MASK_NONE; TSServerSessionSharingPoolType sharing_pool = TS_SERVER_SESSION_SHARING_POOL_GLOBAL; - // Keep track of connection limiting and a pointer to the - // singleton that keeps track of the connection counts. - OutboundConnTrack::Group *conn_track_group = nullptr; + void enable_outbound_connection_tracking(OutboundConnTrack::Group *group); + void release_outbound_connection_tracking(); + + void attach_hostname(const char *hostname); void set_active(); bool is_active(); void set_private(bool new_private = true); bool is_private() const; - void set_netvc(NetVConnection *newvc); + virtual void set_netvc(NetVConnection *newvc); + + // Used to determine whether the session is for parent proxy + // it is session to origin server + // We need to determine whether a closed connection was to + // close parent proxy to update the + // proxy.process.http.current_parent_proxy_connections + bool to_parent_proxy = false; + + // Keep track of connection limiting and a pointer to the + // singleton that keeps track of the connection counts. + OutboundConnTrack::Group *conn_track_group = nullptr; virtual IOBufferReader *get_reader() = 0; @@ -192,3 +206,34 @@ PoolableSession::FQDNLinkage::equal(CryptoHash const &lhs, CryptoHash const &rhs { return lhs == rhs; } + +inline void +PoolableSession::enable_outbound_connection_tracking(OutboundConnTrack::Group *group) +{ + ink_assert(nullptr == conn_track_group); + conn_track_group = group; +} + +inline void +PoolableSession::release_outbound_connection_tracking() +{ + // Update upstream connection tracking data if present. + if (conn_track_group) { + if (conn_track_group->_count >= 0) { + (conn_track_group->_count)--; + conn_track_group = nullptr; + } else { + // A bit dubious, as there's no guarantee it's still negative, but even that would be interesting to know. + Error("[http_ss] [%" PRId64 "] number of connections should be greater than or equal to zero: %u", con_id, + conn_track_group->_count.load()); + } + } +} + +inline void +PoolableSession::attach_hostname(const char *hostname) +{ + if (CRYPTO_HASH_ZERO == hostname_hash) { + CryptoContext().hash_immediate(hostname_hash, (unsigned char *)hostname, strlen(hostname)); + } +} diff --git a/proxy/ProxySession.h b/proxy/ProxySession.h index 58a50f1e55b..4162813db4d 100644 --- a/proxy/ProxySession.h +++ b/proxy/ProxySession.h @@ -107,7 +107,6 @@ class ProxySession : public VConnection, public PluginUserArgs virtual void hook_add(TSHttpHookID id, INKContInternal *cont); virtual bool is_chunked_encoding_supported() const; - virtual void set_half_close_flag(bool flag); virtual bool get_half_close_flag() const; @@ -137,7 +136,7 @@ class ProxySession : public VConnection, public PluginUserArgs void clear_session_active(); bool is_active() const; bool is_draining() const; - bool is_client_closed() const; + bool is_peer_closed() const; int64_t connection_id() const; TSHttpHookID get_hookid() const; @@ -157,6 +156,12 @@ class ProxySession : public VConnection, public PluginUserArgs void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; + virtual ProxyTransaction * + new_transaction() + { + return nullptr; + } + //////////////////// // Members @@ -236,7 +241,7 @@ ProxySession::is_draining() const } inline bool -ProxySession::is_client_closed() const +ProxySession::is_peer_closed() const { return get_netvc() == nullptr; } diff --git a/proxy/ProxyTransaction.cc b/proxy/ProxyTransaction.cc index 50d6682217d..4dc199fc93d 100644 --- a/proxy/ProxyTransaction.cc +++ b/proxy/ProxyTransaction.cc @@ -57,8 +57,8 @@ ProxyTransaction::new_transaction(bool from_early_data) } } - this->increment_client_transactions_stat(); - _sm->attach_client_session(this, _reader); + this->increment_transactions_stat(); + _sm->attach_client_session(this); } bool @@ -181,7 +181,7 @@ void ProxyTransaction::transaction_done() { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - this->decrement_client_transactions_stat(); + this->decrement_transactions_stat(); } // Implement VConnection interface. @@ -221,6 +221,24 @@ ProxyTransaction::has_request_body(int64_t request_content_length, bool is_chunk return request_content_length > 0 || is_chunked; } +bool +ProxyTransaction::is_read_closed() const +{ + return false; +} + +void +ProxyTransaction::attach_transaction(HttpSM *attach_sm) +{ + _sm = attach_sm; +} + +HTTPVersion +ProxyTransaction::get_version(HTTPHdr &hdr) const +{ + return hdr.version_get(); +} + bool ProxyTransaction::allow_half_open() const { diff --git a/proxy/ProxyTransaction.h b/proxy/ProxyTransaction.h index 0ae77f58145..21a17c902cd 100644 --- a/proxy/ProxyTransaction.h +++ b/proxy/ProxyTransaction.h @@ -39,15 +39,17 @@ class ProxyTransaction : public VConnection /// Virtual Methods // virtual void new_transaction(bool from_early_data = false); + virtual void attach_transaction(HttpSM *attach_sm); virtual bool attach_server_session(PoolableSession *ssession, bool transaction_done = true); Action *adjust_thread(Continuation *cont, int event, void *data); - virtual void release(IOBufferReader *r) = 0; - virtual void transaction_done(); + virtual void release() = 0; + virtual void transaction_done() = 0; virtual void set_active_timeout(ink_hrtime timeout_in); virtual void set_inactivity_timeout(ink_hrtime timeout_in); virtual void cancel_inactivity_timeout(); virtual void cancel_active_timeout(); + virtual bool is_read_closed() const; // Implement VConnection interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -63,8 +65,9 @@ class ProxyTransaction : public VConnection virtual int get_transaction_priority_weight() const; virtual int get_transaction_priority_dependence() const; virtual bool allow_half_open() const; - virtual void increment_client_transactions_stat() = 0; - virtual void decrement_client_transactions_stat() = 0; + + virtual void increment_transactions_stat() = 0; + virtual void decrement_transactions_stat() = 0; virtual NetVConnection *get_netvc() const; virtual bool is_first_transaction() const; @@ -85,6 +88,10 @@ class ProxyTransaction : public VConnection // Returns true if there is a request body for this request virtual bool has_request_body(int64_t content_length, bool is_chunked_set) const; + sockaddr const *get_remote_addr() const; + + virtual HTTPVersion get_version(HTTPHdr &hdr) const; + /// Non-Virtual Methods // const char *get_protocol_string(); @@ -114,8 +121,8 @@ class ProxyTransaction : public VConnection // This function must return a non-negative number that is different for two in-progress transactions with the same proxy_ssn // session. // - void set_rx_error_code(ProxyError e); - void set_tx_error_code(ProxyError e); + virtual void set_rx_error_code(ProxyError e); + virtual void set_tx_error_code(ProxyError e); bool support_sni() const; @@ -123,6 +130,8 @@ class ProxyTransaction : public VConnection // HttpSessionAccept::Options upstream_outbound_options; // overwritable copy of options + IOBufferReader *get_reader(); + protected: ProxySession *_proxy_ssn = nullptr; HttpSM *_sm = nullptr; @@ -274,3 +283,19 @@ ProxyTransaction::adjust_thread(Continuation *cont, int event, void *data) } return nullptr; } + +inline IOBufferReader * +ProxyTransaction::get_reader() +{ + return _reader; +} + +inline sockaddr const * +ProxyTransaction::get_remote_addr() const +{ + if (_proxy_ssn) { + return _proxy_ssn->get_remote_addr(); + } else { + return nullptr; + } +} diff --git a/proxy/http/Http1ClientSession.cc b/proxy/http/Http1ClientSession.cc index 5700f74866c..02a7e9b5e57 100644 --- a/proxy/http/Http1ClientSession.cc +++ b/proxy/http/Http1ClientSession.cc @@ -61,6 +61,8 @@ ClassAllocator http1ClientSessionAllocator("http1Clien Http1ClientSession::Http1ClientSession() : super(), trans(this) {} +// +// Will only close the connection if do_io_close has been called previously (to set read_state to HCS_CLOSED void Http1ClientSession::destroy() { @@ -86,12 +88,16 @@ Http1ClientSession::release_transaction() if (transact_count == released_transactions) { // Make sure we previously called release() or do_io_close() on the session ink_release_assert(read_state != HCS_INIT); - if (read_state == HCS_ACTIVE_READER) { + if (is_active()) { // (in)active timeout do_io_close(HTTP_ERRNO); + } else if (read_state == HCS_ACTIVE_READER) { + release(&trans); // Put back to keep-alive state } else { destroy(); } + } else { + ink_release_assert(transact_count == released_transactions); } } @@ -209,6 +215,9 @@ void Http1ClientSession::do_io_close(int alerrno) { if (read_state == HCS_CLOSED) { + if (transact_count == released_transactions) { + this->destroy(); + } return; // Don't double call session close } if (read_state == HCS_ACTIVE_READER) { @@ -257,8 +266,6 @@ Http1ClientSession::do_io_close(int alerrno) HTTP_SUM_DYN_STAT(http_transactions_per_client_con, transact_count); read_state = HCS_CLOSED; - // Can go ahead and close the netvc now, but keeping around the session object - // until all the transactions are closed if (_vc) { _vc->do_io_close(); _vc = nullptr; @@ -347,11 +354,21 @@ Http1ClientSession::state_keep_alive(int event, void *data) { // Route the event. It is either for vc or // the origin server slave vc - if (data && data == slave_ka_vio) { - return state_slave_keep_alive(event, data); - } else { - ink_assert(data && data == ka_vio); - ink_assert(read_state == HCS_KEEP_ALIVE); + if (data) { + if (data == slave_ka_vio) { + return state_slave_keep_alive(event, data); + } else if (data == schedule_event) { + schedule_event = nullptr; + } else { + ink_assert(data && data == ka_vio); + ink_assert(read_state == HCS_KEEP_ALIVE); + } + } + + // If we got here due to a network I/O event directly, go ahead and cancel any remaining schedule events + if (schedule_event) { + schedule_event->cancel(); + schedule_event = nullptr; } STATE_ENTER(&Http1ClientSession::state_keep_alive, event, data); @@ -387,8 +404,6 @@ Http1ClientSession::state_keep_alive(int event, void *data) void Http1ClientSession::release(ProxyTransaction *trans) { - ink_assert(read_state == HCS_ACTIVE_READER || read_state == HCS_INIT); - // When release is called from start() to read the first transaction, get_sm() // will return null. HttpSM *sm = trans->get_sm(); @@ -409,6 +424,7 @@ Http1ClientSession::release(ProxyTransaction *trans) // buffer. If there is, spin up a new state // machine to process it. Otherwise, issue an // IO to wait for new data + /* Start the new transaction once we finish completely the current transaction and unroll the stack */ bool more_to_read = this->_reader->is_read_avail_more_than(0); if (more_to_read) { HttpSsnDebug("[%" PRId64 "] data already in buffer, starting new transaction", con_id); @@ -429,19 +445,19 @@ Http1ClientSession::release(ProxyTransaction *trans) } } -void +ProxyTransaction * Http1ClientSession::new_transaction() { // If the client connection terminated during API callouts we're done. if (nullptr == _vc) { this->do_io_close(); // calls the SSN_CLOSE hooks to match the SSN_START hooks. - return; + return nullptr; } if (!_vc->add_to_active_queue()) { // no room in the active queue close the connection this->do_io_close(); - return; + return nullptr; } // Defensive programming, make sure nothing persists across @@ -453,6 +469,7 @@ Http1ClientSession::new_transaction() transact_count++; trans.new_transaction(read_from_early_data > 0 ? true : false); + return &trans; } bool diff --git a/proxy/http/Http1ClientSession.h b/proxy/http/Http1ClientSession.h index 4c4d0deba42..a2f5525c0d3 100644 --- a/proxy/http/Http1ClientSession.h +++ b/proxy/http/Http1ClientSession.h @@ -37,7 +37,7 @@ #include "HttpConfig.h" #include "IPAllow.h" #include "ProxySession.h" -#include "Http1Transaction.h" +#include "Http1ClientTransaction.h" #ifdef USE_HTTP_DEBUG_LISTS extern ink_mutex debug_cs_list_mutex; @@ -73,8 +73,8 @@ class Http1ClientSession : public ProxySession bool allow_half_open() const; void set_half_close_flag(bool flag) override; bool get_half_close_flag() const override; - bool is_chunked_encoding_supported() const override; int get_transact_count() const override; + bool is_chunked_encoding_supported() const override; virtual bool is_outbound_transparent() const; PoolableSession *get_server_session() const override; @@ -86,7 +86,7 @@ class Http1ClientSession : public ProxySession private: Http1ClientSession(Http1ClientSession &); - void new_transaction(); + ProxyTransaction *new_transaction() override; int state_keep_alive(int event, void *data); int state_slave_keep_alive(int event, void *data); @@ -126,7 +126,7 @@ class Http1ClientSession : public ProxySession /// Set outbound connection to transparent. bool f_outbound_transparent = false; - Http1Transaction trans; + Http1ClientTransaction trans; }; extern ClassAllocator http1ClientSessionAllocator; diff --git a/proxy/http/Http1Transaction.cc b/proxy/http/Http1ClientTransaction.cc similarity index 67% rename from proxy/http/Http1Transaction.cc rename to proxy/http/Http1ClientTransaction.cc index 55e4d1309ae..337f2c5a53e 100644 --- a/proxy/http/Http1Transaction.cc +++ b/proxy/http/Http1ClientTransaction.cc @@ -1,6 +1,6 @@ /** @file - Http1Transaction.cc - The Transaction class for Http1* + Http1ClientTransaction.cc - The Client Transaction class for Http1* @section license License @@ -21,23 +21,18 @@ limitations under the License. */ -#include "Http1Transaction.h" +#include "Http1ClientTransaction.h" #include "Http1ClientSession.h" #include "HttpSM.h" void -Http1Transaction::release(IOBufferReader *r) +Http1ClientTransaction::release() { + _proxy_ssn->clear_session_active(); } void -Http1Transaction::reset() -{ - _sm = nullptr; -} - -void -Http1Transaction::transaction_done() +Http1ClientTransaction::transaction_done() { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); super_type::transaction_done(); @@ -47,7 +42,7 @@ Http1Transaction::transaction_done() } bool -Http1Transaction::allow_half_open() const +Http1ClientTransaction::allow_half_open() const { bool config_allows_it = (_sm) ? _sm->t_state.txn_conf->allow_half_open > 0 : true; if (config_allows_it) { @@ -58,24 +53,13 @@ Http1Transaction::allow_half_open() const } void -Http1Transaction::increment_client_transactions_stat() +Http1ClientTransaction::increment_transactions_stat() { HTTP_INCREMENT_DYN_STAT(http_current_client_transactions_stat); } void -Http1Transaction::decrement_client_transactions_stat() +Http1ClientTransaction::decrement_transactions_stat() { HTTP_DECREMENT_DYN_STAT(http_current_client_transactions_stat); } - -// -int -Http1Transaction::get_transaction_id() const -{ - // For HTTP/1 there is only one on-going transaction at a time per session/connection. Therefore, the transaction count can be - // presumed not to increase during the lifetime of a transaction, thus this function will return a consistent unique transaction - // identifier. - // - return _proxy_ssn->get_transact_count(); -} diff --git a/proxy/http/Http1ClientTransaction.h b/proxy/http/Http1ClientTransaction.h new file mode 100644 index 00000000000..8dd5f340eaf --- /dev/null +++ b/proxy/http/Http1ClientTransaction.h @@ -0,0 +1,50 @@ +/** @file + + Http1ClientTransaction.h - The Client Transaction class for Http1* + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "Http1Transaction.h" + +class Http1ClientTransaction : public Http1Transaction +{ +public: + using super_type = Http1Transaction; + + Http1ClientTransaction() {} + Http1ClientTransaction(ProxySession *session) : super_type(session) {} + + //////////////////// + // Methods + void release() override; + + bool allow_half_open() const override; + void transaction_done() override; + void increment_transactions_stat() override; + void decrement_transactions_stat() override; + + //////////////////// + // Variables + +protected: + bool outbound_transparent{false}; +}; diff --git a/proxy/http/Http1ServerSession.cc b/proxy/http/Http1ServerSession.cc index eff73aff78c..c0b730a4174 100644 --- a/proxy/http/Http1ServerSession.cc +++ b/proxy/http/Http1ServerSession.cc @@ -38,9 +38,14 @@ ClassAllocator httpServerSessionAllocator("httpServerSessionAllocator"); +Http1ServerSession::Http1ServerSession() : super_type(), trans(this) {} + void Http1ServerSession::destroy() { + if (state != SSN_CLOSED) { + return; + } ink_release_assert(_vc == nullptr); ink_assert(read_buffer); magic = HTTP_SS_MAGIC_DEAD; @@ -81,10 +86,10 @@ Http1ServerSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB if (iobuf == nullptr) { read_buffer = new_MIOBuffer(HTTP_SERVER_RESP_HDR_BUFFER_INDEX); - buf_reader = read_buffer->alloc_reader(); + _reader = read_buffer->alloc_reader(); } else { read_buffer = iobuf; - buf_reader = reader; + _reader = reader; } Debug("http_ss", "[%" PRId64 "] session born, netvc %p", con_id, new_vc); state = INIT; @@ -93,26 +98,19 @@ Http1ServerSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB } void -Http1ServerSession::enable_outbound_connection_tracking(OutboundConnTrack::Group *group) +Http1ServerSession::do_io_close(int alerrno) { - ink_assert(nullptr == conn_track_group); - conn_track_group = group; - if (is_debug_tag_set("http_ss")) { - ts::LocalBufferWriter<256> w; - w.print("[{}] new connection, ip: {}, group ({}), count: {}\0", con_id, get_server_ip(), *group, group->_count); - Debug("http_ss", "%s", w.data()); + if (state == SSN_CLOSED) { // Already been closed + if (transact_count == released_transactions) { + this->destroy(); + } + return; } -} -void -Http1ServerSession::do_io_close(int alerrno) -{ ts::LocalBufferWriter<256> w; bool debug_p = is_debug_tag_set("http_ss"); - if (state == SSN_IN_USE) { - HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat); - } + state = SSN_CLOSED; if (debug_p) { w.print("[{}] session close: nevtc {:x}", con_id, _vc); @@ -122,18 +120,8 @@ Http1ServerSession::do_io_close(int alerrno) HTTP_SUM_DYN_STAT(http_transactions_per_server_con, transact_count); // Update upstream connection tracking data if present. - if (conn_track_group) { - if (conn_track_group->_count >= 0) { - auto n = (conn_track_group->_count)--; - if (debug_p) { - w.print(" conn track group ({}) count {}", conn_track_group->_key, n); - } - } else { - // A bit dubious, as there's no guarantee it's still negative, but even that would be interesting to know. - Error("[http_ss] [%" PRId64 "] number of connections should be greater than or equal to zero: %u", con_id, - conn_track_group->_count.load()); - } - } + this->release_outbound_connection_tracking(); + if (debug_p) { Debug("http_ss", "%.*s", static_cast(w.size()), w.data()); } @@ -146,7 +134,9 @@ Http1ServerSession::do_io_close(int alerrno) if (to_parent_proxy) { HTTP_DECREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); } - destroy(); + if (transact_count == released_transactions) { + this->destroy(); + } } // void Http1ServerSession::release() @@ -156,37 +146,13 @@ Http1ServerSession::do_io_close(int alerrno) void Http1ServerSession::release(ProxyTransaction *trans) { - Debug("http_ss", "Releasing session, private_session=%d, sharing_match=%d", this->is_private(), sharing_match); - // Set our state to KA for stat issues - state = KA_POOLED; - - _vc->control_flags.set_flags(0); - - // Private sessions are never released back to the shared pool - if (this->is_private() || sharing_match == 0) { - this->do_io_close(); + Debug("http_ss", "[%" PRId64 "] Releasing session, private_session=%d, sharing_match=%d", con_id, this->is_private(), + sharing_match); + if (state == SSN_IN_USE) { + state = SSN_TO_RELEASE; return; } - - // do not change the read/write cont and mutex yet - // release_session() will either swap them with the - // pool continuation with a valid read buffer or if - // it fails, do_io_close() will clear the cont anyway - - HSMresult_t r = httpSessionManager.release_session(this); - - if (r == HSM_RETRY) { - // Session could not be put in the session manager - // due to lock contention - // FIX: should retry instead of closing - this->do_io_close(); - HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_pool_lock_contention); - } else { - // The session was successfully put into the session - // manager and it will manage it - // (Note: should never get HSM_NOT_FOUND here) - ink_assert(r == HSM_DONE); - } + ink_release_assert(state == SSN_TO_RELEASE); } // Keys for matching hostnames @@ -223,3 +189,71 @@ void Http1ServerSession::start() { } + +bool +Http1ServerSession::is_chunked_encoding_supported() const +{ + return true; +} + +void +Http1ServerSession ::release_transaction() +{ + // Must adjust the release count before attempting to hand the session + // back to the session manager to avoid race conditions in the global + // pool case + released_transactions++; + + // Private sessions are never released back to the shared pool + if (this->is_private() || sharing_match == 0) { + if (this->is_private()) { + HTTP_INCREMENT_DYN_STAT(http_origin_close_private); + } + this->do_io_close(); + ink_release_assert(transact_count == released_transactions); + } else if (state == SSN_TO_RELEASE) { + _vc->control_flags.set_flags(0); + + // do not change the read/write cont and mutex yet + // release_session() will either swap them with the + // pool continuation with a valid read buffer or if + // it fails, do_io_close() will clear the cont anyway + + HSMresult_t r = httpSessionManager.release_session(this); + + if (r == HSM_RETRY) { + // Session could not be put in the session manager + // due to lock contention + // FIX: should retry instead of closing + do_io_close(HTTP_ERRNO); + HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_pool_lock_contention); + } else { + // The session was successfully put into the session + // manager and it will manage it + // (Note: should never get HSM_NOT_FOUND here) + // Set our state to KA for stat issues + state = KA_POOLED; + ink_assert(r == HSM_DONE); + // If the session got picked up immediately by another thread the transact_count could be greater + ink_release_assert(transact_count >= released_transactions); + } + } else { // Not to be released + if (transact_count == released_transactions) { + // Make sure we previously called release() or do_io_close() on the session + ink_release_assert(state != INIT); + do_io_close(HTTP_ERRNO); + } else { + ink_release_assert(transact_count == released_transactions); + } + } +} + +ProxyTransaction * +Http1ServerSession::new_transaction() +{ + state = SSN_IN_USE; + transact_count++; + ink_release_assert(transact_count == (released_transactions + 1)); + trans.set_reader(this->get_reader()); + return &trans; +} diff --git a/proxy/http/Http1ServerSession.h b/proxy/http/Http1ServerSession.h index c74cc80d7fa..2a3c235e2eb 100644 --- a/proxy/http/Http1ServerSession.h +++ b/proxy/http/Http1ServerSession.h @@ -37,6 +37,7 @@ #include "HttpConnectionCount.h" #include "HttpProxyAPIEnums.h" #include "PoolableSession.h" +#include "Http1ServerTransaction.h" class HttpSM; class MIOBuffer; @@ -53,7 +54,7 @@ class Http1ServerSession : public PoolableSession using super_type = PoolableSession; public: - Http1ServerSession() : super_type() {} + Http1ServerSession(); Http1ServerSession(self_type const &) = delete; self_type &operator=(self_type const &) = delete; ~Http1ServerSession() = default; @@ -62,7 +63,7 @@ class Http1ServerSession : public PoolableSession // Methods void release(ProxyTransaction *) override; void destroy() override; - void free() override; + void release_transaction(); // VConnection Methods void do_io_close(int lerrno = -1) override; @@ -74,24 +75,19 @@ class Http1ServerSession : public PoolableSession void decrement_current_active_connections_stat() override; void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override; void start() override; + void free() override; + bool is_chunked_encoding_supported() const override; - void enable_outbound_connection_tracking(OutboundConnTrack::Group *group); - IOBufferReader *get_reader() override; - void attach_hostname(const char *hostname); + IOBufferReader *get_reader(); IpEndpoint const &get_server_ip() const; + ProxyTransaction *new_transaction() override; + //////////////////// // Variables int transact_count = 0; - // Used to determine whether the session is for parent proxy - // it is session to origin server - // We need to determine whether a closed connection was to - // close parent proxy to update the - // proxy.process.http.current_parent_proxy_connections - bool to_parent_proxy = false; - // The ServerSession owns the following buffer which use // for parsing the headers. The server session needs to // own the buffer so we can go from a keep-alive state @@ -104,7 +100,11 @@ class Http1ServerSession : public PoolableSession private: int magic = HTTP_SS_MAGIC_DEAD; - IOBufferReader *buf_reader = nullptr; + IOBufferReader *_reader = nullptr; + + int released_transactions = 0; + + Http1ServerTransaction trans; }; extern ClassAllocator httpServerSessionAllocator; @@ -112,16 +112,8 @@ extern ClassAllocator httpServerSessionAllocator; //////////////////////////////////////////// // INLINE -inline void -Http1ServerSession::attach_hostname(const char *hostname) -{ - if (CRYPTO_HASH_ZERO == hostname_hash) { - CryptoContext().hash_immediate(hostname_hash, (unsigned char *)hostname, strlen(hostname)); - } -} - inline IOBufferReader * Http1ServerSession::get_reader() { - return buf_reader; + return _reader; }; diff --git a/proxy/http/Http1ServerTransaction.cc b/proxy/http/Http1ServerTransaction.cc new file mode 100644 index 00000000000..55c48a77b59 --- /dev/null +++ b/proxy/http/Http1ServerTransaction.cc @@ -0,0 +1,53 @@ +/** @file + + Http1ServerTransaction.cc - The Server Transaction class for Http1* + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "Http1ServerTransaction.h" +#include "Http1ServerSession.h" + +void +Http1ServerTransaction::release() +{ + _proxy_ssn->release(this); +} + +void +Http1ServerTransaction::increment_transactions_stat() +{ + HTTP_INCREMENT_DYN_STAT(http_current_server_transactions_stat); +} + +void +Http1ServerTransaction::decrement_transactions_stat() +{ + HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat); +} + +void +Http1ServerTransaction::transaction_done() +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + super_type::transaction_done(); + if (_proxy_ssn) { + static_cast(_proxy_ssn)->release_transaction(); + } +} diff --git a/proxy/http/Http1ServerTransaction.h b/proxy/http/Http1ServerTransaction.h new file mode 100644 index 00000000000..c5ee40f2871 --- /dev/null +++ b/proxy/http/Http1ServerTransaction.h @@ -0,0 +1,53 @@ +/** @file + + Http1ServerTransaction.h - The Server Transaction class for Http1* + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "Http1Transaction.h" + +class Http1ServerTransaction : public Http1Transaction +{ +public: + using super_type = Http1Transaction; + + Http1ServerTransaction() {} + Http1ServerTransaction(ProxySession *session) : super_type(session) {} + ~Http1ServerTransaction() override {} + + //////////////////// + // Methods + void release() override; + // void destroy() override; // todo make ~Http1Transaction() + + void increment_transactions_stat() override; + void decrement_transactions_stat() override; + void transaction_done() override; + + void force_close(); + + //////////////////// + // Variables + +protected: + bool outbound_transparent{false}; +}; diff --git a/proxy/http/Http1Transaction.h b/proxy/http/Http1Transaction.h index bd5b6b703d8..be0a174d236 100644 --- a/proxy/http/Http1Transaction.h +++ b/proxy/http/Http1Transaction.h @@ -35,28 +35,36 @@ class Http1Transaction : public ProxyTransaction Http1Transaction(ProxySession *session) : super_type(session) {} ~Http1Transaction() = default; + Http1Transaction() {} + + void reset(); + //////////////////// // Methods - void release(IOBufferReader *r) override; - - bool allow_half_open() const override; - void transaction_done() override; int get_transaction_id() const override; - void increment_client_transactions_stat() override; - void decrement_client_transactions_stat() override; - - void reset(); void set_reader(IOBufferReader *reader); //////////////////// // Variables protected: - bool outbound_transparent{false}; }; -////////////////////////////////// -// INLINE +inline int +Http1Transaction::get_transaction_id() const +{ + // For HTTP/1 there is only one on-going transaction at a time per session/connection. Therefore, the transaction count can be + // presumed not to increase during the lifetime of a transaction, thus this function will return a consistent unique transaction + // identifier. + // + return _proxy_ssn->get_transact_count(); +} + +inline void +Http1Transaction::reset() +{ + _sm = nullptr; +} inline void Http1Transaction::set_reader(IOBufferReader *reader) diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc index 8069da3fb40..f93765b7284 100644 --- a/proxy/http/HttpConfig.cc +++ b/proxy/http/HttpConfig.cc @@ -393,6 +393,25 @@ register_stat_callbacks() RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin_shutdown.tunnel_abort", RECD_INT, RECP_NON_PERSISTENT, (int)http_origin_shutdown_tunnel_abort, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.reuse", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_reuse, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.not_found", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_not_found, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.reuse_fail", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_reuse_fail, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.make_new", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_make_new, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.no_sharing", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_no_sharing, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.body", RECD_INT, RECP_NON_PERSISTENT, (int)http_origin_body, + RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.private", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_private, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.close_private", RECD_INT, RECP_NON_PERSISTENT, + (int)http_origin_close_private, RecRawStatSyncCount); + RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.raw", RECD_INT, RECP_NON_PERSISTENT, (int)http_origin_raw, + RecRawStatSyncCount); + // Upstream current connections stats RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.current_parent_proxy_connections", RECD_INT, RECP_NON_PERSISTENT, (int)http_current_parent_proxy_connections_stat, RecRawStatSyncSum); diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h index 38507f557e6..f11e5fa2ad1 100644 --- a/proxy/http/HttpConfig.h +++ b/proxy/http/HttpConfig.h @@ -352,6 +352,16 @@ enum { http_dead_server_no_requests, + http_origin_reuse, + http_origin_not_found, + http_origin_reuse_fail, + http_origin_make_new, + http_origin_no_sharing, + http_origin_body, + http_origin_private, + http_origin_close_private, + http_origin_raw, + http_stat_count }; diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 09fbe0871d3..e1813e384bc 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -513,7 +513,7 @@ HttpSM::start_sub_sm() } void -HttpSM::attach_client_session(ProxyTransaction *client_vc, IOBufferReader *buffer_reader) +HttpSM::attach_client_session(ProxyTransaction *client_vc) { milestones[TS_MILESTONE_UA_BEGIN] = Thread::get_hrtime(); ink_assert(client_vc != nullptr); @@ -598,14 +598,13 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc, IOBufferReader *buffe hooks_set = client_vc->has_hooks(); // Setup for parsing the header - ua_buffer_reader = buffer_reader; ua_entry->vc_handler = &HttpSM::state_read_client_request_header; t_state.hdr_info.client_request.destroy(); t_state.hdr_info.client_request.create(HTTP_TYPE_REQUEST); // Prepare raw reader which will live until we are sure this is HTTP indeed if (is_transparent_passthrough_allowed() || (ssl_vc && ssl_vc->decrypt_tunnel())) { - ua_raw_buffer_reader = buffer_reader->clone(); + ua_raw_buffer_reader = ua_txn->get_reader()->clone(); } // We first need to run the transaction start hook. Since @@ -642,7 +641,7 @@ HttpSM::setup_client_read_request_header() { ink_assert(ua_entry->vc_handler == &HttpSM::state_read_client_request_header); - ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf); + ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); // The header may already be in the buffer if this // a request from a keep-alive connection handleEvent(VC_EVENT_READ_READY, ua_entry->read_vio); @@ -695,7 +694,7 @@ HttpSM::state_read_client_request_header(int event, void *data) ink_assert(ua_entry->read_vio == (VIO *)data); ink_assert(server_entry == nullptr); - ink_assert(server_session == nullptr); + ink_assert(server_txn == nullptr); int bytes_used = 0; ink_assert(ua_entry->eos == false); @@ -733,7 +732,7 @@ HttpSM::state_read_client_request_header(int event, void *data) // time we've been called. The timeout had been set to // the accept timeout by the ProxyTransaction // - if ((ua_buffer_reader->read_avail() > 0) && (client_request_hdr_bytes == 0)) { + if ((ua_txn->get_reader()->read_avail() > 0) && (client_request_hdr_bytes == 0)) { milestones[TS_MILESTONE_UA_FIRST_READ] = Thread::get_hrtime(); ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in)); } @@ -742,7 +741,7 @@ HttpSM::state_read_client_request_header(int event, void *data) ///////////////////// ParseResult state = t_state.hdr_info.client_request.parse_req( - &http_parser, ua_buffer_reader, &bytes_used, ua_entry->eos, t_state.http_config_param->strict_uri_parsing, + &http_parser, ua_txn->get_reader(), &bytes_used, ua_entry->eos, t_state.http_config_param->strict_uri_parsing, t_state.http_config_param->http_request_line_max_size, t_state.http_config_param->http_hdr_field_max_size); client_request_hdr_bytes += bytes_used; @@ -766,7 +765,7 @@ HttpSM::state_read_client_request_header(int event, void *data) // If we had a GET request that has data after the // get request, do blind tunnel } else if (state == PARSE_RESULT_DONE && t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_GET && - ua_buffer_reader->read_avail() > 0 && !t_state.hdr_info.client_request.is_keep_alive_set()) { + ua_txn->get_reader()->read_avail() > 0 && !t_state.hdr_info.client_request.is_keep_alive_set()) { do_blind_tunnel = true; } if (do_blind_tunnel) { @@ -953,9 +952,9 @@ HttpSM::wait_for_full_body() // Next order of business if copy the remaining data from the // header buffer into new buffer int64_t post_bytes = chunked ? INT64_MAX : t_state.hdr_info.request_content_length; - client_request_body_bytes = post_buffer->write(ua_buffer_reader, chunked ? ua_buffer_reader->read_avail() : post_bytes); + client_request_body_bytes = post_buffer->write(ua_txn->get_reader(), chunked ? ua_txn->get_reader()->read_avail() : post_bytes); - ua_buffer_reader->consume(client_request_body_bytes); + ua_txn->get_reader()->consume(client_request_body_bytes); p = tunnel.add_producer(ua_entry->vc, post_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_BUFFER_READ, "ua post buffer"); if (chunked) { tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT); @@ -989,7 +988,6 @@ HttpSM::state_watch_for_client_abort(int event, void *data) ua_entry->eos = true; } else { ua_txn->do_io_close(); - ua_buffer_reader = nullptr; vc_table.cleanup_entry(ua_entry); ua_entry = nullptr; tunnel.kill_tunnel(); @@ -1059,7 +1057,7 @@ HttpSM::state_watch_for_client_abort(int event, void *data) void HttpSM::setup_push_read_response_header() { - ink_assert(server_session == nullptr); + ink_assert(server_txn == nullptr); ink_assert(server_entry == nullptr); ink_assert(ua_txn != nullptr); ink_assert(t_state.method == HTTP_WKSIDX_PUSH); @@ -1087,7 +1085,7 @@ HttpSM::setup_push_read_response_header() // since if the response is finished, we won't get any // additional callbacks int resp_hdr_state = VC_EVENT_CONT; - if (ua_buffer_reader->read_avail() > 0) { + if (ua_txn->get_reader()->read_avail() > 0) { if (ua_entry->eos) { resp_hdr_state = state_read_push_response_header(VC_EVENT_EOS, ua_entry->read_vio); } else { @@ -1100,7 +1098,7 @@ HttpSM::setup_push_read_response_header() // the cache if (resp_hdr_state == VC_EVENT_CONT) { ink_assert(ua_entry->eos == false); - ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf); + ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); } } @@ -1131,10 +1129,10 @@ HttpSM::state_read_push_response_header(int event, void *data) } int state = PARSE_RESULT_CONT; - while (ua_buffer_reader->read_avail() && state == PARSE_RESULT_CONT) { - const char *start = ua_buffer_reader->start(); + while (ua_txn->get_reader()->read_avail() && state == PARSE_RESULT_CONT) { + const char *start = ua_txn->get_reader()->start(); const char *tmp = start; - int64_t data_size = ua_buffer_reader->block_read_avail(); + int64_t data_size = ua_txn->get_reader()->block_read_avail(); ink_assert(data_size >= 0); ///////////////////// @@ -1146,7 +1144,7 @@ HttpSM::state_read_push_response_header(int event, void *data) int64_t bytes_used = tmp - start; ink_release_assert(bytes_used <= data_size); - ua_buffer_reader->consume(bytes_used); + ua_txn->get_reader()->consume(bytes_used); pushed_response_hdr_bytes += bytes_used; client_request_body_bytes += bytes_used; } @@ -1155,7 +1153,7 @@ HttpSM::state_read_push_response_header(int event, void *data) // call the parser with (eof == true) so it can determine // whether to use the response as is or declare a parse error if (ua_entry->eos) { - const char *end = ua_buffer_reader->start(); + const char *end = ua_txn->get_reader()->start(); state = t_state.hdr_info.server_response.parse_resp(&http_parser, &end, end, true // We are out of data after server eos ); ink_release_assert(state == PARSE_RESULT_DONE || state == PARSE_RESULT_ERROR); @@ -1233,7 +1231,7 @@ HttpSM::state_raw_http_server_open(int event, void *data) case VC_EVENT_ERROR: case NET_EVENT_OPEN_FAILED: - t_state.set_connect_fail(server_session->get_netvc()->lerrno); + t_state.set_connect_fail(server_txn->get_netvc()->lerrno); t_state.current.state = HttpTransact::OPEN_RAW_ERROR; // use this value just to get around other values t_state.hdr_info.response_error = HttpTransact::STATUS_CODE_SERVER_ERROR; @@ -1732,8 +1730,8 @@ HttpSM::handle_api_return() IOBufferReader *initial_data = nullptr; if (t_state.is_websocket) { HTTP_INCREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat); - if (server_session) { - initial_data = server_session->get_reader(); + if (server_txn) { + initial_data = server_txn->get_reader(); } if (ua_txn) { @@ -1744,12 +1742,12 @@ HttpSM::handle_api_return() ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_inactive_timeout)); } - if (server_session) { + if (server_txn) { SMDebug("http_websocket", "(server session) Setting websocket active timeout=%" PRId64 "s and inactive timeout=%" PRId64 "s", t_state.txn_conf->websocket_active_timeout, t_state.txn_conf->websocket_inactive_timeout); - server_session->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_active_timeout)); - server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_inactive_timeout)); + server_txn->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_active_timeout)); + server_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_inactive_timeout)); } } @@ -1801,6 +1799,65 @@ HttpSM::handle_api_return() } } +void +HttpSM::set_server_txn(ProxyTransaction *txn) +{ + ink_release_assert(server_txn == nullptr); + server_txn = txn; + server_txn->attach_transaction(this); +} + +PoolableSession * +HttpSM::create_server_session(NetVConnection *netvc) +{ + HttpTransact::State &s = this->t_state; + PoolableSession *retval = httpServerSessionAllocator.alloc(); + + retval->sharing_pool = static_cast(s.http_config_param->server_session_sharing_pool); + retval->sharing_match = static_cast(s.txn_conf->server_session_sharing_match); + MIOBuffer *netvc_read_buffer = new_MIOBuffer(HTTP_SERVER_RESP_HDR_BUFFER_INDEX); + IOBufferReader *netvc_reader = netvc_read_buffer->alloc_reader(); + retval->new_connection(netvc, netvc_read_buffer, netvc_reader); + + retval->attach_hostname(s.current.server->name); + + ATS_PROBE1(new_origin_server_connection, s.current.server->name); + retval->set_active(); + + if (netvc) { + ats_ip_copy(&s.server_info.src_addr, netvc->get_local_addr()); + } + + // If origin_max_connections or origin_min_keep_alive_connections is set then we are metering + // the max and or min number of connections per host. Transfer responsibility for this to the + // session object. + if (s.outbound_conn_track_state.is_active()) { + Debug("http_connect", "[%" PRId64 "] max number of outbound connections: %d", this->sm_id, s.txn_conf->outbound_conntrack.max); + retval->enable_outbound_connection_tracking(s.outbound_conn_track_state.drop()); + } + return retval; +} + +void +HttpSM::create_server_txn(NetVConnection *netvc, PoolableSession *new_session) +{ + if (new_session == nullptr) { + new_session = this->create_server_session(netvc); + } + + server_txn = new_session->new_transaction(); + server_txn->attach_transaction(this); + if (t_state.current.request_to == HttpTransact::PARENT_PROXY) { + new_session->to_parent_proxy = true; + HTTP_INCREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); + HTTP_INCREMENT_DYN_STAT(http_total_parent_proxy_connections_stat); + } else { + new_session->to_parent_proxy = false; + } + + server_txn->do_io_write(this, 0, nullptr); +} + ////////////////////////////////////////////////////////////////////////////// // // HttpSM::state_http_server_open() @@ -1817,50 +1874,22 @@ HttpSM::state_http_server_open(int event, void *data) pending_action = nullptr; } milestones[TS_MILESTONE_SERVER_CONNECT_END] = Thread::get_hrtime(); - NetVConnection *netvc = nullptr; switch (event) { case NET_EVENT_OPEN: { - Http1ServerSession *session = (TS_SERVER_SESSION_SHARING_POOL_THREAD == httpSessionManager.get_pool_type()) ? - THREAD_ALLOC_INIT(httpServerSessionAllocator, mutex->thread_holding) : - httpServerSessionAllocator.alloc(); - session->sharing_pool = static_cast(t_state.http_config_param->server_session_sharing_pool); - session->sharing_match = static_cast(t_state.txn_conf->server_session_sharing_match); - - netvc = static_cast(data); - session->attach_hostname(t_state.current.server->name); + NetVConnection *netvc = static_cast(data); UnixNetVConnection *vc = static_cast(data); + this->create_server_txn(netvc); + // Since the UnixNetVConnection::action_ or SocksEntry::action_ may be returned from netProcessor.connect_re, and the // SocksEntry::action_ will be copied into UnixNetVConnection::action_ before call back NET_EVENT_OPEN from SocksEntry::free(), // so we just compare the Continuation between pending_action and VC's action_. ink_release_assert(pending_action.is_empty() || pending_action.get_continuation() == vc->get_action()->continuation); pending_action = nullptr; - session->new_connection(vc, nullptr, nullptr); - - ATS_PROBE1(new_origin_server_connection, t_state.current.server->name); + attach_server_session(); - session->set_active(); - ats_ip_copy(&t_state.server_info.src_addr, netvc->get_local_addr()); - - // If origin_max_connections or origin_min_keep_alive_connections is set then we are metering - // the max and or min number of connections per host. Transfer responsibility for this to the - // session object. - if (t_state.outbound_conn_track_state.is_active()) { - SMDebug("http_ss", "[%" PRId64 "] max number of outbound connections: %d", sm_id, t_state.txn_conf->outbound_conntrack.max); - session->enable_outbound_connection_tracking(t_state.outbound_conn_track_state.drop()); - } - - attach_server_session(session); - if (t_state.current.request_to == HttpTransact::PARENT_PROXY) { - session->to_parent_proxy = true; - HTTP_INCREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); - HTTP_INCREMENT_DYN_STAT(http_total_parent_proxy_connections_stat); - } else { - session->to_parent_proxy = false; - } - - if (plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) { + if (this->plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) { SMDebug("http", "[%" PRId64 "] setting handler for TCP handshake", sm_id); // Just want to get a write-ready event so we know that the TCP handshake is complete. server_entry->vc_handler = &HttpSM::state_http_server_open; @@ -1868,10 +1897,10 @@ HttpSM::state_http_server_open(int event, void *data) int64_t nbytes = 1; if (t_state.txn_conf->proxy_protocol_out >= 0) { nbytes = - do_outbound_proxy_protocol(server_session->read_buffer, vc, ua_txn->get_netvc(), t_state.txn_conf->proxy_protocol_out); + do_outbound_proxy_protocol(server_txn->get_reader()->mbuf, vc, ua_txn->get_netvc(), t_state.txn_conf->proxy_protocol_out); } - server_entry->write_vio = server_session->do_io_write(this, nbytes, server_session->get_reader()); + server_entry->write_vio = server_txn->do_io_write(this, nbytes, server_txn->get_reader()); // Pre-emptively set a server connect failure that will be cleared once a WRITE_READY is received from origin or // bytes are received back @@ -1891,12 +1920,12 @@ HttpSM::state_http_server_open(int event, void *data) server_entry->vc_handler = &HttpSM::state_send_server_request_header; // Reset the timeout to the non-connect timeout - server_session->set_inactivity_timeout(get_server_inactivity_timeout()); + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); t_state.current.server->clear_connect_fail(); handle_http_server_open(); return 0; case EVENT_INTERVAL: // Delayed call from another thread - if (server_session == nullptr) { + if (server_txn == nullptr) { do_http_server_open(); } break; @@ -1906,8 +1935,8 @@ HttpSM::state_http_server_open(int event, void *data) /* fallthrough */ case VC_EVENT_ERROR: case NET_EVENT_OPEN_FAILED: { - if (server_session) { - NetVConnection *vc = server_session->get_netvc(); + if (server_txn) { + NetVConnection *vc = server_txn->get_netvc(); if (vc) { t_state.set_connect_fail(vc->lerrno); server_connection_provided_cert = vc->provided_cert(); @@ -1989,7 +2018,7 @@ HttpSM::state_read_server_response_header(int event, void *data) if (server_response_hdr_bytes == 0) { milestones[TS_MILESTONE_SERVER_FIRST_READ] = Thread::get_hrtime(); - server_session->set_inactivity_timeout(get_server_inactivity_timeout()); + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); // For requests that contain a body, we can cancel the ua inactivity timeout. if (ua_txn && t_state.hdr_info.request_content_length > 0) { @@ -2000,14 +2029,14 @@ HttpSM::state_read_server_response_header(int event, void *data) // tokenize header // ///////////////////// ParseResult state = - t_state.hdr_info.server_response.parse_resp(&http_parser, server_buffer_reader, &bytes_used, server_entry->eos); + t_state.hdr_info.server_response.parse_resp(&http_parser, server_txn->get_reader(), &bytes_used, server_entry->eos); server_response_hdr_bytes += bytes_used; // Don't allow HTTP 0.9 (unparsable headers) on resued connections. // And don't allow empty headers from closed connections if ((state == PARSE_RESULT_DONE && t_state.hdr_info.server_response.version_get() == HTTP_0_9 && - server_session->get_transact_count() > 1) || + server_txn->get_transaction_id() > 1) || (server_entry->eos && vio->ndone == 0)) { state = PARSE_RESULT_ERROR; } @@ -2170,7 +2199,7 @@ HttpSM::state_send_server_request_header(int event, void *data) // from both read and write sides of a connection so it should be handled correctly (close tunnels, // deallocate, etc) here with handle_server_setup_error(). Otherwise we might hang due to not shutting // down and never receiving another event again. - /*if (server_buffer_reader->read_avail() > 0 && callout_state == HTTP_API_NO_CALLOUT) { + /*if (server_txn->get_reader()->read_avail() > 0 && callout_state == HTTP_API_NO_CALLOUT) { break; } */ @@ -3171,9 +3200,8 @@ HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p) } // We handled the event. Now either shutdown the connection or // setup it up for keep-alive - ink_assert(server_entry->vc == p->vc); ink_assert(p->vc_type == HT_HTTP_SERVER); - ink_assert(p->vc == server_session); + ink_assert(p->vc == server_txn); // The server session has been released. Clean all pointer // Calling remove_entry instead of server_entry because we don't @@ -3192,9 +3220,6 @@ HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p) t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE; } } else { - server_session->attach_hostname(t_state.current.server->name); - HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat); - // If the option to attach the server session to the client session is set // and if the client is still around and the client is keep-alive, attach the // server session to so the next ka request can use it. Server sessions will @@ -3203,20 +3228,17 @@ HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p) bool release_origin_connection = true; if (t_state.txn_conf->attach_server_session_to_client == 1 && ua_txn && t_state.client_info.keep_alive == HTTP_KEEPALIVE) { Debug("http", "attaching server session to the client"); - if (ua_txn->attach_server_session(server_session)) { + if (ua_txn->attach_server_session(static_cast(server_txn->get_proxy_ssn()))) { release_origin_connection = false; } } if (release_origin_connection) { // Release the session back into the shared session pool - server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); - server_session->release(nullptr); + server_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); + server_txn->release(); } } - server_session = nullptr; // Because p->vc == server_session - server_entry = nullptr; - return 0; } @@ -3261,12 +3283,12 @@ HttpSM::is_bg_fill_necessary(HttpTunnelConsumer *c) if (c->producer->alive && // something there to read // server_entry && server_entry->vc && // from an origin server - // server_session && server_session->get_netvc() && // which is still open and valid + // server_txn && server_txn->get_netvc() && // which is still open and valid c->producer->num_consumers > 1 // with someone else reading it ) { HttpTunnelProducer *p = nullptr; - if (!server_entry || !server_entry->vc || !server_session || !server_session->get_netvc()) { + if (!server_txn || !server_txn->get_netvc()) { // return true if we have finished the reading from OS when client aborted p = c->producer->self_consumer ? c->producer->self_consumer->producer : c->producer; if (p->vc_type == HT_HTTP_SERVER && p->read_success) { @@ -3339,9 +3361,9 @@ HttpSM::tunnel_handler_ua(int event, HttpTunnelConsumer *c) HTTP_INCREMENT_DYN_STAT(http_background_fill_current_count_stat); HTTP_INCREMENT_DYN_STAT(http_background_fill_total_count_stat); - ink_assert(server_entry->vc == server_session); - ink_assert(c->is_downstream_from(server_session)); - server_session->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->background_fill_active_timeout)); + ink_assert(server_entry->vc == server_txn); + ink_assert(c->is_downstream_from(server_txn)); + server_txn->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->background_fill_active_timeout)); } // Even with the background fill, the client side should go down @@ -3429,11 +3451,9 @@ HttpSM::tunnel_handler_ua(int event, HttpTunnelConsumer *c) vc_table.remove_entry(this->ua_entry); ua_txn->do_io_close(); } else { - ink_assert(ua_buffer_reader != nullptr); - ua_txn->release(ua_buffer_reader); - ua_txn->get_proxy_ssn()->release(ua_txn); - ua_buffer_reader = nullptr; - // ua_txn = NULL; + ink_assert(ua_txn->get_reader() != nullptr); + vc_table.remove_entry(this->ua_entry); + ua_txn->release(); } return 0; @@ -3589,7 +3609,6 @@ HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p) SMDebug("http_tunnel", "send 408 response to client to vc %p, tunnel vc %p", ua_txn->get_netvc(), p->vc); tunnel.chain_abort_all(p); - server_session = nullptr; // Reset the inactivity timeout, otherwise the InactivityCop will callback again in the next second. ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in)); // if it is active timeout case, we need to give another chance to send 408 response; @@ -3607,7 +3626,6 @@ HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p) p->handler_state = HTTP_SM_POST_UA_FAIL; set_ua_abort(HttpTransact::ABORTED, event); tunnel.chain_abort_all(p); - server_session = nullptr; // the in_tunnel status on both the ua & and // it's consumer must already be set to true. Previously // we were setting it again to true but incorrectly in @@ -3645,7 +3663,7 @@ HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p) // Initiate another read to catch aborts ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort; - ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf); + ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); break; default: ink_release_assert(0); @@ -3707,7 +3725,7 @@ HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c) break; case VC_EVENT_ERROR: t_state.current.state = HttpTransact::CONNECTION_CLOSED; - t_state.set_connect_fail(server_session->get_netvc()->lerrno); + t_state.set_connect_fail(server_txn->get_netvc()->lerrno); break; default: break; @@ -3759,7 +3777,7 @@ HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c) // do not shut down the client read if (enable_redirection) { if (ua_producer->vc_type == HT_STATIC && event != VC_EVENT_ERROR && event != VC_EVENT_EOS) { - ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf); + ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ); } else { if (ua_producer->vc_type == HT_STATIC && t_state.redirect_info.redirect_in_process) { @@ -3767,7 +3785,7 @@ HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c) } } } else { - ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf); + ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); // we should not shutdown read side of the client here to prevent sending a reset // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ); } // end of added logic @@ -4683,7 +4701,7 @@ void HttpSM::do_cache_lookup_and_read() { // TODO decide whether to uncomment after finish testing redirect - // ink_assert(server_session == NULL); + // ink_assert(server_txn == NULL); ink_assert(pending_action.is_empty()); HTTP_INCREMENT_DYN_STAT(http_cache_lookups_stat); @@ -4929,6 +4947,13 @@ HttpSM::do_http_server_open(bool raw) // is consistent with the actual upstream in case of retry. t_state.outbound_conn_track_state.clear(); + // Make sure any previous attempts are cleaned out + if (server_txn) { + tunnel.reset(); + server_txn->transaction_done(); + server_txn = nullptr; + } + // ua_entry can be null if a scheduled update is also a reverse proxy // request. Added REVPROXY to the assert below, and then changed checks // to be based on ua_txn != NULL instead of req_flavor value. @@ -5047,11 +5072,7 @@ HttpSM::do_http_server_open(bool raw) } } - // If there is already an attached server session mark it as private. - if (server_session != nullptr && will_be_private_ss) { - server_session->set_private(); - } - + bool try_reuse = false; if ((raw == false) && TS_SERVER_SESSION_SHARING_MATCH_NONE != t_state.txn_conf->server_session_sharing_match && (t_state.txn_conf->keep_alive_post_out == 1 || t_state.hdr_info.request_content_length <= 0) && !is_private() && ua_txn != nullptr) { @@ -5061,16 +5082,20 @@ HttpSM::do_http_server_open(bool raw) t_state.current.server->name, // hostname ua_txn // has ptr to bound ua sessions ); + try_reuse = true; switch (shared_result) { case HSM_DONE: - hsm_release_assert(server_session != nullptr); + HTTP_INCREMENT_DYN_STAT(http_origin_reuse); + hsm_release_assert(server_txn != nullptr); handle_http_server_open(); return; case HSM_NOT_FOUND: - hsm_release_assert(server_session == nullptr); + HTTP_INCREMENT_DYN_STAT(http_origin_not_found); + hsm_release_assert(server_txn == nullptr); break; case HSM_RETRY: + HTTP_INCREMENT_DYN_STAT(http_origin_reuse_fail); // Could not get shared pool lock // FIX: should retry lock break; @@ -5092,15 +5117,17 @@ HttpSM::do_http_server_open(bool raw) if (ats_ip_addr_port_eq(existing_ss->get_remote_addr(), &t_state.current.server->dst_addr.sa)) { ua_txn->attach_server_session(nullptr); existing_ss->set_active(); - this->attach_server_session(existing_ss); - hsm_release_assert(server_session != nullptr); + server_txn = existing_ss->new_transaction(); + server_txn->attach_transaction(this); + this->attach_server_session(); + hsm_release_assert(server_txn != nullptr); handle_http_server_open(); return; } else { // As this is in the non-sharing configuration, we want to close // the existing connection and call connect_re to get a new one - existing_ss->get_netvc()->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); - existing_ss->release(nullptr); + existing_ss->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); + existing_ss->release(server_txn); ua_txn->attach_server_session(nullptr); } } @@ -5111,11 +5138,26 @@ HttpSM::do_http_server_open(bool raw) else if (ua_txn != nullptr) { PoolableSession *existing_ss = ua_txn->get_server_session(); if (existing_ss) { - existing_ss->get_netvc()->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); - existing_ss->release(nullptr); + existing_ss->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); + existing_ss->release(server_txn); ua_txn->attach_server_session(nullptr); } } + + if (!try_reuse) { + HTTP_INCREMENT_DYN_STAT(http_origin_make_new); + if (TS_SERVER_SESSION_SHARING_MATCH_NONE == t_state.txn_conf->server_session_sharing_match) { + HTTP_INCREMENT_DYN_STAT(http_origin_no_sharing); + } else if ((t_state.txn_conf->keep_alive_post_out != 1 && t_state.hdr_info.request_content_length > 0)) { + HTTP_INCREMENT_DYN_STAT(http_origin_body); + } else if (is_private()) { + HTTP_INCREMENT_DYN_STAT(http_origin_private); + } else if (raw) { + HTTP_INCREMENT_DYN_STAT(http_origin_raw); + } else { + ink_release_assert(ua_txn == nullptr); + } + } // Check to see if we have reached the max number of connections. // Atomically read the current number of connections and check to see // if we have gone above the max allowed. @@ -5470,7 +5512,7 @@ HttpSM::set_ua_abort(HttpTransact::AbortState_t ua_abort, int event) void HttpSM::release_server_session(bool serve_from_cache) { - if (server_session == nullptr) { + if (server_txn == nullptr) { return; } @@ -5480,20 +5522,19 @@ HttpSM::release_server_session(bool serve_from_cache) (t_state.hdr_info.server_response.status_get() == HTTP_STATUS_NOT_MODIFIED || (t_state.hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD && t_state.www_auth_content != HttpTransact::CACHE_AUTH_NONE)) && - plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) { - HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat); - server_session->attach_hostname(t_state.current.server->name); + plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL && (!server_entry || !server_entry->eos)) { if (t_state.www_auth_content == HttpTransact::CACHE_AUTH_NONE || serve_from_cache == false) { // Must explicitly set the keep_alive_no_activity time before doing the release - server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); - server_session->release(nullptr); + server_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out)); + server_txn->release(); } else { // an authenticated server connection - attach to the local client // we are serving from cache for the current transaction t_state.www_auth_content = HttpTransact::CACHE_AUTH_SERVE; - ua_txn->attach_server_session(server_session, false); + ua_txn->attach_server_session(static_cast(server_txn->get_proxy_ssn()), false); } } else { + server_txn->do_io_close(); if (TS_SERVER_SESSION_SHARING_MATCH_NONE == t_state.txn_conf->server_session_sharing_match) { HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_no_sharing); } else if (t_state.current.server == nullptr) { @@ -5511,14 +5552,13 @@ HttpSM::release_server_session(bool serve_from_cache) } else { HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_misc); } - server_session->do_io_close(); } - ink_assert(server_entry->vc == server_session); - server_entry->in_tunnel = true; - vc_table.cleanup_entry(server_entry); - server_entry = nullptr; - server_session = nullptr; + if (server_entry) { + server_entry->vc = nullptr; + server_entry->read_vio = server_entry->write_vio = nullptr; + server_entry = nullptr; + } } // void HttpSM::handle_post_failure() @@ -5561,7 +5601,7 @@ HttpSM::handle_post_failure() t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE; t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE; - if (server_buffer_reader->read_avail() > 0) { + if (server_txn->get_reader()->read_avail() > 0) { tunnel.deallocate_buffers(); tunnel.reset(); // There's data from the server so try to read the header @@ -5571,7 +5611,7 @@ HttpSM::handle_post_failure() tunnel.reset(); // Server died if (t_state.current.state == HttpTransact::STATE_UNDEFINED || t_state.current.state == HttpTransact::CONNECTION_ALIVE) { - t_state.set_connect_fail(server_session->get_netvc()->lerrno); + t_state.set_connect_fail(server_txn->get_netvc()->lerrno); t_state.current.state = HttpTransact::CONNECTION_CLOSED; } call_transact_and_set_next_state(HttpTransact::HandleResponse); @@ -5594,8 +5634,8 @@ HttpSM::handle_http_server_open() // IFF they differ from the netVC's current options. // This should keep this from being redundant on a // server session's first transaction. - if (nullptr != server_session) { - NetVConnection *vc = server_session->get_netvc(); + if (nullptr != server_txn) { + NetVConnection *vc = server_txn->get_netvc(); if (vc) { server_connection_provided_cert = vc->provided_cert(); if (vc->options.sockopt_flags != t_state.txn_conf->sock_option_flag_out || @@ -5608,13 +5648,14 @@ HttpSM::handle_http_server_open() } } } + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); int method = t_state.hdr_info.server_request.method_get_wksidx(); if (method != HTTP_WKSIDX_TRACE && (t_state.hdr_info.request_content_length > 0 || t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING) && do_post_transform_open()) { do_setup_post_tunnel(HTTP_TRANSFORM_VC); - } else if (server_session != nullptr) { + } else if (server_txn != nullptr) { setup_server_send_request_api(); } } @@ -5695,7 +5736,7 @@ HttpSM::handle_server_setup_error(int event, void *data) break; case VC_EVENT_ERROR: t_state.current.state = HttpTransact::CONNECTION_ERROR; - t_state.set_connect_fail(server_session->get_netvc()->lerrno); + t_state.set_connect_fail(server_txn->get_netvc()->lerrno); break; case VC_EVENT_ACTIVE_TIMEOUT: t_state.set_connect_fail(ETIMEDOUT); @@ -5725,8 +5766,7 @@ HttpSM::handle_server_setup_error(int event, void *data) if (server_entry) { ink_assert(server_entry->vc_type == HTTP_SERVER_VC); vc_table.cleanup_entry(server_entry); - server_entry = nullptr; - server_session = nullptr; + server_entry = nullptr; } } @@ -5791,7 +5831,7 @@ void HttpSM::do_drain_request_body(HTTPHdr &response) { int64_t content_length = t_state.hdr_info.client_request.get_content_length(); - int64_t avail = ua_buffer_reader->read_avail(); + int64_t avail = ua_txn->get_reader()->read_avail(); if (t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING) { SMDebug("http", "Chunked body, setting the response to non-keepalive"); @@ -5803,7 +5843,7 @@ HttpSM::do_drain_request_body(HTTPHdr &response) SMDebug("http", "entire body is in the buffer, consuming"); int64_t act_on = (avail < content_length) ? avail : content_length; client_request_body_bytes = act_on; - ua_buffer_reader->consume(act_on); + ua_txn->get_reader()->consume(act_on); } else { SMDebug("http", "entire body is not in the buffer, setting the response to non-keepalive"); goto close_connection; @@ -5865,9 +5905,13 @@ HttpSM::do_setup_post_tunnel(HttpVC_t to_vc_type) // Next order of business if copy the remaining data from the // header buffer into new buffer - client_request_body_bytes = post_buffer->write(ua_buffer_reader, chunked ? ua_buffer_reader->read_avail() : post_bytes); + client_request_body_bytes = post_buffer->write(ua_txn->get_reader(), chunked ? ua_txn->get_reader()->read_avail() : post_bytes); - ua_buffer_reader->consume(client_request_body_bytes); + ua_txn->get_reader()->consume(client_request_body_bytes); + // The user agent has already sent all it has + if (ua_txn->is_read_closed()) { + post_bytes = client_request_body_bytes; + } p = tunnel.add_producer(ua_entry->vc, post_bytes - transfered_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_HTTP_CLIENT, "user agent post"); } @@ -5913,7 +5957,7 @@ HttpSM::do_setup_post_tunnel(HttpVC_t to_vc_type) } ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in)); - server_session->set_inactivity_timeout(get_server_inactivity_timeout()); + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); tunnel.tunnel_run(p); @@ -6076,51 +6120,46 @@ HttpSM::write_header_into_buffer(HTTPHdr *h, MIOBuffer *b) } void -HttpSM::attach_server_session(PoolableSession *s) +HttpSM::attach_server_session() { - hsm_release_assert(server_session == nullptr); hsm_release_assert(server_entry == nullptr); - hsm_release_assert(s != nullptr); - hsm_release_assert(s->is_active()); - server_session = static_cast(s); - server_transact_count = server_session->transact_count++; + // In the h1 only origin version, the transact_count was updated after making this assignment. + // The SSN-TXN-COUNT option in header rewrite relies on this fact, so we decrement here so the + // plugin API interface is consistent as we move to more protocols to origin + server_transact_count = server_txn->get_proxy_ssn()->get_transact_count() - 1; // update the dst_addr when using an existing session // for e.g using Host based session pools may ignore the DNS IP - if (!ats_ip_addr_eq(&t_state.current.server->dst_addr, &server_session->get_server_ip())) { + IpEndpoint addr; + addr.assign(server_txn->get_remote_addr()); + if (!ats_ip_addr_eq(&t_state.current.server->dst_addr, &addr)) { ip_port_text_buffer ipb1, ipb2; Debug("http_ss", "updating ip when attaching server session from %s to %s", ats_ip_ntop(&t_state.current.server->dst_addr.sa, ipb1, sizeof(ipb1)), - ats_ip_ntop(server_session->get_remote_addr(), ipb2, sizeof(ipb2))); - ats_ip_copy(&t_state.current.server->dst_addr, server_session->get_remote_addr()); + ats_ip_ntop(server_txn->get_remote_addr(), ipb2, sizeof(ipb2))); + ats_ip_copy(&t_state.current.server->dst_addr, server_txn->get_remote_addr()); } // Propagate the per client IP debugging if (ua_txn) { - s->get_netvc()->control_flags.set_flags(get_cont_flags().get_flags()); + server_txn->get_netvc()->control_flags.set_flags(get_cont_flags().get_flags()); } else { // If there is no ua_txn no sense in continuing to attach the server session return; } // Set the mutex so that we have something to update // stats with - server_session->mutex = this->mutex; + server_txn->mutex = this->mutex; - HTTP_INCREMENT_DYN_STAT(http_current_server_transactions_stat); + server_txn->increment_transactions_stat(); // Record the VC in our table server_entry = vc_table.new_entry(); - server_entry->vc = server_session; + server_entry->vc = server_txn; server_entry->vc_type = HTTP_SERVER_VC; server_entry->vc_handler = &HttpSM::state_send_server_request_header; - // es - is this a concern here in HttpSM? Does it belong somewhere else? - // Get server and client connections - UnixNetVConnection *server_vc = dynamic_cast(server_session->get_netvc()); - UnixNetVConnection *client_vc = (UnixNetVConnection *)(ua_txn->get_netvc()); - - // Verifying that the user agent and server sessions/transactions are operating on the same thread. - ink_release_assert(!server_vc || !client_vc || server_vc->thread == client_vc->thread); + UnixNetVConnection *server_vc = static_cast(server_txn->get_netvc()); // set flag for server session is SSL SSLNetVConnection *server_ssl_vc = dynamic_cast(server_vc); @@ -6128,14 +6167,14 @@ HttpSM::attach_server_session(PoolableSession *s) server_connection_is_ssl = true; } - server_protocol = server_session->get_protocol_string(); + server_protocol = server_txn->get_protocol_string(); // Initiate a read on the session so that the SM and not // session manager will get called back if the timeout occurs // or the server closes on us. The IO Core now requires us to // do the read with a buffer and a size so preallocate the // buffer - server_buffer_reader = server_session->get_reader(); + // ts-3189 We are only setting up an empty read at this point. This // is sufficient to have the timeout errors directed to the appropriate // SM handler, but we don't want to read any data until the tunnel has @@ -6147,17 +6186,17 @@ HttpSM::attach_server_session(PoolableSession *s) // first tunnel was sometimes behind handled by the consumer of the // first tunnel instead of the producer of the second tunnel. // The real read is setup in setup_server_read_response_header() - server_entry->read_vio = server_session->do_io_read(this, 0, server_session->read_buffer); + server_entry->read_vio = server_txn->do_io_read(this, 0, server_txn->get_reader()->mbuf); // Transfer control of the write side as well - server_entry->write_vio = server_session->do_io_write(this, 0, nullptr); + server_entry->write_vio = server_txn->do_io_write(this, 0, nullptr); // Setup the timeouts // Set the inactivity timeout to the connect timeout so that we // we fail this server if it doesn't start sending the response // header - server_session->set_inactivity_timeout(get_server_connect_timeout()); - server_session->set_active_timeout(get_server_active_timeout()); + server_txn->set_inactivity_timeout(get_server_connect_timeout()); + server_txn->set_active_timeout(get_server_active_timeout()); // Do we need Transfer_Encoding? if (ua_txn->has_request_body(t_state.hdr_info.request_content_length, @@ -6171,9 +6210,8 @@ HttpSM::attach_server_session(PoolableSession *s) } } - if (plugin_tunnel_type != HTTP_NO_PLUGIN_TUNNEL || will_be_private_ss) { - SMDebug("http_ss", "Setting server session to private"); - server_session->set_private(); + if (plugin_tunnel_type != HTTP_NO_PLUGIN_TUNNEL || is_private()) { + this->set_server_session_private(true); } } @@ -6181,7 +6219,7 @@ void HttpSM::setup_server_send_request_api() { // Make sure the VC is on the correct timeout - server_session->set_inactivity_timeout(get_server_inactivity_timeout()); + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR; do_api_callout(); } @@ -6193,8 +6231,8 @@ HttpSM::setup_server_send_request() int64_t msg_len = 0; /* lv: just make gcc happy */ hsm_release_assert(server_entry != nullptr); - hsm_release_assert(server_session != nullptr); - hsm_release_assert(server_entry->vc == server_session); + hsm_release_assert(server_txn != nullptr); + hsm_release_assert(server_entry->vc == server_txn); // Send the request header server_entry->vc_handler = &HttpSM::state_send_server_request_header; @@ -6223,25 +6261,24 @@ HttpSM::setup_server_send_request() server_entry->write_vio = server_entry->vc->do_io_write(this, hdr_length, buf_start); // Make sure the VC is using correct timeouts. We may be reusing a previously used server session - server_session->set_inactivity_timeout(get_server_inactivity_timeout()); + server_txn->set_inactivity_timeout(get_server_inactivity_timeout()); } void HttpSM::setup_server_read_response_header() { - ink_assert(server_session != nullptr); + ink_assert(server_txn != nullptr); ink_assert(server_entry != nullptr); // REQ_FLAVOR_SCHEDULED_UPDATE can be transformed in REQ_FLAVOR_REVPROXY ink_assert(ua_txn != nullptr || t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE || t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY); - // We should have set the server_buffer_reader - // we sent the request header - ink_assert(server_buffer_reader != nullptr); + ink_assert(server_txn != nullptr && server_txn->get_reader() != nullptr); // Now that we've got the ability to read from the // server, setup to read the response header server_entry->vc_handler = &HttpSM::state_read_server_response_header; + server_entry->vc = server_txn; t_state.current.state = HttpTransact::STATE_UNDEFINED; t_state.current.server->state = HttpTransact::STATE_UNDEFINED; @@ -6259,13 +6296,13 @@ HttpSM::setup_server_read_response_header() ink_assert(server_entry->read_vio); // The tunnel from OS to UA is now setup. Ready to read the response - server_entry->read_vio = server_session->do_io_read(this, INT64_MAX, server_buffer_reader->mbuf); + server_entry->read_vio = server_txn->do_io_read(this, INT64_MAX, server_txn->get_reader()->mbuf); // If there is anything in the buffer call the parsing routines // since if the response is finished, we won't get any // additional callbacks - if (server_buffer_reader->read_avail() > 0) { + if (server_txn->get_reader()->read_avail() > 0) { state_read_server_response_header((server_entry->eos) ? VC_EVENT_EOS : VC_EVENT_READ_READY, server_entry->read_vio); } } @@ -6569,7 +6606,7 @@ HttpSM::server_transfer_init(MIOBuffer *buf, int hdr_size) if (server_entry->eos == true) { // The server has shutdown on us already so the only data // we'll get is already in the buffer - nbytes = server_buffer_reader->read_avail() + hdr_size; + nbytes = server_txn->get_reader()->read_avail() + hdr_size; } else if (t_state.hdr_info.response_content_length == HTTP_UNDEFINED_CL) { nbytes = -1; } else { @@ -6582,14 +6619,14 @@ HttpSM::server_transfer_init(MIOBuffer *buf, int hdr_size) } // Next order of business if copy the remaining data from the header buffer into new buffer. - int64_t server_response_pre_read_bytes = buf->write(server_buffer_reader, to_copy); - server_buffer_reader->consume(server_response_pre_read_bytes); + int64_t server_response_pre_read_bytes = buf->write(server_txn->get_reader(), to_copy); + server_txn->get_reader()->consume(server_response_pre_read_bytes); // If we know the length & copied the entire body // of the document out of the header buffer make // sure the server isn't screwing us by having sent too // much. If it did, we want to close the server connection - if (server_response_pre_read_bytes == to_copy && server_buffer_reader->read_avail() > 0) { + if (server_response_pre_read_bytes == to_copy && server_txn->get_reader()->read_avail() > 0) { t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE; } @@ -6832,7 +6869,7 @@ HttpSM::setup_push_transfer_to_cache() // The ua has shutdown on us already so the only data // we'll get is already in the buffer. Make sure it // fulfills the stated length - int64_t avail = ua_buffer_reader->read_avail(); + int64_t avail = ua_txn->get_reader()->read_avail(); if (avail < nbytes) { // Client failed to send the body, it's gone. Kill the @@ -6843,8 +6880,8 @@ HttpSM::setup_push_transfer_to_cache() } // Next order of business is copy the remaining data from the // header buffer into new buffer. - pushed_response_body_bytes = buf->write(ua_buffer_reader, nbytes); - ua_buffer_reader->consume(pushed_response_body_bytes); + pushed_response_body_bytes = buf->write(ua_txn->get_reader(), nbytes); + ua_txn->get_reader()->consume(pushed_response_body_bytes); client_request_body_bytes += pushed_response_body_bytes; HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_push); @@ -6890,7 +6927,7 @@ HttpSM::setup_blind_tunnel(bool send_response_hdr, IOBufferReader *initial) // Next order of business if copy the remaining data from the // header buffer into new buffer - client_request_body_bytes += from_ua_buf->write(ua_buffer_reader); + client_request_body_bytes += from_ua_buf->write(ua_txn->get_reader()); HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler); @@ -7022,8 +7059,6 @@ HttpSM::kill_this() plugin_tunnel = nullptr; } - server_session = nullptr; - // So we don't try to nuke the state machine // if the plugin receives event we must reset // the terminate_flag @@ -7077,6 +7112,10 @@ HttpSM::kill_this() } } + if (server_txn) { + server_txn->transaction_done(); + server_txn = nullptr; + } if (ua_txn) { ua_txn->transaction_done(); } @@ -7483,8 +7522,7 @@ HttpSM::set_next_state() if (server_entry) { ink_assert(server_entry->vc_type == HTTP_SERVER_VC); vc_table.cleanup_entry(server_entry); - server_entry = nullptr; - server_session = nullptr; + server_entry = nullptr; } else { // Now that we have gotten the user agent request, we can cancel // the inactivity timeout associated with it. Note, however, that @@ -7528,8 +7566,7 @@ HttpSM::set_next_state() if (server_entry) { ink_assert(server_entry->vc_type == HTTP_SERVER_VC); vc_table.cleanup_entry(server_entry); - server_entry = nullptr; - server_session = nullptr; + server_entry = nullptr; } else { // Now that we have gotten the user agent request, we can cancel // the inactivity timeout associated with it. Note, however, that @@ -8108,8 +8145,8 @@ HttpSM::get_http_schedule(int event, void * /* data ATS_UNUSED */) bool HttpSM::set_server_session_private(bool private_session) { - if (server_session != nullptr) { - server_session->set_private(private_session); + if (server_txn != nullptr) { + static_cast(server_txn->get_proxy_ssn())->set_private(private_session); return true; } return false; @@ -8119,15 +8156,8 @@ inline bool HttpSM::is_private() { bool res = false; - if (server_session) { - res = server_session->is_private(); - } else if (ua_txn) { - Http1ServerSession *ss = dynamic_cast(ua_txn->get_server_session()); - if (ss) { - res = ss->is_private(); - } else if (will_be_private_ss) { - res = will_be_private_ss; - } + if (will_be_private_ss) { + res = will_be_private_ss; } return res; } @@ -8213,8 +8243,8 @@ HttpSM::populate_server_protocol(std::string_view *result, int n) const std::string_view proto = HttpSM::find_proto_string(t_state.hdr_info.server_request.version_get()); if (!proto.empty()) { result[retval++] = proto; - if (n > retval && server_session) { - retval += server_session->populate_protocol(result + retval, n - retval); + if (n > retval && server_txn) { + retval += server_txn->populate_protocol(result + retval, n - retval); } } } @@ -8232,8 +8262,8 @@ HttpSM::server_protocol_contains(std::string_view tag_prefix) const if (prefix.size() <= proto.size() && 0 == strncmp(proto.data(), prefix.data(), prefix.size())) { retval = proto.data(); } else { - if (server_session) { - retval = server_session->protocol_contains(prefix); + if (server_txn) { + retval = server_txn->protocol_contains(prefix); } } } @@ -8320,14 +8350,8 @@ PostDataBuffers::~PostDataBuffers() this->clear(); } -PoolableSession * -HttpSM::get_server_session() const -{ - return server_session; -} - HTTPVersion HttpSM::get_server_version(HTTPHdr &hdr) const { - return this->server_session->get_version(hdr); + return this->server_txn->get_proxy_ssn()->get_version(hdr); } diff --git a/proxy/http/HttpSM.h b/proxy/http/HttpSM.h index d137c4eb188..9228556e722 100644 --- a/proxy/http/HttpSM.h +++ b/proxy/http/HttpSM.h @@ -262,16 +262,16 @@ class HttpSM : public Continuation, public PluginUserArgs void init(bool from_early_data = false); - void attach_client_session(ProxyTransaction *client_vc_arg, IOBufferReader *buffer_reader); + void attach_client_session(ProxyTransaction *client_vc_arg); - // Called by httpSessionManager so that we can reset - // the session timeouts and initiate a read while + // Called after the network connection has been completed + // to set the session timeouts and initiate a read while // holding the lock for the server session - void attach_server_session(PoolableSession *s); + void attach_server_session(); - // Used to read attributes of - // the current active server session - PoolableSession *get_server_session() const; + void set_server_txn(ProxyTransaction *txn); + void create_server_txn(NetVConnection *netvc, PoolableSession *new_session = nullptr); + PoolableSession *create_server_session(NetVConnection *netvc); HTTPVersion get_server_version(HTTPHdr &hdr) const; @@ -281,6 +281,12 @@ class HttpSM : public Continuation, public PluginUserArgs return ua_txn; } + ProxyTransaction * + get_server_txn() + { + return server_txn; + } + // Called by transact. Updates are fire and forget // so there are no callbacks and are safe to do // directly from transact @@ -406,30 +412,28 @@ class HttpSM : public Continuation, public PluginUserArgs HttpVCTable vc_table; - HttpVCTableEntry *ua_entry = nullptr; - public: - ProxyTransaction *ua_txn = nullptr; BackgroundFill_t background_fill = BACKGROUND_FILL_NONE; void set_http_schedule(Continuation *); int get_http_schedule(int event, void *data); History history; + ProxyTransaction *ua_txn = nullptr; + protected: - IOBufferReader *ua_buffer_reader = nullptr; IOBufferReader *ua_raw_buffer_reader = nullptr; - HttpVCTableEntry *server_entry = nullptr; - Http1ServerSession *server_session = nullptr; + HttpVCTableEntry *ua_entry = nullptr; + HttpVCTableEntry *server_entry = nullptr; + ProxyTransaction *server_txn = nullptr; /* Because we don't want to take a session from a shared pool if we know that it will be private, * but we cannot set it to private until we have an attached server session. * So we use this variable to indicate that * we should create a new connection and then once we attach the session we'll mark it as private. */ - bool will_be_private_ss = false; - IOBufferReader *server_buffer_reader = nullptr; + bool will_be_private_ss = false; HttpTransformInfo transform_info; HttpTransformInfo post_transform_info; diff --git a/proxy/http/HttpSessionManager.cc b/proxy/http/HttpSessionManager.cc index 7dc21cebf5f..1b74d330c6c 100644 --- a/proxy/http/HttpSessionManager.cc +++ b/proxy/http/HttpSessionManager.cc @@ -126,7 +126,7 @@ ServerSessionPool::validate_cert(HttpSM *sm, NetVConnection *netvc) // a new connection. // if (sm->t_state.scheme == URL_WKSIDX_HTTPS) { - const char *session_cert = netvc->options.ssl_client_cert_name.get(); + const char *session_cert = netvc->options.ssl_client_cert_name; std::string_view proposed_cert = sm->get_outbound_cert(); Debug("http_ss", "validate_cert proposed_cert=%.*s, cert=%s", static_cast(proposed_cert.size()), proposed_cert.data(), session_cert); @@ -165,9 +165,11 @@ ServerSessionPool::acquireSession(sockaddr const *addr, CryptoHash const &hostna } if (zret == HSM_DONE) { to_return = first; - HTTP_DECREMENT_DYN_STAT(http_pooled_server_connections_stat); - m_fqdn_pool.erase(first); - m_ip_pool.erase(to_return); + this->removeSession(to_return); + } else { + if (first != m_fqdn_pool.end()) { + Debug("http_ss", "Failed find entry due to name mismatch %s", sm->t_state.current.server->name); + } } } else if (TS_SERVER_SESSION_SHARING_MATCH_MASK_IP & match_style) { // matching is not disabled. auto first = m_ip_pool.find(addr); @@ -190,9 +192,7 @@ ServerSessionPool::acquireSession(sockaddr const *addr, CryptoHash const &hostna } if (zret == HSM_DONE) { to_return = first; - HTTP_DECREMENT_DYN_STAT(http_pooled_server_connections_stat); - m_ip_pool.erase(first); - m_fqdn_pool.erase(to_return); + this->removeSession(to_return); } } return zret; @@ -217,10 +217,7 @@ ServerSessionPool::releaseSession(PoolableSession *ss) ss->set_inactivity_timeout(ss->get_netvc()->get_inactivity_timeout()); ss->set_active_timeout(ss->get_netvc()->get_active_timeout()); // put it in the pools. - m_ip_pool.insert(ss); - m_fqdn_pool.insert(ss); - - HTTP_INCREMENT_DYN_STAT(http_pooled_server_connections_stat); + this->addSession(ss); Debug("http_ss", "[%" PRId64 "] [release session] " @@ -287,12 +284,10 @@ ServerSessionPool::eventHandler(int event, void *data) HttpDebugNames::get_event_name(event)); ink_assert(s->state == PoolableSession::KA_POOLED); // Out of the pool! Now! - m_ip_pool.erase(spot); - m_fqdn_pool.erase(s); + this->removeSession(s); // Drop connection on this end. s->do_io_close(); found = true; - HTTP_DECREMENT_DYN_STAT(http_pooled_server_connections_stat); break; } } @@ -364,7 +359,8 @@ HttpSessionManager::acquire_session(HttpSM *sm, sockaddr const *ip, const char * ServerSessionPool::validate_cert(sm, to_return->get_netvc()))) { Debug("http_ss", "[%" PRId64 "] [acquire session] returning attached session ", to_return->connection_id()); to_return->state = PoolableSession::SSN_IN_USE; - sm->attach_server_session(to_return); + sm->set_server_txn(to_return->new_transaction()); + sm->attach_server_session(); return HSM_DONE; } // Release this session back to the main session pool and @@ -450,11 +446,20 @@ HttpSessionManager::_acquire_session(sockaddr const *ip, CryptoHash const &hostn } if (to_return) { - Debug("http_ss", "[%" PRId64 "] [acquire session] return session from shared pool", to_return->connection_id()); - to_return->state = PoolableSession::SSN_IN_USE; - // the attach_server_session will issue the do_io_read under the sm lock - sm->attach_server_session(to_return); - retval = HSM_DONE; + ProxyTransaction *trans = to_return->new_transaction(); + if (trans) { + Debug("http_ss", "[%" PRId64 "] [acquire session] return session from shared pool", to_return->connection_id()); + to_return->state = PoolableSession::SSN_IN_USE; + // the attach_server_session will issue the do_io_read under the sm lock + sm->set_server_txn(trans); + sm->attach_server_session(); + retval = HSM_DONE; + } else { + Debug("http_ss", "[%" PRId64 "] [acquire session] failed to get transaction on session from shared pool", + to_return->connection_id()); + to_return->do_io_close(); + retval = HSM_RETRY; + } } } return retval; @@ -484,3 +489,50 @@ HttpSessionManager::release_session(PoolableSession *to_release) return released_p ? HSM_DONE : HSM_RETRY; } + +void +ServerSessionPool::removeSession(PoolableSession *to_remove) +{ + EThread *ethread = this_ethread(); + SCOPED_MUTEX_LOCK(lock, mutex, ethread); + char peer_ip[INET6_ADDRPORTSTRLEN]; + if (is_debug_tag_set("http_ss")) { + ats_ip_nptop(to_remove->get_remote_addr(), peer_ip, sizeof(peer_ip)); + Debug("http_ss", "Remove session %p %s m_fqdn_pool size=%" PRId64 " m_ip_pool_size=%" PRId64, to_remove, peer_ip, + m_fqdn_pool.count(), m_ip_pool.count()); + } + m_fqdn_pool.erase(to_remove); + if (m_ip_pool.erase(to_remove)) { + HTTP_DECREMENT_DYN_STAT(http_pooled_server_connections_stat); + } + if (is_debug_tag_set("http_ss")) { + Debug("http_ss", "After Remove session %p m_fqdn_pool size=%" PRId64 " m_ip_pool_size=%" PRId64, to_remove, m_fqdn_pool.count(), + m_ip_pool.count()); + } +} + +void +ServerSessionPool::testSession(PoolableSession *ss) +{ + auto fqdn_iter = m_fqdn_pool.find(ss); + ink_release_assert(fqdn_iter == m_fqdn_pool.end()); + auto ip_iter = m_ip_pool.find(ss); + ink_release_assert(ip_iter == m_ip_pool.end()); +} + +void +ServerSessionPool::addSession(PoolableSession *ss) +{ + EThread *ethread = this_ethread(); + SCOPED_MUTEX_LOCK(lock, mutex, ethread); + // put it in the pools. + m_ip_pool.insert(ss); + m_fqdn_pool.insert(ss); + HTTP_INCREMENT_DYN_STAT(http_pooled_server_connections_stat); + + if (is_debug_tag_set("http_ss")) { + char peer_ip[INET6_ADDRPORTSTRLEN]; + ats_ip_nptop(ss->get_remote_addr(), peer_ip, sizeof(peer_ip)); + Debug("http_ss", "[%" PRId64 "] [add session] session placed into shared pool under ip %s", ss->connection_id(), peer_ip); + } +} diff --git a/proxy/http/HttpSessionManager.h b/proxy/http/HttpSessionManager.h index b8ed65b75aa..4a7c642edec 100644 --- a/proxy/http/HttpSessionManager.h +++ b/proxy/http/HttpSessionManager.h @@ -67,6 +67,9 @@ class ServerSessionPool : public Continuation static bool validate_host_sni(HttpSM *sm, NetVConnection *netvc); static bool validate_sni(HttpSM *sm, NetVConnection *netvc); static bool validate_cert(HttpSM *sm, NetVConnection *netvc); + void removeSession(PoolableSession *ssn); + void addSession(PoolableSession *ssn); + void testSession(PoolableSession *ssn); int count() const { diff --git a/proxy/http/HttpTransactHeaders.cc b/proxy/http/HttpTransactHeaders.cc index 5558da03bf4..168e015c12c 100644 --- a/proxy/http/HttpTransactHeaders.cc +++ b/proxy/http/HttpTransactHeaders.cc @@ -842,7 +842,7 @@ HttpTransactHeaders::insert_via_header_in_response(HttpTransact::State *s, HTTPH // TODO H2 expand for HTTP/2 outbound proto_buf[n_proto++] = header->version_get().get_minor() == 0 ? IP_PROTO_TAG_HTTP_1_0 : IP_PROTO_TAG_HTTP_1_1; - auto ss = s->state_machine->get_server_session(); + auto ss = s->state_machine->get_server_txn(); if (ss) { n_proto += ss->populate_protocol(proto_buf.data() + n_proto, proto_buf.size() - n_proto); } diff --git a/proxy/http/Makefile.am b/proxy/http/Makefile.am index adfbe73cdc2..a29d5155b52 100644 --- a/proxy/http/Makefile.am +++ b/proxy/http/Makefile.am @@ -48,8 +48,11 @@ libhttp_a_SOURCES = \ HttpCacheSM.h \ Http1ClientSession.cc \ Http1ClientSession.h \ - Http1Transaction.cc \ + Http1ClientTransaction.cc \ Http1Transaction.h \ + Http1ClientTransaction.h \ + Http1ServerTransaction.h \ + Http1ServerTransaction.cc \ HttpConfig.cc \ HttpConfig.h \ HttpConnectionCount.cc \ diff --git a/proxy/http2/Http2ClientSession.cc b/proxy/http2/Http2ClientSession.cc index 009842f31c2..6ed524d03c5 100644 --- a/proxy/http2/Http2ClientSession.cc +++ b/proxy/http2/Http2ClientSession.cc @@ -593,7 +593,7 @@ Http2ClientSession::do_process_frame_read(int event, VIO *vio, bool inside_frame } // If the client hasn't shut us down, reenable - if (!this->is_client_closed()) { + if (!this->is_peer_closed()) { vio->reenable(); } return 0; diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc index a6bc25ef959..1be2bb8cef5 100644 --- a/proxy/http2/Http2Stream.cc +++ b/proxy/http2/Http2Stream.cc @@ -889,20 +889,20 @@ Http2Stream::clear_io_events() // release and do_io_close are the same for the HTTP/2 protocol void -Http2Stream::release(IOBufferReader *r) +Http2Stream::release() { this->do_io_close(); } void -Http2Stream::increment_client_transactions_stat() +Http2Stream::increment_transactions_stat() { HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, _thread); HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_TOTAL_CLIENT_STREAM_COUNT, _thread); } void -Http2Stream::decrement_client_transactions_stat() +Http2Stream::decrement_transactions_stat() { HTTP2_DECREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, _thread); } diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h index fe4720d934d..03d9decea09 100644 --- a/proxy/http2/Http2Stream.h +++ b/proxy/http2/Http2Stream.h @@ -60,7 +60,7 @@ class Http2Stream : public ProxyTransaction int main_event_handler(int event, void *edata); - void release(IOBufferReader *r) override; + void release() override; void reenable(VIO *vio) override; void transaction_done() override; @@ -101,8 +101,8 @@ class Http2Stream : public ProxyTransaction bool is_inactive_timeout_expired(ink_hrtime now); bool is_first_transaction() const override; - void increment_client_transactions_stat() override; - void decrement_client_transactions_stat() override; + void increment_transactions_stat() override; + void decrement_transactions_stat() override; int get_transaction_id() const override; int get_transaction_priority_weight() const override; int get_transaction_priority_dependence() const override; diff --git a/src/traffic_server/InkAPI.cc b/src/traffic_server/InkAPI.cc index c1af7333614..47cb4df72fc 100644 --- a/src/traffic_server/InkAPI.cc +++ b/src/traffic_server/InkAPI.cc @@ -4949,9 +4949,9 @@ TSHttpTxnServerVConnGet(TSHttpTxn txnp) sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS); HttpSM *sm = reinterpret_cast(txnp); if (sm != nullptr) { - PoolableSession *ss = sm->get_server_session(); - if (ss != nullptr) { - vconn = reinterpret_cast(ss->get_netvc()); + ProxyTransaction *st = sm->get_server_txn(); + if (st != nullptr) { + vconn = reinterpret_cast(st->get_netvc()); } } return vconn; @@ -5823,17 +5823,15 @@ TSHttpTxnOutgoingAddrGet(TSHttpTxn txnp) HttpSM *sm = reinterpret_cast(txnp); - PoolableSession *ssn = sm->get_server_session(); - if (ssn == nullptr) { - return nullptr; - } - - NetVConnection *vc = ssn->get_netvc(); - if (vc == nullptr) { - return nullptr; + const sockaddr *retval = nullptr; + ProxyTransaction *ssn = sm->get_server_txn(); + if (ssn != nullptr) { + NetVConnection *vc = ssn->get_netvc(); + if (vc != nullptr) { + retval = vc->get_local_addr(); + } } - - return vc->get_local_addr(); + return retval; } sockaddr const * @@ -5957,14 +5955,12 @@ TSHttpTxnServerPacketMarkSet(TSHttpTxn txnp, int mark) HttpSM *sm = (HttpSM *)txnp; // change the mark on an active server session - if (nullptr != sm->ua_txn) { - PoolableSession *ssn = sm->ua_txn->get_server_session(); - if (nullptr != ssn) { - NetVConnection *vc = ssn->get_netvc(); - if (vc != nullptr) { - vc->options.packet_mark = (uint32_t)mark; - vc->apply_options(); - } + ProxyTransaction *ssn = sm->get_server_txn(); + if (nullptr != ssn) { + NetVConnection *vc = ssn->get_netvc(); + if (vc != nullptr) { + vc->options.packet_mark = (uint32_t)mark; + vc->apply_options(); } } @@ -5999,14 +5995,12 @@ TSHttpTxnServerPacketTosSet(TSHttpTxn txnp, int tos) HttpSM *sm = (HttpSM *)txnp; // change the tos on an active server session - if (nullptr != sm->ua_txn) { - PoolableSession *ssn = sm->ua_txn->get_server_session(); - if (nullptr != ssn) { - NetVConnection *vc = ssn->get_netvc(); - if (vc != nullptr) { - vc->options.packet_tos = (uint32_t)tos; - vc->apply_options(); - } + ProxyTransaction *ssn = sm->get_server_txn(); + if (nullptr != ssn) { + NetVConnection *vc = ssn->get_netvc(); + if (vc != nullptr) { + vc->options.packet_tos = (uint32_t)tos; + vc->apply_options(); } } @@ -6041,14 +6035,12 @@ TSHttpTxnServerPacketDscpSet(TSHttpTxn txnp, int dscp) HttpSM *sm = (HttpSM *)txnp; // change the tos on an active server session - if (nullptr != sm->ua_txn) { - PoolableSession *ssn = sm->ua_txn->get_server_session(); - if (nullptr != ssn) { - NetVConnection *vc = ssn->get_netvc(); - if (vc != nullptr) { - vc->options.packet_tos = (uint32_t)dscp << 2; - vc->apply_options(); - } + ProxyTransaction *ssn = sm->get_server_txn(); + if (nullptr != ssn) { + NetVConnection *vc = ssn->get_netvc(); + if (vc != nullptr) { + vc->options.packet_tos = (uint32_t)dscp << 2; + vc->apply_options(); } } @@ -7829,18 +7821,16 @@ TSHttpTxnServerFdGet(TSHttpTxn txnp, int *fdp) HttpSM *sm = reinterpret_cast(txnp); *fdp = -1; - PoolableSession *ss = sm->get_server_session(); - if (ss == nullptr) { - return TS_ERROR; - } - - NetVConnection *vc = ss->get_netvc(); - if (vc == nullptr) { - return TS_ERROR; + TSReturnCode retval = TS_ERROR; + ProxyTransaction *ss = sm->get_server_txn(); + if (ss != nullptr) { + NetVConnection *vc = ss->get_netvc(); + if (vc != nullptr) { + *fdp = vc->get_socket(); + retval = TS_SUCCESS; + } } - - *fdp = vc->get_socket(); - return TS_SUCCESS; + return retval; } /* Matcher Utils */ From a3c65e557fca25041073db7581847658d1214038 Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Mon, 17 May 2021 21:12:07 +0000 Subject: [PATCH 2/6] Remove the intrusive hash map change --- include/tscore/IntrusiveHashMap.h | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/include/tscore/IntrusiveHashMap.h b/include/tscore/IntrusiveHashMap.h index f741340d391..f8dd340aff2 100644 --- a/include/tscore/IntrusiveHashMap.h +++ b/include/tscore/IntrusiveHashMap.h @@ -572,37 +572,20 @@ IntrusiveHashMap::erase(iterator const &loc) -> iterator --b->_count; } } - _list.erase(v); + _list.erase(loc); return zret; } template bool -IntrusiveHashMap::erase(value_type *v) +IntrusiveHashMap::erase(value_type *value) { - ++(this->iterator_for(v)); // get around no const_iterator -> iterator. - Bucket *b = this->bucket_for(H::key_of(v)); - value_type *nv = H::next_ptr(v); - value_type *limit = b->limit(); - if (b->_v == v) { // removed first element in bucket, update bucket - if (limit == nv) { // that was also the only element, deactivate bucket - _active_buckets.erase(b); - b->clear(); - } else { - b->_v = nv; - --b->_count; - } + auto loc = this->find(value); + if (loc != this->end()) { + this->erase(loc); + return true; } - _list.erase(v); - return true; - /* - auto loc = this->find(v); - if (loc != this->end()) { - this->erase(loc); - return true; - } - return false; - */ + return false; } template From e986eb2d19081cbbdd4c409fe088a8c6f18f2106 Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Mon, 17 May 2021 21:36:06 +0000 Subject: [PATCH 3/6] Fix missing override --- proxy/http/Http1ServerSession.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http/Http1ServerSession.h b/proxy/http/Http1ServerSession.h index 2a3c235e2eb..d59774a0f57 100644 --- a/proxy/http/Http1ServerSession.h +++ b/proxy/http/Http1ServerSession.h @@ -78,7 +78,7 @@ class Http1ServerSession : public PoolableSession void free() override; bool is_chunked_encoding_supported() const override; - IOBufferReader *get_reader(); + IOBufferReader *get_reader() override; IpEndpoint const &get_server_ip() const; ProxyTransaction *new_transaction() override; From bea41a52331542ee229eaa49830f30c1e32484c8 Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Mon, 17 May 2021 21:50:59 +0000 Subject: [PATCH 4/6] Make http3 happy --- proxy/http3/Http3Transaction.cc | 6 +++--- proxy/http3/Http3Transaction.h | 6 +++--- src/traffic_quic/traffic_quic.cc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/proxy/http3/Http3Transaction.cc b/proxy/http3/Http3Transaction.cc index 04afaa4a541..2e0b7435b8c 100644 --- a/proxy/http3/Http3Transaction.cc +++ b/proxy/http3/Http3Transaction.cc @@ -104,7 +104,7 @@ HQTransaction::cancel_inactivity_timeout() } void -HQTransaction::release(IOBufferReader *r) +HQTransaction::release() { this->do_io_close(); this->_sm = nullptr; @@ -224,13 +224,13 @@ HQTransaction::get_transaction_id() const } void -HQTransaction::increment_client_transactions_stat() +HQTransaction::increment_transactions_stat() { // TODO } void -HQTransaction::decrement_client_transactions_stat() +HQTransaction::decrement_transactions_stat() { // TODO } diff --git a/proxy/http3/Http3Transaction.h b/proxy/http3/Http3Transaction.h index 9e643d6df5c..8dccccfe83f 100644 --- a/proxy/http3/Http3Transaction.h +++ b/proxy/http3/Http3Transaction.h @@ -49,10 +49,10 @@ class HQTransaction : public ProxyTransaction void set_inactivity_timeout(ink_hrtime timeout_in) override; void cancel_inactivity_timeout() override; void transaction_done() override; - void release(IOBufferReader *r) override; + void release() override; int get_transaction_id() const override; - void increment_client_transactions_stat() override; - void decrement_client_transactions_stat() override; + void increment_transactions_stat() override; + void decrement_transactions_stat() override; // VConnection interface virtual VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index 51e673777a7..72964d0c9c3 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -305,7 +305,7 @@ HttpSM::handle_api_return() } void -HttpSM::attach_client_session(ProxyTransaction *, IOBufferReader *) +HttpSM::attach_client_session(ProxyTransaction *) { ink_abort("do not call stub"); } From 19d2e37d453738b03d1228a3c408e1f45afb55ba Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Mon, 17 May 2021 22:31:53 +0000 Subject: [PATCH 5/6] make clang-analyzer happy --- proxy/http/HttpSM.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index e1813e384bc..b149f59b0d7 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -3657,13 +3657,14 @@ HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p) // Now that we have communicated the post body, turn off the inactivity timeout // until the server starts sending data back - if (ua_txn && t_state.hdr_info.request_content_length > 0) { - ua_txn->cancel_inactivity_timeout(); + if (ua_txn) { + if (t_state.hdr_info.request_content_length > 0) { + ua_txn->cancel_inactivity_timeout(); + } + // Initiate another read to catch aborts + ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort; + ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); } - - // Initiate another read to catch aborts - ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort; - ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); break; default: ink_release_assert(0); From 7e9a61ce43e272189f1dde8e07db73491b64fbaf Mon Sep 17 00:00:00 2001 From: Susan Hinrichs Date: Tue, 25 May 2021 21:35:23 +0000 Subject: [PATCH 6/6] Incorproate comments --- proxy/PoolableSession.h | 2 +- proxy/ProxyTransaction.cc | 6 -- proxy/ProxyTransaction.h | 5 +- proxy/http/Http1ClientSession.cc | 2 +- proxy/http/Http1ServerSession.cc | 49 +++++----- proxy/http/Http1ServerSession.h | 4 +- proxy/http/HttpSM.cc | 151 ++++++++++++++----------------- proxy/http/HttpSM.h | 3 +- proxy/http/HttpSessionManager.cc | 34 ++----- proxy/http/HttpSessionManager.h | 8 +- 10 files changed, 113 insertions(+), 151 deletions(-) diff --git a/proxy/PoolableSession.h b/proxy/PoolableSession.h index 7545440b753..d98f93c2540 100644 --- a/proxy/PoolableSession.h +++ b/proxy/PoolableSession.h @@ -97,7 +97,7 @@ class PoolableSession : public ProxySession // singleton that keeps track of the connection counts. OutboundConnTrack::Group *conn_track_group = nullptr; - virtual IOBufferReader *get_reader() = 0; + virtual IOBufferReader *get_remote_reader() = 0; private: // Sessions become if authentication headers diff --git a/proxy/ProxyTransaction.cc b/proxy/ProxyTransaction.cc index 4dc199fc93d..bb63ebc4ce1 100644 --- a/proxy/ProxyTransaction.cc +++ b/proxy/ProxyTransaction.cc @@ -221,12 +221,6 @@ ProxyTransaction::has_request_body(int64_t request_content_length, bool is_chunk return request_content_length > 0 || is_chunked; } -bool -ProxyTransaction::is_read_closed() const -{ - return false; -} - void ProxyTransaction::attach_transaction(HttpSM *attach_sm) { diff --git a/proxy/ProxyTransaction.h b/proxy/ProxyTransaction.h index 21a17c902cd..82a07d6e757 100644 --- a/proxy/ProxyTransaction.h +++ b/proxy/ProxyTransaction.h @@ -49,7 +49,6 @@ class ProxyTransaction : public VConnection virtual void set_inactivity_timeout(ink_hrtime timeout_in); virtual void cancel_inactivity_timeout(); virtual void cancel_active_timeout(); - virtual bool is_read_closed() const; // Implement VConnection interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -130,7 +129,7 @@ class ProxyTransaction : public VConnection // HttpSessionAccept::Options upstream_outbound_options; // overwritable copy of options - IOBufferReader *get_reader(); + IOBufferReader *get_remote_reader(); protected: ProxySession *_proxy_ssn = nullptr; @@ -285,7 +284,7 @@ ProxyTransaction::adjust_thread(Continuation *cont, int event, void *data) } inline IOBufferReader * -ProxyTransaction::get_reader() +ProxyTransaction::get_remote_reader() { return _reader; } diff --git a/proxy/http/Http1ClientSession.cc b/proxy/http/Http1ClientSession.cc index 02a7e9b5e57..0bc42ffdc34 100644 --- a/proxy/http/Http1ClientSession.cc +++ b/proxy/http/Http1ClientSession.cc @@ -489,7 +489,7 @@ Http1ClientSession::attach_server_session(PoolableSession *ssession, bool transa // have it call the client session back. This IO also prevent // the server net conneciton from calling back a dead sm SET_HANDLER(&Http1ClientSession::state_keep_alive); - slave_ka_vio = ssession->do_io_read(this, INT64_MAX, ssession->get_reader()->mbuf); + slave_ka_vio = ssession->do_io_read(this, INT64_MAX, ssession->get_remote_reader()->mbuf); ink_assert(slave_ka_vio != ka_vio); // Transfer control of the write side as well diff --git a/proxy/http/Http1ServerSession.cc b/proxy/http/Http1ServerSession.cc index c0b730a4174..764cd810a14 100644 --- a/proxy/http/Http1ServerSession.cc +++ b/proxy/http/Http1ServerSession.cc @@ -100,40 +100,37 @@ Http1ServerSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB void Http1ServerSession::do_io_close(int alerrno) { - if (state == SSN_CLOSED) { // Already been closed - if (transact_count == released_transactions) { - this->destroy(); - } - return; - } + // Only do the close bookkeeping 1 time + if (state != SSN_CLOSED) { + ts::LocalBufferWriter<256> w; + bool debug_p = is_debug_tag_set("http_ss"); - ts::LocalBufferWriter<256> w; - bool debug_p = is_debug_tag_set("http_ss"); + state = SSN_CLOSED; - state = SSN_CLOSED; + if (debug_p) { + w.print("[{}] session close: nevtc {:x}", con_id, _vc); + } - if (debug_p) { - w.print("[{}] session close: nevtc {:x}", con_id, _vc); - } + HTTP_SUM_GLOBAL_DYN_STAT(http_current_server_connections_stat, -1); // Make sure to work on the global stat + HTTP_SUM_DYN_STAT(http_transactions_per_server_con, transact_count); - HTTP_SUM_GLOBAL_DYN_STAT(http_current_server_connections_stat, -1); // Make sure to work on the global stat - HTTP_SUM_DYN_STAT(http_transactions_per_server_con, transact_count); + // Update upstream connection tracking data if present. + this->release_outbound_connection_tracking(); - // Update upstream connection tracking data if present. - this->release_outbound_connection_tracking(); + if (debug_p) { + Debug("http_ss", "%.*s", static_cast(w.size()), w.data()); + } - if (debug_p) { - Debug("http_ss", "%.*s", static_cast(w.size()), w.data()); - } + if (_vc) { + _vc->do_io_close(alerrno); + } + _vc = nullptr; - if (_vc) { - _vc->do_io_close(alerrno); + if (to_parent_proxy) { + HTTP_DECREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); + } } - _vc = nullptr; - if (to_parent_proxy) { - HTTP_DECREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); - } if (transact_count == released_transactions) { this->destroy(); } @@ -254,6 +251,6 @@ Http1ServerSession::new_transaction() state = SSN_IN_USE; transact_count++; ink_release_assert(transact_count == (released_transactions + 1)); - trans.set_reader(this->get_reader()); + trans.set_reader(this->get_remote_reader()); return &trans; } diff --git a/proxy/http/Http1ServerSession.h b/proxy/http/Http1ServerSession.h index d59774a0f57..befdc282eae 100644 --- a/proxy/http/Http1ServerSession.h +++ b/proxy/http/Http1ServerSession.h @@ -78,7 +78,7 @@ class Http1ServerSession : public PoolableSession void free() override; bool is_chunked_encoding_supported() const override; - IOBufferReader *get_reader() override; + IOBufferReader *get_remote_reader() override; IpEndpoint const &get_server_ip() const; ProxyTransaction *new_transaction() override; @@ -113,7 +113,7 @@ extern ClassAllocator httpServerSessionAllocator; // INLINE inline IOBufferReader * -Http1ServerSession::get_reader() +Http1ServerSession::get_remote_reader() { return _reader; }; diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index b149f59b0d7..36b29e002b7 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -604,7 +604,7 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc) // Prepare raw reader which will live until we are sure this is HTTP indeed if (is_transparent_passthrough_allowed() || (ssl_vc && ssl_vc->decrypt_tunnel())) { - ua_raw_buffer_reader = ua_txn->get_reader()->clone(); + ua_raw_buffer_reader = ua_txn->get_remote_reader()->clone(); } // We first need to run the transaction start hook. Since @@ -641,7 +641,7 @@ HttpSM::setup_client_read_request_header() { ink_assert(ua_entry->vc_handler == &HttpSM::state_read_client_request_header); - ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); + ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_remote_reader()->mbuf); // The header may already be in the buffer if this // a request from a keep-alive connection handleEvent(VC_EVENT_READ_READY, ua_entry->read_vio); @@ -732,7 +732,7 @@ HttpSM::state_read_client_request_header(int event, void *data) // time we've been called. The timeout had been set to // the accept timeout by the ProxyTransaction // - if ((ua_txn->get_reader()->read_avail() > 0) && (client_request_hdr_bytes == 0)) { + if ((ua_txn->get_remote_reader()->read_avail() > 0) && (client_request_hdr_bytes == 0)) { milestones[TS_MILESTONE_UA_FIRST_READ] = Thread::get_hrtime(); ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in)); } @@ -741,7 +741,7 @@ HttpSM::state_read_client_request_header(int event, void *data) ///////////////////// ParseResult state = t_state.hdr_info.client_request.parse_req( - &http_parser, ua_txn->get_reader(), &bytes_used, ua_entry->eos, t_state.http_config_param->strict_uri_parsing, + &http_parser, ua_txn->get_remote_reader(), &bytes_used, ua_entry->eos, t_state.http_config_param->strict_uri_parsing, t_state.http_config_param->http_request_line_max_size, t_state.http_config_param->http_hdr_field_max_size); client_request_hdr_bytes += bytes_used; @@ -765,7 +765,7 @@ HttpSM::state_read_client_request_header(int event, void *data) // If we had a GET request that has data after the // get request, do blind tunnel } else if (state == PARSE_RESULT_DONE && t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_GET && - ua_txn->get_reader()->read_avail() > 0 && !t_state.hdr_info.client_request.is_keep_alive_set()) { + ua_txn->get_remote_reader()->read_avail() > 0 && !t_state.hdr_info.client_request.is_keep_alive_set()) { do_blind_tunnel = true; } if (do_blind_tunnel) { @@ -951,10 +951,11 @@ HttpSM::wait_for_full_body() // Next order of business if copy the remaining data from the // header buffer into new buffer - int64_t post_bytes = chunked ? INT64_MAX : t_state.hdr_info.request_content_length; - client_request_body_bytes = post_buffer->write(ua_txn->get_reader(), chunked ? ua_txn->get_reader()->read_avail() : post_bytes); + int64_t post_bytes = chunked ? INT64_MAX : t_state.hdr_info.request_content_length; + client_request_body_bytes = + post_buffer->write(ua_txn->get_remote_reader(), chunked ? ua_txn->get_remote_reader()->read_avail() : post_bytes); - ua_txn->get_reader()->consume(client_request_body_bytes); + ua_txn->get_remote_reader()->consume(client_request_body_bytes); p = tunnel.add_producer(ua_entry->vc, post_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_BUFFER_READ, "ua post buffer"); if (chunked) { tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT); @@ -1085,7 +1086,7 @@ HttpSM::setup_push_read_response_header() // since if the response is finished, we won't get any // additional callbacks int resp_hdr_state = VC_EVENT_CONT; - if (ua_txn->get_reader()->read_avail() > 0) { + if (ua_txn->get_remote_reader()->read_avail() > 0) { if (ua_entry->eos) { resp_hdr_state = state_read_push_response_header(VC_EVENT_EOS, ua_entry->read_vio); } else { @@ -1098,7 +1099,7 @@ HttpSM::setup_push_read_response_header() // the cache if (resp_hdr_state == VC_EVENT_CONT) { ink_assert(ua_entry->eos == false); - ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); + ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_txn->get_remote_reader()->mbuf); } } @@ -1129,10 +1130,10 @@ HttpSM::state_read_push_response_header(int event, void *data) } int state = PARSE_RESULT_CONT; - while (ua_txn->get_reader()->read_avail() && state == PARSE_RESULT_CONT) { - const char *start = ua_txn->get_reader()->start(); + while (ua_txn->get_remote_reader()->read_avail() && state == PARSE_RESULT_CONT) { + const char *start = ua_txn->get_remote_reader()->start(); const char *tmp = start; - int64_t data_size = ua_txn->get_reader()->block_read_avail(); + int64_t data_size = ua_txn->get_remote_reader()->block_read_avail(); ink_assert(data_size >= 0); ///////////////////// @@ -1144,7 +1145,7 @@ HttpSM::state_read_push_response_header(int event, void *data) int64_t bytes_used = tmp - start; ink_release_assert(bytes_used <= data_size); - ua_txn->get_reader()->consume(bytes_used); + ua_txn->get_remote_reader()->consume(bytes_used); pushed_response_hdr_bytes += bytes_used; client_request_body_bytes += bytes_used; } @@ -1153,7 +1154,7 @@ HttpSM::state_read_push_response_header(int event, void *data) // call the parser with (eof == true) so it can determine // whether to use the response as is or declare a parse error if (ua_entry->eos) { - const char *end = ua_txn->get_reader()->start(); + const char *end = ua_txn->get_remote_reader()->start(); state = t_state.hdr_info.server_response.parse_resp(&http_parser, &end, end, true // We are out of data after server eos ); ink_release_assert(state == PARSE_RESULT_DONE || state == PARSE_RESULT_ERROR); @@ -1731,7 +1732,7 @@ HttpSM::handle_api_return() if (t_state.is_websocket) { HTTP_INCREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat); if (server_txn) { - initial_data = server_txn->get_reader(); + initial_data = server_txn->get_remote_reader(); } if (ua_txn) { @@ -1799,14 +1800,6 @@ HttpSM::handle_api_return() } } -void -HttpSM::set_server_txn(ProxyTransaction *txn) -{ - ink_release_assert(server_txn == nullptr); - server_txn = txn; - server_txn->attach_transaction(this); -} - PoolableSession * HttpSM::create_server_session(NetVConnection *netvc) { @@ -1838,24 +1831,18 @@ HttpSM::create_server_session(NetVConnection *netvc) return retval; } -void -HttpSM::create_server_txn(NetVConnection *netvc, PoolableSession *new_session) +bool +HttpSM::create_server_txn(PoolableSession *new_session) { - if (new_session == nullptr) { - new_session = this->create_server_session(netvc); - } - - server_txn = new_session->new_transaction(); - server_txn->attach_transaction(this); - if (t_state.current.request_to == HttpTransact::PARENT_PROXY) { - new_session->to_parent_proxy = true; - HTTP_INCREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); - HTTP_INCREMENT_DYN_STAT(http_total_parent_proxy_connections_stat); - } else { - new_session->to_parent_proxy = false; + bool retval = false; + server_txn = new_session->new_transaction(); + if (server_txn != nullptr) { + server_txn->attach_transaction(this); + server_txn->do_io_write(this, 0, nullptr); + attach_server_session(); + retval = true; } - - server_txn->do_io_write(this, 0, nullptr); + return retval; } ////////////////////////////////////////////////////////////////////////////// @@ -1877,9 +1864,17 @@ HttpSM::state_http_server_open(int event, void *data) switch (event) { case NET_EVENT_OPEN: { - NetVConnection *netvc = static_cast(data); - UnixNetVConnection *vc = static_cast(data); - this->create_server_txn(netvc); + NetVConnection *netvc = static_cast(data); + UnixNetVConnection *vc = static_cast(data); + PoolableSession *new_session = this->create_server_session(netvc); + if (t_state.current.request_to == HttpTransact::PARENT_PROXY) { + new_session->to_parent_proxy = true; + HTTP_INCREMENT_DYN_STAT(http_current_parent_proxy_connections_stat); + HTTP_INCREMENT_DYN_STAT(http_total_parent_proxy_connections_stat); + } else { + new_session->to_parent_proxy = false; + } + this->create_server_txn(new_session); // Since the UnixNetVConnection::action_ or SocksEntry::action_ may be returned from netProcessor.connect_re, and the // SocksEntry::action_ will be copied into UnixNetVConnection::action_ before call back NET_EVENT_OPEN from SocksEntry::free(), @@ -1887,8 +1882,6 @@ HttpSM::state_http_server_open(int event, void *data) ink_release_assert(pending_action.is_empty() || pending_action.get_continuation() == vc->get_action()->continuation); pending_action = nullptr; - attach_server_session(); - if (this->plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) { SMDebug("http", "[%" PRId64 "] setting handler for TCP handshake", sm_id); // Just want to get a write-ready event so we know that the TCP handshake is complete. @@ -1896,11 +1889,11 @@ HttpSM::state_http_server_open(int event, void *data) int64_t nbytes = 1; if (t_state.txn_conf->proxy_protocol_out >= 0) { - nbytes = - do_outbound_proxy_protocol(server_txn->get_reader()->mbuf, vc, ua_txn->get_netvc(), t_state.txn_conf->proxy_protocol_out); + nbytes = do_outbound_proxy_protocol(server_txn->get_remote_reader()->mbuf, vc, ua_txn->get_netvc(), + t_state.txn_conf->proxy_protocol_out); } - server_entry->write_vio = server_txn->do_io_write(this, nbytes, server_txn->get_reader()); + server_entry->write_vio = server_txn->do_io_write(this, nbytes, server_txn->get_remote_reader()); // Pre-emptively set a server connect failure that will be cleared once a WRITE_READY is received from origin or // bytes are received back @@ -2029,7 +2022,7 @@ HttpSM::state_read_server_response_header(int event, void *data) // tokenize header // ///////////////////// ParseResult state = - t_state.hdr_info.server_response.parse_resp(&http_parser, server_txn->get_reader(), &bytes_used, server_entry->eos); + t_state.hdr_info.server_response.parse_resp(&http_parser, server_txn->get_remote_reader(), &bytes_used, server_entry->eos); server_response_hdr_bytes += bytes_used; @@ -2199,7 +2192,7 @@ HttpSM::state_send_server_request_header(int event, void *data) // from both read and write sides of a connection so it should be handled correctly (close tunnels, // deallocate, etc) here with handle_server_setup_error(). Otherwise we might hang due to not shutting // down and never receiving another event again. - /*if (server_txn->get_reader()->read_avail() > 0 && callout_state == HTTP_API_NO_CALLOUT) { + /*if (server_txn->get_remote_reader()->read_avail() > 0 && callout_state == HTTP_API_NO_CALLOUT) { break; } */ @@ -3451,7 +3444,7 @@ HttpSM::tunnel_handler_ua(int event, HttpTunnelConsumer *c) vc_table.remove_entry(this->ua_entry); ua_txn->do_io_close(); } else { - ink_assert(ua_txn->get_reader() != nullptr); + ink_assert(ua_txn->get_remote_reader() != nullptr); vc_table.remove_entry(this->ua_entry); ua_txn->release(); } @@ -3663,7 +3656,7 @@ HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p) } // Initiate another read to catch aborts ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort; - ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); + ua_entry->read_vio = p->vc->do_io_read(this, INT64_MAX, ua_txn->get_remote_reader()->mbuf); } break; default: @@ -3778,7 +3771,7 @@ HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c) // do not shut down the client read if (enable_redirection) { if (ua_producer->vc_type == HT_STATIC && event != VC_EVENT_ERROR && event != VC_EVENT_EOS) { - ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); + ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_remote_reader()->mbuf); // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ); } else { if (ua_producer->vc_type == HT_STATIC && t_state.redirect_info.redirect_in_process) { @@ -3786,7 +3779,7 @@ HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c) } } } else { - ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_reader()->mbuf); + ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_txn->get_remote_reader()->mbuf); // we should not shutdown read side of the client here to prevent sending a reset // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ); } // end of added logic @@ -5118,9 +5111,7 @@ HttpSM::do_http_server_open(bool raw) if (ats_ip_addr_port_eq(existing_ss->get_remote_addr(), &t_state.current.server->dst_addr.sa)) { ua_txn->attach_server_session(nullptr); existing_ss->set_active(); - server_txn = existing_ss->new_transaction(); - server_txn->attach_transaction(this); - this->attach_server_session(); + this->create_server_txn(existing_ss); hsm_release_assert(server_txn != nullptr); handle_http_server_open(); return; @@ -5556,9 +5547,10 @@ HttpSM::release_server_session(bool serve_from_cache) } if (server_entry) { - server_entry->vc = nullptr; - server_entry->read_vio = server_entry->write_vio = nullptr; - server_entry = nullptr; + server_entry->vc = nullptr; + server_entry->read_vio = nullptr; + server_entry->write_vio = nullptr; + server_entry = nullptr; } } @@ -5602,7 +5594,7 @@ HttpSM::handle_post_failure() t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE; t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE; - if (server_txn->get_reader()->read_avail() > 0) { + if (server_txn->get_remote_reader()->read_avail() > 0) { tunnel.deallocate_buffers(); tunnel.reset(); // There's data from the server so try to read the header @@ -5832,7 +5824,7 @@ void HttpSM::do_drain_request_body(HTTPHdr &response) { int64_t content_length = t_state.hdr_info.client_request.get_content_length(); - int64_t avail = ua_txn->get_reader()->read_avail(); + int64_t avail = ua_txn->get_remote_reader()->read_avail(); if (t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING) { SMDebug("http", "Chunked body, setting the response to non-keepalive"); @@ -5844,7 +5836,7 @@ HttpSM::do_drain_request_body(HTTPHdr &response) SMDebug("http", "entire body is in the buffer, consuming"); int64_t act_on = (avail < content_length) ? avail : content_length; client_request_body_bytes = act_on; - ua_txn->get_reader()->consume(act_on); + ua_txn->get_remote_reader()->consume(act_on); } else { SMDebug("http", "entire body is not in the buffer, setting the response to non-keepalive"); goto close_connection; @@ -5906,13 +5898,10 @@ HttpSM::do_setup_post_tunnel(HttpVC_t to_vc_type) // Next order of business if copy the remaining data from the // header buffer into new buffer - client_request_body_bytes = post_buffer->write(ua_txn->get_reader(), chunked ? ua_txn->get_reader()->read_avail() : post_bytes); + client_request_body_bytes = + post_buffer->write(ua_txn->get_remote_reader(), chunked ? ua_txn->get_remote_reader()->read_avail() : post_bytes); - ua_txn->get_reader()->consume(client_request_body_bytes); - // The user agent has already sent all it has - if (ua_txn->is_read_closed()) { - post_bytes = client_request_body_bytes; - } + ua_txn->get_remote_reader()->consume(client_request_body_bytes); p = tunnel.add_producer(ua_entry->vc, post_bytes - transfered_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_HTTP_CLIENT, "user agent post"); } @@ -6187,7 +6176,7 @@ HttpSM::attach_server_session() // first tunnel was sometimes behind handled by the consumer of the // first tunnel instead of the producer of the second tunnel. // The real read is setup in setup_server_read_response_header() - server_entry->read_vio = server_txn->do_io_read(this, 0, server_txn->get_reader()->mbuf); + server_entry->read_vio = server_txn->do_io_read(this, 0, server_txn->get_remote_reader()->mbuf); // Transfer control of the write side as well server_entry->write_vio = server_txn->do_io_write(this, 0, nullptr); @@ -6274,7 +6263,7 @@ HttpSM::setup_server_read_response_header() ink_assert(ua_txn != nullptr || t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE || t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY); - ink_assert(server_txn != nullptr && server_txn->get_reader() != nullptr); + ink_assert(server_txn != nullptr && server_txn->get_remote_reader() != nullptr); // Now that we've got the ability to read from the // server, setup to read the response header @@ -6297,13 +6286,13 @@ HttpSM::setup_server_read_response_header() ink_assert(server_entry->read_vio); // The tunnel from OS to UA is now setup. Ready to read the response - server_entry->read_vio = server_txn->do_io_read(this, INT64_MAX, server_txn->get_reader()->mbuf); + server_entry->read_vio = server_txn->do_io_read(this, INT64_MAX, server_txn->get_remote_reader()->mbuf); // If there is anything in the buffer call the parsing routines // since if the response is finished, we won't get any // additional callbacks - if (server_txn->get_reader()->read_avail() > 0) { + if (server_txn->get_remote_reader()->read_avail() > 0) { state_read_server_response_header((server_entry->eos) ? VC_EVENT_EOS : VC_EVENT_READ_READY, server_entry->read_vio); } } @@ -6607,7 +6596,7 @@ HttpSM::server_transfer_init(MIOBuffer *buf, int hdr_size) if (server_entry->eos == true) { // The server has shutdown on us already so the only data // we'll get is already in the buffer - nbytes = server_txn->get_reader()->read_avail() + hdr_size; + nbytes = server_txn->get_remote_reader()->read_avail() + hdr_size; } else if (t_state.hdr_info.response_content_length == HTTP_UNDEFINED_CL) { nbytes = -1; } else { @@ -6620,14 +6609,14 @@ HttpSM::server_transfer_init(MIOBuffer *buf, int hdr_size) } // Next order of business if copy the remaining data from the header buffer into new buffer. - int64_t server_response_pre_read_bytes = buf->write(server_txn->get_reader(), to_copy); - server_txn->get_reader()->consume(server_response_pre_read_bytes); + int64_t server_response_pre_read_bytes = buf->write(server_txn->get_remote_reader(), to_copy); + server_txn->get_remote_reader()->consume(server_response_pre_read_bytes); // If we know the length & copied the entire body // of the document out of the header buffer make // sure the server isn't screwing us by having sent too // much. If it did, we want to close the server connection - if (server_response_pre_read_bytes == to_copy && server_txn->get_reader()->read_avail() > 0) { + if (server_response_pre_read_bytes == to_copy && server_txn->get_remote_reader()->read_avail() > 0) { t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE; } @@ -6870,7 +6859,7 @@ HttpSM::setup_push_transfer_to_cache() // The ua has shutdown on us already so the only data // we'll get is already in the buffer. Make sure it // fulfills the stated length - int64_t avail = ua_txn->get_reader()->read_avail(); + int64_t avail = ua_txn->get_remote_reader()->read_avail(); if (avail < nbytes) { // Client failed to send the body, it's gone. Kill the @@ -6881,8 +6870,8 @@ HttpSM::setup_push_transfer_to_cache() } // Next order of business is copy the remaining data from the // header buffer into new buffer. - pushed_response_body_bytes = buf->write(ua_txn->get_reader(), nbytes); - ua_txn->get_reader()->consume(pushed_response_body_bytes); + pushed_response_body_bytes = buf->write(ua_txn->get_remote_reader(), nbytes); + ua_txn->get_remote_reader()->consume(pushed_response_body_bytes); client_request_body_bytes += pushed_response_body_bytes; HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_push); @@ -6928,7 +6917,7 @@ HttpSM::setup_blind_tunnel(bool send_response_hdr, IOBufferReader *initial) // Next order of business if copy the remaining data from the // header buffer into new buffer - client_request_body_bytes += from_ua_buf->write(ua_txn->get_reader()); + client_request_body_bytes += from_ua_buf->write(ua_txn->get_remote_reader()); HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler); diff --git a/proxy/http/HttpSM.h b/proxy/http/HttpSM.h index 9228556e722..9bff26e04c0 100644 --- a/proxy/http/HttpSM.h +++ b/proxy/http/HttpSM.h @@ -269,9 +269,8 @@ class HttpSM : public Continuation, public PluginUserArgs // holding the lock for the server session void attach_server_session(); - void set_server_txn(ProxyTransaction *txn); - void create_server_txn(NetVConnection *netvc, PoolableSession *new_session = nullptr); PoolableSession *create_server_session(NetVConnection *netvc); + bool create_server_txn(PoolableSession *new_session); HTTPVersion get_server_version(HTTPHdr &hdr) const; diff --git a/proxy/http/HttpSessionManager.cc b/proxy/http/HttpSessionManager.cc index 1b74d330c6c..0874f100c0b 100644 --- a/proxy/http/HttpSessionManager.cc +++ b/proxy/http/HttpSessionManager.cc @@ -166,10 +166,8 @@ ServerSessionPool::acquireSession(sockaddr const *addr, CryptoHash const &hostna if (zret == HSM_DONE) { to_return = first; this->removeSession(to_return); - } else { - if (first != m_fqdn_pool.end()) { - Debug("http_ss", "Failed find entry due to name mismatch %s", sm->t_state.current.server->name); - } + } else if (first != m_fqdn_pool.end()) { + Debug("http_ss", "Failed find entry due to name mismatch %s", sm->t_state.current.server->name); } } else if (TS_SERVER_SESSION_SHARING_MATCH_MASK_IP & match_style) { // matching is not disabled. auto first = m_ip_pool.find(addr); @@ -208,7 +206,7 @@ ServerSessionPool::releaseSession(PoolableSession *ss) // to remove the connection from our lists // Actually need to have a buffer here, otherwise the vc is // disabled - ss->do_io_read(this, INT64_MAX, ss->get_reader()->mbuf); + ss->do_io_read(this, INT64_MAX, ss->get_remote_reader()->mbuf); // Transfer control of the write side as well ss->do_io_write(this, 0, nullptr); @@ -359,8 +357,7 @@ HttpSessionManager::acquire_session(HttpSM *sm, sockaddr const *ip, const char * ServerSessionPool::validate_cert(sm, to_return->get_netvc()))) { Debug("http_ss", "[%" PRId64 "] [acquire session] returning attached session ", to_return->connection_id()); to_return->state = PoolableSession::SSN_IN_USE; - sm->set_server_txn(to_return->new_transaction()); - sm->attach_server_session(); + sm->create_server_txn(to_return); return HSM_DONE; } // Release this session back to the main session pool and @@ -446,14 +443,10 @@ HttpSessionManager::_acquire_session(sockaddr const *ip, CryptoHash const &hostn } if (to_return) { - ProxyTransaction *trans = to_return->new_transaction(); - if (trans) { + if (sm->create_server_txn(to_return)) { Debug("http_ss", "[%" PRId64 "] [acquire session] return session from shared pool", to_return->connection_id()); to_return->state = PoolableSession::SSN_IN_USE; - // the attach_server_session will issue the do_io_read under the sm lock - sm->set_server_txn(trans); - sm->attach_server_session(); - retval = HSM_DONE; + retval = HSM_DONE; } else { Debug("http_ss", "[%" PRId64 "] [acquire session] failed to get transaction on session from shared pool", to_return->connection_id()); @@ -498,28 +491,19 @@ ServerSessionPool::removeSession(PoolableSession *to_remove) char peer_ip[INET6_ADDRPORTSTRLEN]; if (is_debug_tag_set("http_ss")) { ats_ip_nptop(to_remove->get_remote_addr(), peer_ip, sizeof(peer_ip)); - Debug("http_ss", "Remove session %p %s m_fqdn_pool size=%" PRId64 " m_ip_pool_size=%" PRId64, to_remove, peer_ip, - m_fqdn_pool.count(), m_ip_pool.count()); + Debug("http_ss", "Remove session %p %s m_fqdn_pool size=%zu m_ip_pool_size=%zu", to_remove, peer_ip, m_fqdn_pool.count(), + m_ip_pool.count()); } m_fqdn_pool.erase(to_remove); if (m_ip_pool.erase(to_remove)) { HTTP_DECREMENT_DYN_STAT(http_pooled_server_connections_stat); } if (is_debug_tag_set("http_ss")) { - Debug("http_ss", "After Remove session %p m_fqdn_pool size=%" PRId64 " m_ip_pool_size=%" PRId64, to_remove, m_fqdn_pool.count(), + Debug("http_ss", "After Remove session %p m_fqdn_pool size=%zu m_ip_pool_size=%zu", to_remove, m_fqdn_pool.count(), m_ip_pool.count()); } } -void -ServerSessionPool::testSession(PoolableSession *ss) -{ - auto fqdn_iter = m_fqdn_pool.find(ss); - ink_release_assert(fqdn_iter == m_fqdn_pool.end()); - auto ip_iter = m_ip_pool.find(ss); - ink_release_assert(ip_iter == m_ip_pool.end()); -} - void ServerSessionPool::addSession(PoolableSession *ss) { diff --git a/proxy/http/HttpSessionManager.h b/proxy/http/HttpSessionManager.h index 4a7c642edec..8ce9a89baab 100644 --- a/proxy/http/HttpSessionManager.h +++ b/proxy/http/HttpSessionManager.h @@ -67,16 +67,16 @@ class ServerSessionPool : public Continuation static bool validate_host_sni(HttpSM *sm, NetVConnection *netvc); static bool validate_sni(HttpSM *sm, NetVConnection *netvc); static bool validate_cert(HttpSM *sm, NetVConnection *netvc); - void removeSession(PoolableSession *ssn); - void addSession(PoolableSession *ssn); - void testSession(PoolableSession *ssn); int count() const { return m_ip_pool.count(); } -protected: +private: + void removeSession(PoolableSession *ssn); + void addSession(PoolableSession *ssn); + using IPTable = IntrusiveHashMap; using FQDNTable = IntrusiveHashMap;