1 /** @file
2 
3   ProxyTransaction - Base class for protocol client transactions.
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include "http/HttpSM.h"
25 #include "Plugin.h"
26 
27 #define HttpTxnDebug(fmt, ...) SsnDebug(this, "http_txn", fmt, __VA_ARGS__)
28 
29 extern ClassAllocator<HttpSM> httpSMAllocator;
30 
ProxyTransaction(ProxySession * session)31 ProxyTransaction::ProxyTransaction(ProxySession *session) : VConnection(nullptr), _proxy_ssn(session) {}
32 
~ProxyTransaction()33 ProxyTransaction::~ProxyTransaction()
34 {
35   this->_sm = nullptr;
36   this->mutex.clear();
37 }
38 
39 void
new_transaction(bool from_early_data)40 ProxyTransaction::new_transaction(bool from_early_data)
41 {
42   ink_release_assert(_sm == nullptr);
43 
44   // Defensive programming, make sure nothing persists across
45   // connection re-use
46 
47   ink_release_assert(_proxy_ssn != nullptr);
48   _sm = THREAD_ALLOC(httpSMAllocator, this_thread());
49   _sm->init(from_early_data);
50   HttpTxnDebug("[%" PRId64 "] Starting transaction %d using sm [%" PRId64 "]", _proxy_ssn->connection_id(),
51                _proxy_ssn->get_transact_count(), _sm->sm_id);
52 
53   // PI tag valid only for internal requests
54   if (this->get_netvc()->get_is_internal_request()) {
55     PluginIdentity *pi = dynamic_cast<PluginIdentity *>(this->get_netvc());
56     if (pi) {
57       _sm->plugin_tag = pi->getPluginTag();
58       _sm->plugin_id  = pi->getPluginId();
59     }
60   }
61 
62   this->increment_client_transactions_stat();
63   _sm->attach_client_session(this, _reader);
64 }
65 
66 bool
attach_server_session(PoolableSession * ssession,bool transaction_done)67 ProxyTransaction::attach_server_session(PoolableSession *ssession, bool transaction_done)
68 {
69   return _proxy_ssn->attach_server_session(ssession, transaction_done);
70 }
71 
72 void
set_rx_error_code(ProxyError e)73 ProxyTransaction::set_rx_error_code(ProxyError e)
74 {
75   if (this->_sm) {
76     this->_sm->t_state.client_info.rx_error_code = e;
77   }
78 }
79 
80 void
set_tx_error_code(ProxyError e)81 ProxyTransaction::set_tx_error_code(ProxyError e)
82 {
83   if (this->_sm) {
84     this->_sm->t_state.client_info.tx_error_code = e;
85   }
86 }
87 
88 NetVConnection *
get_netvc() const89 ProxyTransaction::get_netvc() const
90 {
91   return (_proxy_ssn) ? _proxy_ssn->get_netvc() : nullptr;
92 }
93 
94 bool
is_first_transaction() const95 ProxyTransaction::is_first_transaction() const
96 {
97   return _proxy_ssn->get_transact_count() == 1;
98 }
99 
100 void
set_session_active()101 ProxyTransaction::set_session_active()
102 {
103   if (_proxy_ssn) {
104     _proxy_ssn->set_session_active();
105   }
106 }
107 
108 void
clear_session_active()109 ProxyTransaction::clear_session_active()
110 {
111   if (_proxy_ssn) {
112     _proxy_ssn->clear_session_active();
113   }
114 }
115 
116 const IpAllow::ACL &
get_acl() const117 ProxyTransaction::get_acl() const
118 {
119   return _proxy_ssn ? _proxy_ssn->acl : IpAllow::DENY_ALL_ACL;
120 }
121 
122 // outbound values Set via the server port definition.  Really only used for Http1 at the moment
123 in_port_t
get_outbound_port() const124 ProxyTransaction::get_outbound_port() const
125 {
126   return upstream_outbound_options.outbound_port;
127 }
128 void
set_outbound_port(in_port_t port)129 ProxyTransaction::set_outbound_port(in_port_t port)
130 {
131   upstream_outbound_options.outbound_port = port;
132 }
133 
134 IpAddr
get_outbound_ip4() const135 ProxyTransaction::get_outbound_ip4() const
136 {
137   return upstream_outbound_options.outbound_ip4;
138 }
139 
140 IpAddr
get_outbound_ip6() const141 ProxyTransaction::get_outbound_ip6() const
142 {
143   return upstream_outbound_options.outbound_ip6;
144 }
145 
146 void
set_outbound_ip(const IpAddr & new_addr)147 ProxyTransaction::set_outbound_ip(const IpAddr &new_addr)
148 {
149   if (new_addr.isIp4()) {
150     upstream_outbound_options.outbound_ip4 = new_addr;
151   } else if (new_addr.isIp6()) {
152     upstream_outbound_options.outbound_ip6 = new_addr;
153   } else {
154     upstream_outbound_options.outbound_ip4.invalidate();
155     upstream_outbound_options.outbound_ip6.invalidate();
156   }
157 }
158 bool
is_outbound_transparent() const159 ProxyTransaction::is_outbound_transparent() const
160 {
161   return upstream_outbound_options.f_outbound_transparent;
162 }
163 
164 void
set_outbound_transparent(bool flag)165 ProxyTransaction::set_outbound_transparent(bool flag)
166 {
167   upstream_outbound_options.f_outbound_transparent = flag;
168 }
169 
170 int
get_transaction_priority_weight() const171 ProxyTransaction::get_transaction_priority_weight() const
172 {
173   return 0;
174 }
175 
176 int
get_transaction_priority_dependence() const177 ProxyTransaction::get_transaction_priority_dependence() const
178 {
179   return 0;
180 }
181 
182 void
transaction_done()183 ProxyTransaction::transaction_done()
184 {
185   SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
186   this->decrement_client_transactions_stat();
187 }
188 
189 // Implement VConnection interface.
190 VIO *
do_io_read(Continuation * c,int64_t nbytes,MIOBuffer * buf)191 ProxyTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
192 {
193   return _proxy_ssn->do_io_read(c, nbytes, buf);
194 }
195 VIO *
do_io_write(Continuation * c,int64_t nbytes,IOBufferReader * buf,bool owner)196 ProxyTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
197 {
198   return _proxy_ssn->do_io_write(c, nbytes, buf, owner);
199 }
200 
201 void
do_io_close(int lerrno)202 ProxyTransaction::do_io_close(int lerrno)
203 {
204   _proxy_ssn->do_io_close(lerrno);
205   // this->destroy(); Parent owns this data structure.  No need for separate destroy.
206 }
207 
208 void
do_io_shutdown(ShutdownHowTo_t howto)209 ProxyTransaction::do_io_shutdown(ShutdownHowTo_t howto)
210 {
211   _proxy_ssn->do_io_shutdown(howto);
212 }
213 
214 void
reenable(VIO * vio)215 ProxyTransaction::reenable(VIO *vio)
216 {
217   _proxy_ssn->reenable(vio);
218 }
219 
220 bool
has_request_body(int64_t request_content_length,bool is_chunked) const221 ProxyTransaction::has_request_body(int64_t request_content_length, bool is_chunked) const
222 {
223   return request_content_length > 0 || is_chunked;
224 }
225 
226 bool
allow_half_open() const227 ProxyTransaction::allow_half_open() const
228 {
229   return false;
230 }
231