1 /** @file
2 
3   HTTP state machine
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 
25 #include "../ProxyTransaction.h"
26 #include "HttpSM.h"
27 #include "HttpTransact.h"
28 #include "HttpTransactHeaders.h"
29 #include "ProxyConfig.h"
30 #include "Http1ServerSession.h"
31 #include "HttpDebugNames.h"
32 #include "HttpSessionManager.h"
33 #include "P_Cache.h"
34 #include "P_Net.h"
35 #include "StatPages.h"
36 #include "Log.h"
37 #include "LogAccess.h"
38 #include "PluginVC.h"
39 #include "ReverseProxy.h"
40 #include "RemapProcessor.h"
41 #include "Transform.h"
42 #include "P_SSLConfig.h"
43 #include "P_SSLSNI.h"
44 #include "HttpPages.h"
45 #include "IPAllow.h"
46 
47 #include "ProxyProtocol.h"
48 
49 #include "tscore/I_Layout.h"
50 #include "tscore/bwf_std_format.h"
51 #include "ts/sdt.h"
52 
53 #include <openssl/ossl_typ.h>
54 #include <openssl/ssl.h>
55 #include <algorithm>
56 #include <atomic>
57 #include <logging/Log.h>
58 
59 #define DEFAULT_RESPONSE_BUFFER_SIZE_INDEX 6 // 8K
60 #define DEFAULT_REQUEST_BUFFER_SIZE_INDEX 6  // 8K
61 #define MIN_CONFIG_BUFFER_SIZE_INDEX 5       // 4K
62 
63 #define hsm_release_assert(EX)              \
64   {                                         \
65     if (!(EX)) {                            \
66       this->dump_state_on_assert();         \
67       _ink_assert(#EX, __FILE__, __LINE__); \
68     }                                       \
69   }
70 
71 /*
72  * Comment this off if you don't
73  * want httpSM to use new_empty_MIOBuffer(..) call
74  */
75 
76 #define USE_NEW_EMPTY_MIOBUFFER
77 
78 extern int cache_config_read_while_writer;
79 
80 // We have a debugging list that can use to find stuck
81 //  state machines
82 DList(HttpSM, debug_link) debug_sm_list;
83 ink_mutex debug_sm_list_mutex;
84 
85 static const int sub_header_size = sizeof("Content-type: ") - 1 + 2 + sizeof("Content-range: bytes ") - 1 + 4;
86 static const int boundary_size   = 2 + sizeof("RANGE_SEPARATOR") - 1 + 2;
87 
88 static const char *str_100_continue_response = "HTTP/1.1 100 Continue\r\n\r\n";
89 static const int len_100_continue_response   = strlen(str_100_continue_response);
90 
91 // Handy typedef for short (single line) message generation.
92 using lbw = ts::LocalBufferWriter<256>;
93 
94 namespace
95 {
96 /// Update the milestone state given the milestones and timer.
97 inline void
milestone_update_api_time(TransactionMilestones & milestones,ink_hrtime & api_timer)98 milestone_update_api_time(TransactionMilestones &milestones, ink_hrtime &api_timer)
99 {
100   // Bit of funkiness - we set @a api_timer to be the negative value when we're tracking
101   // non-active API time. In that case we need to make a note of it and flip the value back
102   // to positive.
103   if (api_timer) {
104     ink_hrtime delta;
105     bool active = api_timer >= 0;
106     if (!active) {
107       api_timer = -api_timer;
108     }
109     delta     = Thread::get_hrtime_updated() - api_timer;
110     api_timer = 0;
111     // Zero or negative time is a problem because we want to signal *something* happened
112     // vs. no API activity at all. This can happen due to graininess or real time
113     // clock adjustment.
114     if (delta <= 0) {
115       delta = 1;
116     }
117 
118     if (0 == milestones[TS_MILESTONE_PLUGIN_TOTAL]) {
119       milestones[TS_MILESTONE_PLUGIN_TOTAL] = milestones[TS_MILESTONE_SM_START];
120     }
121     milestones[TS_MILESTONE_PLUGIN_TOTAL] += delta;
122     if (active) {
123       if (0 == milestones[TS_MILESTONE_PLUGIN_ACTIVE]) {
124         milestones[TS_MILESTONE_PLUGIN_ACTIVE] = milestones[TS_MILESTONE_SM_START];
125       }
126       milestones[TS_MILESTONE_PLUGIN_ACTIVE] += delta;
127     }
128   }
129 }
130 
131 // Unique state machine identifier
132 std::atomic<int64_t> next_sm_id(0);
133 
134 /**
135    Outbound PROXY Protocol
136 
137    Write PROXY Protocol to the first block of given MIOBuffer
138    FIXME: make @vc_in const
139  */
140 int64_t
do_outbound_proxy_protocol(MIOBuffer * miob,NetVConnection * vc_out,NetVConnection * vc_in,int conf)141 do_outbound_proxy_protocol(MIOBuffer *miob, NetVConnection *vc_out, NetVConnection *vc_in, int conf)
142 {
143   ink_release_assert(conf >= 0);
144 
145   ProxyProtocol info              = vc_in->get_proxy_protocol_info();
146   ProxyProtocolVersion pp_version = proxy_protocol_version_cast(conf);
147 
148   if (info.version == ProxyProtocolVersion::UNDEFINED) {
149     if (conf == 0) {
150       // nothing to forward
151       return 0;
152     } else {
153       // set info from incoming NetVConnection
154       IpEndpoint local = vc_in->get_local_endpoint();
155       info             = ProxyProtocol{pp_version, local.family(), local, vc_in->get_remote_endpoint()};
156     }
157   }
158 
159   vc_out->set_proxy_protocol_info(info);
160 
161   IOBufferBlock *block = miob->first_write_block();
162   size_t len           = proxy_protocol_build(reinterpret_cast<uint8_t *>(block->buf()), block->write_avail(), info, pp_version);
163 
164   if (len > 0) {
165     miob->fill(len);
166   }
167 
168   return len;
169 }
170 
171 } // namespace
172 
173 ClassAllocator<HttpSM> httpSMAllocator("httpSMAllocator");
174 
HttpVCTable(HttpSM * mysm)175 HttpVCTable::HttpVCTable(HttpSM *mysm)
176 {
177   memset(&vc_table, 0, sizeof(vc_table));
178   sm = mysm;
179 }
180 
181 HttpVCTableEntry *
new_entry()182 HttpVCTable::new_entry()
183 {
184   for (int i = 0; i < vc_table_max_entries; i++) {
185     if (vc_table[i].vc == nullptr) {
186       vc_table[i].sm = sm;
187       return vc_table + i;
188     }
189   }
190 
191   ink_release_assert(0);
192   return nullptr;
193 }
194 
195 HttpVCTableEntry *
find_entry(VConnection * vc)196 HttpVCTable::find_entry(VConnection *vc)
197 {
198   for (int i = 0; i < vc_table_max_entries; i++) {
199     if (vc_table[i].vc == vc) {
200       return vc_table + i;
201     }
202   }
203 
204   return nullptr;
205 }
206 
207 HttpVCTableEntry *
find_entry(VIO * vio)208 HttpVCTable::find_entry(VIO *vio)
209 {
210   for (int i = 0; i < vc_table_max_entries; i++) {
211     if (vc_table[i].read_vio == vio || vc_table[i].write_vio == vio) {
212       ink_assert(vc_table[i].vc != nullptr);
213       return vc_table + i;
214     }
215   }
216 
217   return nullptr;
218 }
219 
220 // bool HttpVCTable::remove_entry(HttpVCEntry* e)
221 //
222 //    Deallocates all buffers from the associated
223 //      entry and re-initializes it's other fields
224 //      for reuse
225 //
226 void
remove_entry(HttpVCTableEntry * e)227 HttpVCTable::remove_entry(HttpVCTableEntry *e)
228 {
229   ink_assert(e->vc == nullptr || e->in_tunnel);
230   e->vc  = nullptr;
231   e->eos = false;
232   if (e->read_buffer) {
233     free_MIOBuffer(e->read_buffer);
234     e->read_buffer = nullptr;
235   }
236   if (e->write_buffer) {
237     free_MIOBuffer(e->write_buffer);
238     e->write_buffer = nullptr;
239   }
240   // Cannot reach in to checkout the netvc
241   // for remaining I/O operations because the netvc
242   // may have been deleted at this point and the pointer
243   // could be stale.
244   e->read_vio   = nullptr;
245   e->write_vio  = nullptr;
246   e->vc_handler = nullptr;
247   e->vc_type    = HTTP_UNKNOWN;
248   e->in_tunnel  = false;
249 }
250 
251 // bool HttpVCTable::cleanup_entry(HttpVCEntry* e)
252 //
253 //    Closes the associate vc for the entry,
254 //     and the call remove_entry
255 //
256 void
cleanup_entry(HttpVCTableEntry * e)257 HttpVCTable::cleanup_entry(HttpVCTableEntry *e)
258 {
259   ink_assert(e->vc);
260   if (e->in_tunnel == false) {
261     // Update stats
262     switch (e->vc_type) {
263     case HTTP_UA_VC:
264       // proxy.process.http.current_client_transactions is decremented in HttpSM::destroy
265       break;
266     default:
267       // This covers:
268       // HTTP_UNKNOWN, HTTP_SERVER_VC, HTTP_TRANSFORM_VC, HTTP_CACHE_READ_VC,
269       // HTTP_CACHE_WRITE_VC, HTTP_RAW_SERVER_VC
270       break;
271     }
272 
273     if (e->vc_type == HTTP_SERVER_VC) {
274       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_cleanup_entry);
275     }
276     e->vc->do_io_close();
277     e->vc = nullptr;
278   }
279   remove_entry(e);
280 }
281 
282 void
cleanup_all()283 HttpVCTable::cleanup_all()
284 {
285   for (int i = 0; i < vc_table_max_entries; i++) {
286     if (vc_table[i].vc != nullptr) {
287       cleanup_entry(vc_table + i);
288     }
289   }
290 }
291 
292 #define SMDebug(tag, ...) SpecificDebug(debug_on, tag, __VA_ARGS__)
293 
294 #define REMEMBER(e, r)                             \
295   {                                                \
296     history.push_back(MakeSourceLocation(), e, r); \
297   }
298 
299 #ifdef STATE_ENTER
300 #undef STATE_ENTER
301 #endif
302 #define STATE_ENTER(state_name, event)                                                                    \
303   {                                                                                                       \
304     /*ink_assert (magic == HTTP_SM_MAGIC_ALIVE); */ REMEMBER(event, reentrancy_count);                    \
305     SMDebug("http", "[%" PRId64 "] [%s, %s]", sm_id, #state_name, HttpDebugNames::get_event_name(event)); \
306   }
307 
308 #define HTTP_SM_SET_DEFAULT_HANDLER(_h)   \
309   {                                       \
310     REMEMBER(NO_EVENT, reentrancy_count); \
311     default_handler = _h;                 \
312   }
313 
314 /*
315  * Helper functions to ensure that the parallel
316  * API set timeouts are set consistently with the records.config settings
317  */
318 ink_hrtime
get_server_inactivity_timeout()319 HttpSM::get_server_inactivity_timeout()
320 {
321   ink_hrtime retval = 0;
322   if (t_state.api_txn_no_activity_timeout_value != -1) {
323     retval = HRTIME_MSECONDS(t_state.api_txn_no_activity_timeout_value);
324   } else {
325     retval = HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_out);
326   }
327   return retval;
328 }
329 
330 ink_hrtime
get_server_active_timeout()331 HttpSM::get_server_active_timeout()
332 {
333   ink_hrtime retval = 0;
334   if (t_state.api_txn_active_timeout_value != -1) {
335     retval = HRTIME_MSECONDS(t_state.api_txn_active_timeout_value);
336   } else {
337     retval = HRTIME_SECONDS(t_state.txn_conf->transaction_active_timeout_out);
338   }
339   return retval;
340 }
341 
342 ink_hrtime
get_server_connect_timeout()343 HttpSM::get_server_connect_timeout()
344 {
345   ink_hrtime retval = 0;
346   if (t_state.api_txn_connect_timeout_value != -1) {
347     retval = HRTIME_MSECONDS(t_state.api_txn_connect_timeout_value);
348   } else {
349     int connect_timeout;
350     if (t_state.method == HTTP_WKSIDX_POST || t_state.method == HTTP_WKSIDX_PUT) {
351       connect_timeout = t_state.txn_conf->post_connect_attempts_timeout;
352     } else if (t_state.current.server == &t_state.parent_info) {
353       connect_timeout = t_state.txn_conf->parent_connect_timeout;
354     } else {
355       connect_timeout = t_state.txn_conf->connect_attempts_timeout;
356     }
357     retval = HRTIME_SECONDS(connect_timeout);
358   }
359   return retval;
360 }
361 
HttpSM()362 HttpSM::HttpSM() : Continuation(nullptr), vc_table(this) {}
363 
364 void
cleanup()365 HttpSM::cleanup()
366 {
367   t_state.destroy();
368   api_hooks.clear();
369   http_parser_clear(&http_parser);
370 
371   HttpConfig::release(t_state.http_config_param);
372   m_remap->release();
373 
374   mutex.clear();
375   tunnel.mutex.clear();
376   cache_sm.mutex.clear();
377   transform_cache_sm.mutex.clear();
378   magic    = HTTP_SM_MAGIC_DEAD;
379   debug_on = false;
380 }
381 
382 void
destroy()383 HttpSM::destroy()
384 {
385   cleanup();
386   THREAD_FREE(this, httpSMAllocator, this_thread());
387 }
388 
389 void
init(bool from_early_data)390 HttpSM::init(bool from_early_data)
391 {
392   milestones[TS_MILESTONE_SM_START] = Thread::get_hrtime();
393 
394   _from_early_data = from_early_data;
395 
396   magic = HTTP_SM_MAGIC_ALIVE;
397 
398   // Unique state machine identifier
399   sm_id                    = next_sm_id++;
400   t_state.state_machine_id = sm_id;
401   t_state.state_machine    = this;
402 
403   t_state.http_config_param = HttpConfig::acquire();
404   // Acquire a lease on the global remap / rewrite table (stupid global name ...)
405   m_remap = rewrite_table->acquire();
406 
407   // Simply point to the global config for the time being, no need to copy this
408   // entire struct if nothing is going to change it.
409   t_state.txn_conf = &t_state.http_config_param->oride;
410 
411   t_state.init();
412   http_parser_init(&http_parser);
413 
414   // Added to skip dns if the document is in cache. DNS will be forced if there is a ip based ACL in
415   // cache control or parent.config or if the doc_in_cache_skip_dns is disabled or if http caching is disabled
416   // TODO: This probably doesn't honor this as a per-transaction overridable config.
417   t_state.force_dns = (ip_rule_in_CacheControlTable() || t_state.parent_params->parent_table->ipMatch ||
418                        !(t_state.txn_conf->doc_in_cache_skip_dns) || !(t_state.txn_conf->cache_http));
419 
420   SET_HANDLER(&HttpSM::main_handler);
421 
422   // Remember where this SM is running so it gets returned correctly
423   this->setThreadAffinity(this_ethread());
424 
425 #ifdef USE_HTTP_DEBUG_LISTS
426   ink_mutex_acquire(&debug_sm_list_mutex);
427   debug_sm_list.push(this);
428   ink_mutex_release(&debug_sm_list_mutex);
429 #endif
430 }
431 
432 void
set_ua_half_close_flag()433 HttpSM::set_ua_half_close_flag()
434 {
435   ua_txn->set_half_close_flag(true);
436 }
437 
438 inline int
do_api_callout()439 HttpSM::do_api_callout()
440 {
441   if (hooks_set) {
442     return do_api_callout_internal();
443   } else {
444     handle_api_return();
445     return 0;
446   }
447 }
448 
449 int
state_add_to_list(int event,void *)450 HttpSM::state_add_to_list(int event, void * /* data ATS_UNUSED */)
451 {
452   // The list if for stat pages and general debugging
453   //   The config variable exists mostly to allow us to
454   //   measure an performance drop during benchmark runs
455   if (t_state.http_config_param->enable_http_info) {
456     STATE_ENTER(&HttpSM::state_add_to_list, event);
457     ink_assert(event == EVENT_NONE || event == EVENT_INTERVAL);
458 
459     int bucket = (static_cast<unsigned int>(sm_id) % HTTP_LIST_BUCKETS);
460 
461     MUTEX_TRY_LOCK(lock, HttpSMList[bucket].mutex, mutex->thread_holding);
462     // the client_vc`s timeout events can be triggered, so we should not
463     // reschedule the http_sm when the lock is not acquired.
464     // FIXME: the sm_list may miss some http_sms when the lock contention
465     if (lock.is_locked()) {
466       HttpSMList[bucket].sm_list.push(this);
467     }
468   }
469 
470   t_state.api_next_action = HttpTransact::SM_ACTION_API_SM_START;
471   if (do_api_callout() < 0) {
472     // Didn't get the hook continuation lock. Clear the read and wait for next event
473     if (ua_entry->read_vio) {
474       // Seems like ua_entry->read_vio->disable(); should work, but that was
475       // not sufficient to stop the state machine from processing IO events until the
476       // TXN_START hooks had completed.  Just set the number of bytes to read to 0
477       ua_entry->read_vio = ua_entry->vc->do_io_read(this, 0, nullptr);
478     }
479     return EVENT_CONT;
480   }
481   return EVENT_DONE;
482 }
483 
484 int
state_remove_from_list(int event,void *)485 HttpSM::state_remove_from_list(int event, void * /* data ATS_UNUSED */)
486 {
487   // The config parameters are guaranteed not change
488   //   across the life of a transaction so it safe to
489   //   check the config here and use it determine
490   //   whether we need to strip ourselves off of the
491   //   state page list
492   if (t_state.http_config_param->enable_http_info) {
493     STATE_ENTER(&HttpSM::state_remove_from_list, event);
494     ink_assert(event == EVENT_NONE || event == EVENT_INTERVAL);
495 
496     int bucket = (static_cast<unsigned int>(sm_id) % HTTP_LIST_BUCKETS);
497 
498     MUTEX_TRY_LOCK(lock, HttpSMList[bucket].mutex, mutex->thread_holding);
499     if (!lock.is_locked()) {
500       HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_remove_from_list);
501       mutex->thread_holding->schedule_in(this, HTTP_LIST_RETRY);
502       return EVENT_DONE;
503     }
504 
505     HttpSMList[bucket].sm_list.remove(this);
506   }
507 
508   // We're now ready to finish off the state machine
509   terminate_sm         = true;
510   kill_this_async_done = true;
511 
512   return EVENT_DONE;
513 }
514 
515 void
start_sub_sm()516 HttpSM::start_sub_sm()
517 {
518   tunnel.init(this, mutex);
519   cache_sm.init(this, mutex);
520   transform_cache_sm.init(this, mutex);
521 }
522 
523 void
attach_client_session(ProxyTransaction * client_vc,IOBufferReader * buffer_reader)524 HttpSM::attach_client_session(ProxyTransaction *client_vc, IOBufferReader *buffer_reader)
525 {
526   milestones[TS_MILESTONE_UA_BEGIN] = Thread::get_hrtime();
527   ink_assert(client_vc != nullptr);
528 
529   NetVConnection *netvc = client_vc->get_netvc();
530   if (!netvc) {
531     return;
532   }
533   ua_txn = client_vc;
534 
535   // It seems to be possible that the ua_txn pointer will go stale before log entries for this HTTP transaction are
536   // generated.  Therefore, collect information that may be needed for logging from the ua_txn object at this point.
537   //
538   _client_transaction_id                  = ua_txn->get_transaction_id();
539   _client_transaction_priority_weight     = ua_txn->get_transaction_priority_weight();
540   _client_transaction_priority_dependence = ua_txn->get_transaction_priority_dependence();
541   {
542     auto p = ua_txn->get_proxy_ssn();
543 
544     if (p) {
545       _client_connection_id = p->connection_id();
546     }
547   }
548 
549   // Collect log & stats information. We've already verified that the netvc is !nullptr above,
550   // and netvc == ua_txn->get_netvc().
551   SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(netvc);
552 
553   is_internal       = netvc->get_is_internal_request();
554   mptcp_state       = netvc->get_mptcp_state();
555   client_tcp_reused = !(ua_txn->is_first_transaction());
556 
557   if (ssl_vc != nullptr) {
558     client_connection_is_ssl = true;
559     client_ssl_reused        = ssl_vc->getSSLSessionCacheHit();
560     const char *protocol     = ssl_vc->getSSLProtocol();
561     client_sec_protocol      = protocol ? protocol : "-";
562     const char *cipher       = ssl_vc->getSSLCipherSuite();
563     client_cipher_suite      = cipher ? cipher : "-";
564     const char *curve        = ssl_vc->getSSLCurve();
565     client_curve             = curve ? curve : "-";
566     client_alpn_id           = ssl_vc->get_negotiated_protocol_id();
567 
568     if (!client_tcp_reused) {
569       // Copy along the TLS handshake timings
570       milestones[TS_MILESTONE_TLS_HANDSHAKE_START] = ssl_vc->sslHandshakeBeginTime;
571       milestones[TS_MILESTONE_TLS_HANDSHAKE_END]   = ssl_vc->sslHandshakeEndTime;
572     }
573   }
574 
575   const char *protocol_str = client_vc->get_protocol_string();
576   client_protocol          = protocol_str ? protocol_str : "-";
577 
578   ink_release_assert(ua_txn->get_half_close_flag() == false);
579   mutex = client_vc->mutex;
580   if (ua_txn->debug()) {
581     debug_on = true;
582   }
583 
584   t_state.setup_per_txn_configs();
585 
586   ink_assert(ua_txn->get_proxy_ssn());
587   ink_assert(ua_txn->get_proxy_ssn()->accept_options);
588 
589   // default the upstream IP style host resolution order from inbound
590   t_state.my_txn_conf().host_res_data.order = ua_txn->get_proxy_ssn()->accept_options->host_res_preference;
591 
592   start_sub_sm();
593 
594   // Allocate a user agent entry in the state machine's
595   //   vc table
596   ua_entry          = vc_table.new_entry();
597   ua_entry->vc      = client_vc;
598   ua_entry->vc_type = HTTP_UA_VC;
599 
600   ats_ip_copy(&t_state.client_info.src_addr, netvc->get_remote_addr());
601   ats_ip_copy(&t_state.client_info.dst_addr, netvc->get_local_addr());
602   t_state.client_info.is_transparent = netvc->get_is_transparent();
603   t_state.client_info.port_attribute = static_cast<HttpProxyPort::TransportType>(netvc->attributes);
604 
605   // Record api hook set state
606   hooks_set = client_vc->has_hooks();
607 
608   // Setup for parsing the header
609   ua_buffer_reader     = buffer_reader;
610   ua_entry->vc_handler = &HttpSM::state_read_client_request_header;
611   t_state.hdr_info.client_request.destroy();
612   t_state.hdr_info.client_request.create(HTTP_TYPE_REQUEST);
613 
614   // Prepare raw reader which will live until we are sure this is HTTP indeed
615   if (is_transparent_passthrough_allowed() || (ssl_vc && ssl_vc->decrypt_tunnel())) {
616     ua_raw_buffer_reader = buffer_reader->clone();
617   }
618 
619   // We first need to run the transaction start hook.  Since
620   //  this hook maybe asynchronous, we need to disable IO on
621   //  client but set the continuation to be the state machine
622   //  so if we get an timeout events the sm handles them
623   //  hold onto enabling read until setup_client_read_request_header
624   ua_entry->read_vio  = client_vc->do_io_read(this, 0, nullptr);
625   ua_entry->write_vio = client_vc->do_io_write(this, 0, nullptr);
626 
627   /////////////////////////
628   // set up timeouts     //
629   /////////////////////////
630   client_vc->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
631   client_vc->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_active_timeout_in));
632 
633   ++reentrancy_count;
634   // Add our state sm to the sm list
635   state_add_to_list(EVENT_NONE, nullptr);
636 
637   // This is another external entry point and it is possible for the state machine to get terminated
638   // while down the call chain from @c state_add_to_list. So we need to use the reentrancy_count to
639   // prevent cleanup there and do it here as we return to the external caller.
640   if (terminate_sm == true && reentrancy_count == 1) {
641     kill_this();
642   } else {
643     --reentrancy_count;
644     ink_assert(reentrancy_count >= 0);
645   }
646 }
647 
648 void
setup_client_read_request_header()649 HttpSM::setup_client_read_request_header()
650 {
651   ink_assert(ua_entry->vc_handler == &HttpSM::state_read_client_request_header);
652 
653   ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf);
654   // The header may already be in the buffer if this
655   //  a request from a keep-alive connection
656   handleEvent(VC_EVENT_READ_READY, ua_entry->read_vio);
657 }
658 
659 void
setup_blind_tunnel_port()660 HttpSM::setup_blind_tunnel_port()
661 {
662   NetVConnection *netvc = ua_txn->get_netvc();
663   ink_release_assert(netvc);
664   int host_len;
665   if (SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(netvc)) {
666     if (!t_state.hdr_info.client_request.url_get()->host_get(&host_len)) {
667       // the URL object has not been created in the start of the transaction. Hence, we need to create the URL here
668       URL u;
669 
670       t_state.hdr_info.client_request.create(HTTP_TYPE_REQUEST);
671       t_state.hdr_info.client_request.method_set(HTTP_METHOD_CONNECT, HTTP_LEN_CONNECT);
672       t_state.hdr_info.client_request.url_create(&u);
673       u.scheme_set(URL_SCHEME_TUNNEL, URL_LEN_TUNNEL);
674       t_state.hdr_info.client_request.url_set(&u);
675 
676       if (ssl_vc->has_tunnel_destination()) {
677         const char *tunnel_host = ssl_vc->get_tunnel_host();
678         t_state.hdr_info.client_request.url_get()->host_set(tunnel_host, strlen(tunnel_host));
679         if (ssl_vc->get_tunnel_port() > 0) {
680           t_state.hdr_info.client_request.url_get()->port_set(ssl_vc->get_tunnel_port());
681         } else {
682           t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
683         }
684       } else {
685         t_state.hdr_info.client_request.url_get()->host_set(ssl_vc->get_server_name(), strlen(ssl_vc->get_server_name()));
686         t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
687       }
688     }
689   } else {
690     char new_host[INET6_ADDRSTRLEN];
691     ats_ip_ntop(netvc->get_local_addr(), new_host, sizeof(new_host));
692 
693     t_state.hdr_info.client_request.url_get()->host_set(new_host, strlen(new_host));
694     t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
695   }
696   call_transact_and_set_next_state(HttpTransact::HandleBlindTunnel);
697 }
698 
699 int
state_read_client_request_header(int event,void * data)700 HttpSM::state_read_client_request_header(int event, void *data)
701 {
702   STATE_ENTER(&HttpSM::state_read_client_request_header, event);
703 
704   ink_assert(ua_entry->read_vio == (VIO *)data);
705   ink_assert(server_entry == nullptr);
706   ink_assert(server_session == nullptr);
707 
708   int bytes_used = 0;
709   ink_assert(ua_entry->eos == false);
710 
711   NetVConnection *netvc = ua_txn->get_netvc();
712   if (!netvc && event != VC_EVENT_EOS) {
713     return 0;
714   }
715 
716   switch (event) {
717   case VC_EVENT_READ_READY:
718   case VC_EVENT_READ_COMPLETE:
719     // More data to parse
720     break;
721 
722   case VC_EVENT_EOS:
723     ua_entry->eos = true;
724     if ((client_request_hdr_bytes > 0) && is_transparent_passthrough_allowed() && (ua_raw_buffer_reader != nullptr)) {
725       break;
726     }
727   // Fall through
728   case VC_EVENT_ERROR:
729   case VC_EVENT_INACTIVITY_TIMEOUT:
730   case VC_EVENT_ACTIVE_TIMEOUT:
731     // The user agent is hosed.  Close it &
732     //   bail on the state machine
733     vc_table.cleanup_entry(ua_entry);
734     ua_entry = nullptr;
735     set_ua_abort(HttpTransact::ABORTED, event);
736     terminate_sm = true;
737     return 0;
738   }
739 
740   // Reset the inactivity timeout if this is the first
741   //   time we've been called.  The timeout had been set to
742   //   the accept timeout by the ProxyTransaction
743   //
744   if ((ua_buffer_reader->read_avail() > 0) && (client_request_hdr_bytes == 0)) {
745     milestones[TS_MILESTONE_UA_FIRST_READ] = Thread::get_hrtime();
746     ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
747   }
748   /////////////////////
749   // tokenize header //
750   /////////////////////
751 
752   ParseResult state = t_state.hdr_info.client_request.parse_req(
753     &http_parser, ua_buffer_reader, &bytes_used, ua_entry->eos, t_state.http_config_param->strict_uri_parsing,
754     t_state.http_config_param->http_request_line_max_size, t_state.http_config_param->http_hdr_field_max_size);
755 
756   client_request_hdr_bytes += bytes_used;
757 
758   // Check to see if we are over the hdr size limit
759   if (client_request_hdr_bytes > t_state.txn_conf->request_hdr_max_size) {
760     SMDebug("http", "client header bytes were over max header size; treating as a bad request");
761     state = PARSE_RESULT_ERROR;
762   }
763 
764   // We need to handle EOS as well as READ_READY because the client
765   // may have sent all of the data already followed by a FIN and that
766   // should be OK.
767   if (ua_raw_buffer_reader != nullptr) {
768     bool do_blind_tunnel = false;
769     // If we had a parse error and we're done reading data
770     // blind tunnel
771     if ((event == VC_EVENT_READ_READY || event == VC_EVENT_EOS) && state == PARSE_RESULT_ERROR) {
772       do_blind_tunnel = true;
773 
774       // If we had a GET request that has data after the
775       // get request, do blind tunnel
776     } else if (state == PARSE_RESULT_DONE && t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_GET &&
777                ua_buffer_reader->read_avail() > 0 && !t_state.hdr_info.client_request.is_keep_alive_set()) {
778       do_blind_tunnel = true;
779     }
780     if (do_blind_tunnel) {
781       SMDebug("http", "[%" PRId64 "] first request on connection failed parsing, switching to passthrough.", sm_id);
782 
783       t_state.transparent_passthrough = true;
784       http_parser_clear(&http_parser);
785 
786       // Turn off read eventing until we get the
787       // blind tunnel infrastructure set up
788       if (netvc) {
789         netvc->do_io_read(nullptr, 0, nullptr);
790       }
791 
792       /* establish blind tunnel */
793       setup_blind_tunnel_port();
794 
795       // Setting half close means we will send the FIN when we've written all of the data.
796       if (event == VC_EVENT_EOS) {
797         this->set_ua_half_close_flag();
798         t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE;
799       }
800       return 0;
801     }
802   }
803 
804   // Check to see if we are done parsing the header
805   if (state != PARSE_RESULT_CONT || ua_entry->eos || (state == PARSE_RESULT_CONT && event == VC_EVENT_READ_COMPLETE)) {
806     if (ua_raw_buffer_reader != nullptr) {
807       ua_raw_buffer_reader->dealloc();
808       ua_raw_buffer_reader = nullptr;
809     }
810     http_parser_clear(&http_parser);
811     ua_entry->vc_handler                         = &HttpSM::state_watch_for_client_abort;
812     milestones[TS_MILESTONE_UA_READ_HEADER_DONE] = Thread::get_hrtime();
813   }
814 
815   switch (state) {
816   case PARSE_RESULT_ERROR:
817     SMDebug("http", "[%" PRId64 "] error parsing client request header", sm_id);
818 
819     // Disable further I/O on the client
820     ua_entry->read_vio->nbytes = ua_entry->read_vio->ndone;
821 
822     (bytes_used > t_state.http_config_param->http_request_line_max_size) ?
823       t_state.http_return_code = HTTP_STATUS_REQUEST_URI_TOO_LONG :
824       t_state.http_return_code = HTTP_STATUS_NONE;
825 
826     if (!is_http1_hdr_version_supported(t_state.hdr_info.client_request.version_get())) {
827       t_state.http_return_code = HTTP_STATUS_HTTPVER_NOT_SUPPORTED;
828     }
829 
830     call_transact_and_set_next_state(HttpTransact::BadRequest);
831     break;
832 
833   case PARSE_RESULT_CONT:
834     if (ua_entry->eos) {
835       SMDebug("http_seq", "[%" PRId64 "] EOS before client request parsing finished", sm_id);
836       set_ua_abort(HttpTransact::ABORTED, event);
837 
838       // Disable further I/O on the client
839       ua_entry->read_vio->nbytes = ua_entry->read_vio->ndone;
840 
841       call_transact_and_set_next_state(HttpTransact::BadRequest);
842       break;
843     } else if (event == VC_EVENT_READ_COMPLETE) {
844       SMDebug("http_parse", "[%" PRId64 "] VC_EVENT_READ_COMPLETE and PARSE CONT state", sm_id);
845       break;
846     } else {
847       if (is_transparent_passthrough_allowed() && ua_raw_buffer_reader != nullptr &&
848           ua_raw_buffer_reader->get_current_block()->write_avail() <= 0) {
849         // Disable passthrough regardless of eventual parsing failure or success -- otherwise
850         // we either have to consume some data or risk blocking the writer.
851         ua_raw_buffer_reader->dealloc();
852         ua_raw_buffer_reader = nullptr;
853       }
854       ua_entry->read_vio->reenable();
855       return VC_EVENT_CONT;
856     }
857   case PARSE_RESULT_DONE:
858     SMDebug("http", "[%" PRId64 "] done parsing client request header", sm_id);
859 
860     if (!t_state.hdr_info.client_request.check_hdr_implements()) {
861       t_state.http_return_code = HTTP_STATUS_NOT_IMPLEMENTED;
862       call_transact_and_set_next_state(HttpTransact::BadRequest);
863       break;
864     }
865 
866     if (_from_early_data) {
867       // Only allow early data for safe methods defined in RFC7231 Section 4.2.1.
868       // https://tools.ietf.org/html/rfc7231#section-4.2.1
869       SMDebug("ssl_early_data", "%d", t_state.hdr_info.client_request.method_get_wksidx());
870       if (!HttpTransactHeaders::is_method_safe(t_state.hdr_info.client_request.method_get_wksidx())) {
871         SMDebug("http", "client request was from early data but is NOT safe");
872         call_transact_and_set_next_state(HttpTransact::TooEarly);
873         return 0;
874       } else if (!SSLConfigParams::server_allow_early_data_params &&
875                  (t_state.hdr_info.client_request.m_http->u.req.m_url_impl->m_len_params > 0 ||
876                   t_state.hdr_info.client_request.m_http->u.req.m_url_impl->m_len_query > 0)) {
877         SMDebug("http", "client request was from early data but HAS parameters");
878         call_transact_and_set_next_state(HttpTransact::TooEarly);
879         return 0;
880       }
881       t_state.hdr_info.client_request.mark_early_data();
882     }
883 
884     ua_txn->set_session_active();
885 
886     if (t_state.hdr_info.client_request.version_get() == HTTP_1_1 &&
887         (t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_POST ||
888          t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_PUT) &&
889         t_state.http_config_param->send_100_continue_response) {
890       int len            = 0;
891       const char *expect = t_state.hdr_info.client_request.value_get(MIME_FIELD_EXPECT, MIME_LEN_EXPECT, &len);
892       // When receive an "Expect: 100-continue" request from client, ATS sends a "100 Continue" response to client
893       // immediately, before receive the real response from original server.
894       if ((len == HTTP_LEN_100_CONTINUE) && (strncasecmp(expect, HTTP_VALUE_100_CONTINUE, HTTP_LEN_100_CONTINUE) == 0)) {
895         int64_t alloc_index = buffer_size_to_index(len_100_continue_response, t_state.http_config_param->max_payload_iobuf_index);
896         if (ua_entry->write_buffer) {
897           free_MIOBuffer(ua_entry->write_buffer);
898           ua_entry->write_buffer = nullptr;
899         }
900         ua_entry->write_buffer    = new_MIOBuffer(alloc_index);
901         IOBufferReader *buf_start = ua_entry->write_buffer->alloc_reader();
902 
903         t_state.hdr_info.client_request.m_100_continue_required = true;
904 
905         SMDebug("http_seq", "send 100 Continue response to client");
906         int64_t nbytes      = ua_entry->write_buffer->write(str_100_continue_response, len_100_continue_response);
907         ua_entry->write_vio = ua_txn->do_io_write(this, nbytes, buf_start);
908       }
909     }
910 
911     // Call to ensure the content-length and transfer_encoding elements in client_request are filled in
912     HttpTransact::set_client_request_state(&t_state, &t_state.hdr_info.client_request);
913 
914     if (t_state.hdr_info.client_request.get_content_length() == 0 &&
915         t_state.client_info.transfer_encoding != HttpTransact::CHUNKED_ENCODING) {
916       // Enable further IO to watch for client aborts
917       ua_entry->read_vio->reenable();
918     } else if (t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_TRACE) {
919       // Trace with request body is not allowed
920       call_transact_and_set_next_state(HttpTransact::BadRequest);
921       return 0;
922     } else {
923       // Disable further I/O on the client since there could
924       //  be body that we are tunneling POST/PUT/CONNECT or
925       //  extension methods and we can't issue another
926       //  another IO later for the body with a different buffer
927       ua_entry->read_vio->nbytes = ua_entry->read_vio->ndone;
928     }
929 
930     call_transact_and_set_next_state(HttpTransact::ModifyRequest);
931 
932     break;
933   default:
934     ink_assert(!"not reached");
935   }
936 
937   return 0;
938 }
939 
940 void
wait_for_full_body()941 HttpSM::wait_for_full_body()
942 {
943   is_waiting_for_full_body = true;
944   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_post);
945   bool chunked = (t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING);
946   int64_t alloc_index;
947   HttpTunnelProducer *p = nullptr;
948 
949   // content length is undefined, use default buffer size
950   if (t_state.hdr_info.request_content_length == HTTP_UNDEFINED_CL) {
951     alloc_index = static_cast<int>(t_state.txn_conf->default_buffer_size_index);
952     if (alloc_index < MIN_CONFIG_BUFFER_SIZE_INDEX || alloc_index > MAX_BUFFER_SIZE_INDEX) {
953       alloc_index = DEFAULT_REQUEST_BUFFER_SIZE_INDEX;
954     }
955   } else {
956     alloc_index = buffer_size_to_index(t_state.hdr_info.request_content_length, t_state.http_config_param->max_payload_iobuf_index);
957   }
958   MIOBuffer *post_buffer    = new_MIOBuffer(alloc_index);
959   IOBufferReader *buf_start = post_buffer->alloc_reader();
960 
961   this->_postbuf.init(post_buffer->clone_reader(buf_start));
962 
963   // Note: Many browsers, Netscape and IE included send two extra
964   //  bytes (CRLF) at the end of the post.  We just ignore those
965   //  bytes since the sending them is not spec
966 
967   // Next order of business if copy the remaining data from the
968   //  header buffer into new buffer
969   int64_t post_bytes        = chunked ? INT64_MAX : t_state.hdr_info.request_content_length;
970   client_request_body_bytes = post_buffer->write(ua_buffer_reader, chunked ? ua_buffer_reader->read_avail() : post_bytes);
971 
972   ua_buffer_reader->consume(client_request_body_bytes);
973   p = tunnel.add_producer(ua_entry->vc, post_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_BUFFER_READ, "ua post buffer");
974   if (chunked) {
975     tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT);
976   }
977   ua_entry->in_tunnel = true;
978   ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
979   tunnel.tunnel_run(p);
980 }
981 
982 int
state_watch_for_client_abort(int event,void * data)983 HttpSM::state_watch_for_client_abort(int event, void *data)
984 {
985   STATE_ENTER(&HttpSM::state_watch_for_client_abort, event);
986 
987   ink_assert(ua_entry->read_vio == (VIO *)data || ua_entry->write_vio == (VIO *)data);
988   ink_assert(ua_entry->vc == ua_txn);
989 
990   switch (event) {
991   /* EOS means that the client has initiated the connection shut down.
992    * Only half close the client connection so ATS can read additional
993    * data that may still be sent from the server and send it to the
994    * client.
995    */
996   case VC_EVENT_EOS: {
997     // We got an early EOS. If the tunnal has cache writer, don't kill it for background fill.
998     NetVConnection *netvc = ua_txn->get_netvc();
999     if (ua_txn->allow_half_open() || tunnel.has_consumer_besides_client()) {
1000       if (netvc) {
1001         netvc->do_io_shutdown(IO_SHUTDOWN_READ);
1002       }
1003       ua_entry->eos = true;
1004     } else {
1005       ua_txn->do_io_close();
1006       ua_buffer_reader = nullptr;
1007       vc_table.cleanup_entry(ua_entry);
1008       ua_entry = nullptr;
1009       tunnel.kill_tunnel();
1010       terminate_sm = true; // Just die already, the requester is gone
1011       set_ua_abort(HttpTransact::ABORTED, event);
1012     }
1013     break;
1014   }
1015   case VC_EVENT_ERROR:
1016   case VC_EVENT_ACTIVE_TIMEOUT:
1017   case VC_EVENT_INACTIVITY_TIMEOUT: {
1018     if (tunnel.is_tunnel_active()) {
1019       // Check to see if the user agent is part of the tunnel.
1020       //  If so forward the event to the tunnel.  Otherwise,
1021       //  kill the tunnel and fallthrough to the case
1022       //  where the tunnel is not active
1023       HttpTunnelConsumer *c = tunnel.get_consumer(ua_txn);
1024       if (c && c->alive) {
1025         SMDebug("http",
1026                 "[%" PRId64 "] [watch_for_client_abort] "
1027                 "forwarding event %s to tunnel",
1028                 sm_id, HttpDebugNames::get_event_name(event));
1029         tunnel.handleEvent(event, c->write_vio);
1030         return 0;
1031       } else {
1032         tunnel.kill_tunnel();
1033       }
1034     }
1035     // Disable further I/O on the client
1036     if (ua_entry->read_vio) {
1037       ua_entry->read_vio->nbytes = ua_entry->read_vio->ndone;
1038     }
1039     milestones[TS_MILESTONE_UA_CLOSE] = Thread::get_hrtime();
1040     set_ua_abort(HttpTransact::ABORTED, event);
1041 
1042     terminate_sm = true;
1043     break;
1044   }
1045   case VC_EVENT_READ_COMPLETE:
1046   // XXX Work around for TS-1233.
1047   case VC_EVENT_READ_READY:
1048     //  Ignore.  Could be a pipelined request.  We'll get to  it
1049     //    when we finish the current transaction
1050     break;
1051   case VC_EVENT_WRITE_READY:
1052     // 100-continue handler
1053     ink_assert(t_state.hdr_info.client_request.m_100_continue_required);
1054     ua_entry->write_vio->reenable();
1055     break;
1056   case VC_EVENT_WRITE_COMPLETE:
1057     // 100-continue handler
1058     ink_assert(t_state.hdr_info.client_request.m_100_continue_required);
1059     if (ua_entry->write_buffer) {
1060       ink_assert(ua_entry->write_vio && !ua_entry->write_vio->ntodo());
1061       free_MIOBuffer(ua_entry->write_buffer);
1062       ua_entry->write_buffer = nullptr;
1063     }
1064     break;
1065   default:
1066     ink_release_assert(0);
1067     break;
1068   }
1069 
1070   return 0;
1071 }
1072 
1073 void
setup_push_read_response_header()1074 HttpSM::setup_push_read_response_header()
1075 {
1076   ink_assert(server_session == nullptr);
1077   ink_assert(server_entry == nullptr);
1078   ink_assert(ua_txn != nullptr);
1079   ink_assert(t_state.method == HTTP_WKSIDX_PUSH);
1080 
1081   // Set the handler to read the pushed response hdr
1082   ua_entry->vc_handler = &HttpSM::state_read_push_response_header;
1083 
1084   // We record both the total payload size as
1085   //  client_request_body_bytes and the bytes for the individual
1086   //  pushed hdr and body components
1087   pushed_response_hdr_bytes = 0;
1088   client_request_body_bytes = 0;
1089 
1090   // Note: we must use destroy() here since clear()
1091   //  does not free the memory from the header
1092   t_state.hdr_info.server_response.destroy();
1093   t_state.hdr_info.server_response.create(HTTP_TYPE_RESPONSE);
1094   http_parser_clear(&http_parser);
1095 
1096   // We already done the READ when we read the client
1097   //  request header
1098   ink_assert(ua_entry->read_vio);
1099 
1100   // If there is anything in the buffer call the parsing routines
1101   //  since if the response is finished, we won't get any
1102   //  additional callbacks
1103   int resp_hdr_state = VC_EVENT_CONT;
1104   if (ua_buffer_reader->read_avail() > 0) {
1105     if (ua_entry->eos) {
1106       resp_hdr_state = state_read_push_response_header(VC_EVENT_EOS, ua_entry->read_vio);
1107     } else {
1108       resp_hdr_state = state_read_push_response_header(VC_EVENT_READ_READY, ua_entry->read_vio);
1109     }
1110   }
1111   // It is possible that the entire PUSHed response header was already
1112   //  in the buffer.  In this case we don't want to fire off any more
1113   //  IO since we are going to switch buffers when we go to tunnel to
1114   //  the cache
1115   if (resp_hdr_state == VC_EVENT_CONT) {
1116     ink_assert(ua_entry->eos == false);
1117     ua_entry->read_vio = ua_txn->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf);
1118   }
1119 }
1120 
1121 int
state_read_push_response_header(int event,void * data)1122 HttpSM::state_read_push_response_header(int event, void *data)
1123 {
1124   STATE_ENTER(&HttpSM::state_read_push_response_header, event);
1125   ink_assert(ua_entry->read_vio == (VIO *)data);
1126   ink_assert(t_state.current.server == nullptr);
1127 
1128   switch (event) {
1129   case VC_EVENT_EOS:
1130     ua_entry->eos = true;
1131     // Fall through
1132 
1133   case VC_EVENT_READ_READY:
1134   case VC_EVENT_READ_COMPLETE:
1135     // More data to parse
1136     break;
1137 
1138   case VC_EVENT_ERROR:
1139   case VC_EVENT_INACTIVITY_TIMEOUT:
1140   case VC_EVENT_ACTIVE_TIMEOUT:
1141     // The user agent is hosed.  Send an error
1142     set_ua_abort(HttpTransact::ABORTED, event);
1143     call_transact_and_set_next_state(HttpTransact::HandleBadPushRespHdr);
1144     return 0;
1145   }
1146 
1147   int state = PARSE_RESULT_CONT;
1148   while (ua_buffer_reader->read_avail() && state == PARSE_RESULT_CONT) {
1149     const char *start = ua_buffer_reader->start();
1150     const char *tmp   = start;
1151     int64_t data_size = ua_buffer_reader->block_read_avail();
1152     ink_assert(data_size >= 0);
1153 
1154     /////////////////////
1155     // tokenize header //
1156     /////////////////////
1157     state = t_state.hdr_info.server_response.parse_resp(&http_parser, &tmp, tmp + data_size,
1158                                                         false); // Only call w/ eof when data exhausted
1159 
1160     int64_t bytes_used = tmp - start;
1161 
1162     ink_release_assert(bytes_used <= data_size);
1163     ua_buffer_reader->consume(bytes_used);
1164     pushed_response_hdr_bytes += bytes_used;
1165     client_request_body_bytes += bytes_used;
1166   }
1167 
1168   // We are out of data.  If we've received an EOS we need to
1169   //  call the parser with (eof == true) so it can determine
1170   //  whether to use the response as is or declare a parse error
1171   if (ua_entry->eos) {
1172     const char *end = ua_buffer_reader->start();
1173     state = t_state.hdr_info.server_response.parse_resp(&http_parser, &end, end, true // We are out of data after server eos
1174     );
1175     ink_release_assert(state == PARSE_RESULT_DONE || state == PARSE_RESULT_ERROR);
1176   }
1177   // Don't allow 0.9 (unparsable headers) since TS doesn't
1178   //   cache 0.9 responses
1179   if (state == PARSE_RESULT_DONE && t_state.hdr_info.server_response.version_get() == HTTP_0_9) {
1180     state = PARSE_RESULT_ERROR;
1181   }
1182 
1183   if (state != PARSE_RESULT_CONT) {
1184     // Disable further IO
1185     ua_entry->read_vio->nbytes = ua_entry->read_vio->ndone;
1186     http_parser_clear(&http_parser);
1187     milestones[TS_MILESTONE_SERVER_READ_HEADER_DONE] = Thread::get_hrtime();
1188   }
1189 
1190   switch (state) {
1191   case PARSE_RESULT_ERROR:
1192     SMDebug("http", "[%" PRId64 "] error parsing push response header", sm_id);
1193     call_transact_and_set_next_state(HttpTransact::HandleBadPushRespHdr);
1194     break;
1195 
1196   case PARSE_RESULT_CONT:
1197     ua_entry->read_vio->reenable();
1198     return VC_EVENT_CONT;
1199 
1200   case PARSE_RESULT_DONE:
1201     SMDebug("http", "[%" PRId64 "] done parsing push response header", sm_id);
1202     call_transact_and_set_next_state(HttpTransact::HandlePushResponseHdr);
1203     break;
1204   default:
1205     ink_assert(!"not reached");
1206   }
1207 
1208   return VC_EVENT_DONE;
1209 }
1210 
1211 //////////////////////////////////////////////////////////////////////////////
1212 //
1213 //  HttpSM::state_raw_http_server_open()
1214 //
1215 //////////////////////////////////////////////////////////////////////////////
1216 int
state_raw_http_server_open(int event,void * data)1217 HttpSM::state_raw_http_server_open(int event, void *data)
1218 {
1219   STATE_ENTER(&HttpSM::state_raw_http_server_open, event);
1220   ink_assert(server_entry == nullptr);
1221   milestones[TS_MILESTONE_SERVER_CONNECT_END] = Thread::get_hrtime();
1222   NetVConnection *netvc                       = nullptr;
1223 
1224   pending_action = nullptr;
1225   switch (event) {
1226   case EVENT_INTERVAL:
1227     // If we get EVENT_INTERNAL it means that we moved the transaction
1228     // to a different thread in do_http_server_open.  Since we didn't
1229     // do any of the actual work in do_http_server_open, we have to
1230     // go back and do it now.
1231     do_http_server_open(true);
1232     return 0;
1233 
1234   case NET_EVENT_OPEN:
1235 
1236     // Record the VC in our table
1237     server_entry     = vc_table.new_entry();
1238     server_entry->vc = netvc = static_cast<NetVConnection *>(data);
1239     server_entry->vc_type    = HTTP_RAW_SERVER_VC;
1240     t_state.current.state    = HttpTransact::CONNECTION_ALIVE;
1241     ats_ip_copy(&t_state.server_info.src_addr, netvc->get_local_addr());
1242 
1243     netvc->set_inactivity_timeout(get_server_inactivity_timeout());
1244     netvc->set_active_timeout(get_server_active_timeout());
1245     t_state.current.server->clear_connect_fail();
1246     break;
1247 
1248   case VC_EVENT_ERROR:
1249   case NET_EVENT_OPEN_FAILED:
1250     t_state.set_connect_fail(server_session->get_netvc()->lerrno);
1251     t_state.current.state = HttpTransact::OPEN_RAW_ERROR;
1252     // use this value just to get around other values
1253     t_state.hdr_info.response_error = HttpTransact::STATUS_CODE_SERVER_ERROR;
1254     break;
1255 
1256   default:
1257     ink_release_assert(0);
1258     break;
1259   }
1260 
1261   call_transact_and_set_next_state(HttpTransact::OriginServerRawOpen);
1262   return 0;
1263 }
1264 
1265 // int HttpSM::state_request_wait_for_transform_read(int event, void* data)
1266 //
1267 //   We've done a successful transform open and issued a do_io_write
1268 //    to the transform.  We are now ready for the transform  to tell
1269 //    us it is now ready to be read from and it done modifying the
1270 //    server request header
1271 //
1272 int
state_request_wait_for_transform_read(int event,void * data)1273 HttpSM::state_request_wait_for_transform_read(int event, void *data)
1274 {
1275   STATE_ENTER(&HttpSM::state_request_wait_for_transform_read, event);
1276   int64_t size;
1277 
1278   switch (event) {
1279   case TRANSFORM_READ_READY:
1280     size = *(static_cast<int64_t *>(data));
1281     if (size != INT64_MAX && size >= 0) {
1282       // We got a content length so update our internal
1283       //   data as well as fix up the request header
1284       t_state.hdr_info.transform_request_cl = size;
1285       t_state.hdr_info.server_request.value_set_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH, size);
1286       setup_server_send_request_api();
1287       break;
1288     } else {
1289       // No content length from the post.  This is a no go
1290       //  since http spec requires content length when
1291       //  sending a request message body.  Change the event
1292       //  to an error and fall through
1293       event = VC_EVENT_ERROR;
1294       Log::error("Request transformation failed to set content length");
1295     }
1296   // FALLTHROUGH
1297   default:
1298     state_common_wait_for_transform_read(&post_transform_info, &HttpSM::tunnel_handler_post, event, data);
1299     break;
1300   }
1301 
1302   return 0;
1303 }
1304 
1305 // int HttpSM::state_response_wait_for_transform_read(int event, void* data)
1306 //
1307 //   We've done a successful transform open and issued a do_io_write
1308 //    to the transform.  We are now ready for the transform  to tell
1309 //    us it is now ready to be read from and it done modifying the
1310 //    user agent response header
1311 //
1312 int
state_response_wait_for_transform_read(int event,void * data)1313 HttpSM::state_response_wait_for_transform_read(int event, void *data)
1314 {
1315   STATE_ENTER(&HttpSM::state_response_wait_for_transform_read, event);
1316   int64_t size = *(static_cast<int64_t *>(data));
1317 
1318   switch (event) {
1319   case TRANSFORM_READ_READY:
1320     if (size != INT64_MAX && size >= 0) {
1321       // We got a content length so update our internal state
1322       t_state.hdr_info.transform_response_cl = size;
1323       t_state.hdr_info.transform_response.value_set_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH, size);
1324     } else {
1325       t_state.hdr_info.transform_response_cl = HTTP_UNDEFINED_CL;
1326     }
1327     call_transact_and_set_next_state(HttpTransact::handle_transform_ready);
1328     break;
1329   default:
1330     state_common_wait_for_transform_read(&transform_info, &HttpSM::tunnel_handler, event, data);
1331     break;
1332   }
1333 
1334   return 0;
1335 }
1336 
1337 // int HttpSM::state_common_wait_for_transform_read(...)
1338 //
1339 //   This function handles the overlapping cases between request and response
1340 //     transforms which prevents code duplication
1341 //
1342 int
state_common_wait_for_transform_read(HttpTransformInfo * t_info,HttpSMHandler tunnel_handler,int event,void * data)1343 HttpSM::state_common_wait_for_transform_read(HttpTransformInfo *t_info, HttpSMHandler tunnel_handler, int event, void *data)
1344 {
1345   STATE_ENTER(&HttpSM::state_common_wait_for_transform_read, event);
1346   HttpTunnelConsumer *c = nullptr;
1347 
1348   switch (event) {
1349   case HTTP_TUNNEL_EVENT_DONE:
1350     // There are three reasons why the the tunnel could signal completed
1351     //   1) there was error from the transform write
1352     //   2) there was an error from the data source
1353     //   3) the transform write completed before it sent
1354     //      TRANSFORM_READ_READY which is legal and in which
1355     //      case we should just wait for the transform read ready
1356     c = tunnel.get_consumer(t_info->vc);
1357     ink_assert(c != nullptr);
1358     ink_assert(c->vc == t_info->entry->vc);
1359 
1360     if (c->handler_state == HTTP_SM_TRANSFORM_FAIL) {
1361       // Case 1 we failed to complete the write to the
1362       //  transform fall through to vc event error case
1363       ink_assert(c->write_success == false);
1364     } else if (c->producer->read_success == false) {
1365       // Case 2 - error from data source
1366       if (c->producer->vc_type == HT_HTTP_CLIENT) {
1367         // Our source is the client.  POST can't
1368         //   be truncated so forward to the tunnel
1369         //   handler to clean this mess up
1370         ink_assert(t_info == &post_transform_info);
1371         return (this->*tunnel_handler)(event, data);
1372       } else {
1373         // On the response side, we just forward as much
1374         //   as we can of truncated documents so
1375         //   just don't cache the result
1376         ink_assert(t_info == &transform_info);
1377         t_state.api_info.cache_transformed = false;
1378         return 0;
1379       }
1380     } else {
1381       // Case 3 - wait for transform read ready
1382       return 0;
1383     }
1384   // FALLTHROUGH
1385   case VC_EVENT_ERROR:
1386     // Transform VC sends NULL on error conditions
1387     if (!c) {
1388       c = tunnel.get_consumer(t_info->vc);
1389       ink_assert(c != nullptr);
1390     }
1391     vc_table.cleanup_entry(t_info->entry);
1392     t_info->entry = nullptr;
1393     // In Case 1: error due to transform write,
1394     // we need to keep the original t_info->vc for transform_cleanup()
1395     // to skip do_io_close(); otherwise, set it to NULL.
1396     if (c->handler_state != HTTP_SM_TRANSFORM_FAIL) {
1397       t_info->vc = nullptr;
1398     }
1399     if (c->producer->vc_type == HT_HTTP_CLIENT) {
1400       /* Producer was the user agent and there was a failure transforming the POST.
1401          Handling this is challenging and this isn't the best way but it at least
1402          avoids a crash due to trying to send a response to a NULL'd out user agent.
1403          The problem with not closing the user agent is handling draining of the
1404          rest of the POST - the user agent may well not check for a response until that's
1405          done in which case we can get a deadlock where the user agent never reads the
1406          error response because the POST wasn't drained and the buffers filled up.
1407          Draining has a potential bad impact on any pipelining which must be considered.
1408          If we're not going to drain properly the next best choice is to shut down the
1409          entire state machine since (1) there's no point in finishing the POST to the
1410          origin and (2) there's no user agent connection to which to send the error response.
1411       */
1412       terminate_sm = true;
1413     } else {
1414       tunnel.kill_tunnel();
1415       call_transact_and_set_next_state(HttpTransact::HandleApiErrorJump);
1416     }
1417     break;
1418   default:
1419     ink_release_assert(0);
1420   }
1421 
1422   return 0;
1423 }
1424 
1425 // int HttpSM::state_api_callback(int event, void *data)
1426 
1427 //   InkAPI.cc calls us directly here to avoid problems
1428 //    with setting and changing the default_handler
1429 //    function.  As such, this is an entry point
1430 //    and needs to handle the reentrancy counter and
1431 //    deallocation the state machine if necessary
1432 //
1433 int
state_api_callback(int event,void * data)1434 HttpSM::state_api_callback(int event, void *data)
1435 {
1436   ink_release_assert(magic == HTTP_SM_MAGIC_ALIVE);
1437 
1438   ink_assert(reentrancy_count >= 0);
1439   reentrancy_count++;
1440 
1441   milestone_update_api_time(milestones, api_timer);
1442 
1443   STATE_ENTER(&HttpSM::state_api_callback, event);
1444 
1445   state_api_callout(event, data);
1446 
1447   // The sub-handler signals when it is time for the state
1448   //  machine to exit.  We can only exit if we are not reentrantly
1449   //  called otherwise when the our call unwinds, we will be
1450   //  running on a dead state machine
1451   //
1452   // Because of the need for an api shutdown hook, kill_this()
1453   //  is also reentrant.  As such, we don't want to decrement
1454   //  the reentrancy count until after we run kill_this()
1455   //
1456   if (terminate_sm == true && reentrancy_count == 1) {
1457     kill_this();
1458   } else {
1459     reentrancy_count--;
1460     ink_assert(reentrancy_count >= 0);
1461   }
1462 
1463   return VC_EVENT_CONT;
1464 }
1465 
1466 int
state_api_callout(int event,void * data)1467 HttpSM::state_api_callout(int event, void *data)
1468 {
1469   // enum and variable for figuring out what the next action is after
1470   //   after we've finished the api state
1471   enum AfterApiReturn_t {
1472     API_RETURN_UNKNOWN = 0,
1473     API_RETURN_CONTINUE,
1474     API_RETURN_DEFERED_CLOSE,
1475     API_RETURN_DEFERED_SERVER_ERROR,
1476     API_RETURN_ERROR_JUMP,
1477     API_RETURN_SHUTDOWN,
1478     API_RETURN_INVALIDATE_ERROR
1479   };
1480   AfterApiReturn_t api_next = API_RETURN_UNKNOWN;
1481 
1482   if (event != EVENT_NONE) {
1483     STATE_ENTER(&HttpSM::state_api_callout, event);
1484   }
1485 
1486   if (api_timer < 0) {
1487     // This happens when either the plugin lock was missed and the hook rescheduled or
1488     // the transaction got an event without the plugin calling TsHttpTxnReenable().
1489     // The call chain does not recurse here if @a api_timer < 0 which means this call
1490     // is the first from an event dispatch in this case.
1491     milestone_update_api_time(milestones, api_timer);
1492   }
1493 
1494   switch (event) {
1495   case HTTP_TUNNEL_EVENT_DONE:
1496   // This is a reschedule via the tunnel.  Just fall through
1497   //
1498   case EVENT_INTERVAL:
1499     pending_action = nullptr;
1500   // FALLTHROUGH
1501   case EVENT_NONE:
1502     if (cur_hook_id == TS_HTTP_TXN_START_HOOK && t_state.client_info.port_attribute == HttpProxyPort::TRANSPORT_BLIND_TUNNEL) {
1503       /* Creating the request object early to set the host header and port for blind tunneling here for the
1504 plugins required to work with sni_routing.
1505 */
1506       // Plugins triggered on txn_start_hook will get the host and port at that point
1507       // We've received a request on a port which we blind forward
1508       URL u;
1509 
1510       t_state.hdr_info.client_request.create(HTTP_TYPE_REQUEST);
1511       t_state.hdr_info.client_request.method_set(HTTP_METHOD_CONNECT, HTTP_LEN_CONNECT);
1512       t_state.hdr_info.client_request.url_create(&u);
1513       u.scheme_set(URL_SCHEME_TUNNEL, URL_LEN_TUNNEL);
1514       t_state.hdr_info.client_request.url_set(&u);
1515 
1516       NetVConnection *netvc     = ua_txn->get_netvc();
1517       SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(netvc);
1518 
1519       if (ssl_vc && ssl_vc->has_tunnel_destination()) {
1520         const char *tunnel_host = ssl_vc->get_tunnel_host();
1521         t_state.hdr_info.client_request.url_get()->host_set(tunnel_host, strlen(tunnel_host));
1522         ushort tunnel_port = ssl_vc->get_tunnel_port();
1523         if (tunnel_port > 0) {
1524           t_state.hdr_info.client_request.url_get()->port_set(tunnel_port);
1525         } else {
1526           t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
1527         }
1528       } else if (ssl_vc) {
1529         t_state.hdr_info.client_request.url_get()->host_set(ssl_vc->get_server_name(), strlen(ssl_vc->get_server_name()));
1530         t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
1531       }
1532     }
1533   // FALLTHROUGH
1534   case HTTP_API_CONTINUE:
1535     if (nullptr == cur_hook) {
1536       cur_hook = hook_state.getNext();
1537     }
1538     if (cur_hook) {
1539       if (callout_state == HTTP_API_NO_CALLOUT) {
1540         callout_state = HTTP_API_IN_CALLOUT;
1541       }
1542 
1543       WEAK_MUTEX_TRY_LOCK(lock, cur_hook->m_cont->mutex, mutex->thread_holding);
1544 
1545       // Have a mutex but didn't get the lock, reschedule
1546       if (!lock.is_locked()) {
1547         api_timer = -Thread::get_hrtime_updated();
1548         HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_api_callout);
1549         ink_release_assert(pending_action.is_empty());
1550         pending_action = mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(10));
1551         return -1;
1552       }
1553 
1554       SMDebug("http", "[%" PRId64 "] calling plugin on hook %s at hook %p", sm_id, HttpDebugNames::get_api_hook_name(cur_hook_id),
1555               cur_hook);
1556 
1557       APIHook const *hook = cur_hook;
1558       // Need to delay the next hook update until after this hook is called to handle dynamic
1559       // callback manipulation. cur_hook isn't needed to track state (in hook_state).
1560       cur_hook = nullptr;
1561 
1562       if (!api_timer) {
1563         api_timer = Thread::get_hrtime();
1564       }
1565 
1566       hook->invoke(TS_EVENT_HTTP_READ_REQUEST_HDR + cur_hook_id, this);
1567       if (api_timer > 0) { // true if the hook did not call TxnReenable()
1568         milestone_update_api_time(milestones, api_timer);
1569         api_timer = -Thread::get_hrtime(); // set in order to track non-active callout duration
1570         // which means that if we get back from the invoke with api_timer < 0 we're already
1571         // tracking a non-complete callout from a chain so just let it ride. It will get cleaned
1572         // up in state_api_callback when the plugin re-enables this transaction.
1573       }
1574       return 0;
1575     }
1576     // Map the callout state into api_next
1577     switch (callout_state) {
1578     case HTTP_API_NO_CALLOUT:
1579     case HTTP_API_IN_CALLOUT:
1580       if (t_state.api_modifiable_cached_resp && t_state.api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_PREPARE) {
1581         t_state.api_update_cached_object = HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE;
1582       }
1583       api_next = API_RETURN_CONTINUE;
1584       break;
1585     case HTTP_API_DEFERED_CLOSE:
1586       api_next = API_RETURN_DEFERED_CLOSE;
1587       break;
1588     case HTTP_API_DEFERED_SERVER_ERROR:
1589       api_next = API_RETURN_DEFERED_SERVER_ERROR;
1590       break;
1591     case HTTP_API_REWIND_STATE_MACHINE:
1592       SMDebug("http", "REWIND");
1593       callout_state = HTTP_API_NO_CALLOUT;
1594       set_next_state();
1595       return 0;
1596     default:
1597       ink_release_assert(0);
1598     }
1599     break;
1600 
1601   case HTTP_API_ERROR:
1602     if (callout_state == HTTP_API_DEFERED_CLOSE) {
1603       api_next = API_RETURN_DEFERED_CLOSE;
1604     } else if (cur_hook_id == TS_HTTP_TXN_CLOSE_HOOK) {
1605       // If we are closing the state machine, we can't
1606       //   jump to an error state so just continue
1607       api_next = API_RETURN_CONTINUE;
1608     } else if (t_state.api_http_sm_shutdown) {
1609       t_state.api_http_sm_shutdown   = false;
1610       t_state.cache_info.object_read = nullptr;
1611       cache_sm.close_read();
1612       transform_cache_sm.close_read();
1613       release_server_session();
1614       terminate_sm                 = true;
1615       api_next                     = API_RETURN_SHUTDOWN;
1616       t_state.squid_codes.log_code = SQUID_LOG_TCP_DENIED;
1617     } else if (t_state.api_modifiable_cached_resp &&
1618                t_state.api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_PREPARE) {
1619       t_state.api_update_cached_object = HttpTransact::UPDATE_CACHED_OBJECT_ERROR;
1620       api_next                         = API_RETURN_INVALIDATE_ERROR;
1621     } else {
1622       api_next = API_RETURN_ERROR_JUMP;
1623     }
1624     break;
1625 
1626   default:
1627     ink_assert(false);
1628     terminate_sm = true;
1629     return 0;
1630   }
1631 
1632   // Now that we're completed with the api state and figured out what
1633   //   to do next, do it
1634   callout_state = HTTP_API_NO_CALLOUT;
1635   api_timer     = 0;
1636   switch (api_next) {
1637   case API_RETURN_CONTINUE:
1638     handle_api_return();
1639     break;
1640   case API_RETURN_DEFERED_CLOSE:
1641     ink_assert(t_state.api_next_action == HttpTransact::SM_ACTION_API_SM_SHUTDOWN);
1642     do_api_callout();
1643     break;
1644   case API_RETURN_DEFERED_SERVER_ERROR:
1645     ink_assert(t_state.api_next_action == HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR);
1646     ink_assert(t_state.current.state != HttpTransact::CONNECTION_ALIVE);
1647     call_transact_and_set_next_state(HttpTransact::HandleResponse);
1648     break;
1649   case API_RETURN_ERROR_JUMP:
1650     call_transact_and_set_next_state(HttpTransact::HandleApiErrorJump);
1651     break;
1652   case API_RETURN_SHUTDOWN:
1653     break;
1654   case API_RETURN_INVALIDATE_ERROR:
1655     do_cache_prepare_update();
1656     break;
1657   default:
1658   case API_RETURN_UNKNOWN:
1659     ink_release_assert(0);
1660   }
1661 
1662   return 0;
1663 }
1664 
1665 // void HttpSM::handle_api_return()
1666 //
1667 //   Figures out what to do after calling api callouts
1668 //    have finished.  This messy and I would like
1669 //    to come up with a cleaner way to handle the api
1670 //    return.  The way we are doing things also makes a
1671 //    mess of set_next_state()
1672 //
1673 void
handle_api_return()1674 HttpSM::handle_api_return()
1675 {
1676   switch (t_state.api_next_action) {
1677   case HttpTransact::SM_ACTION_API_SM_START: {
1678     NetVConnection *netvc     = ua_txn->get_netvc();
1679     SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(netvc);
1680     bool forward_dest         = ssl_vc != nullptr && ssl_vc->decrypt_tunnel();
1681     if (t_state.client_info.port_attribute == HttpProxyPort::TRANSPORT_BLIND_TUNNEL || forward_dest) {
1682       setup_blind_tunnel_port();
1683     } else {
1684       setup_client_read_request_header();
1685     }
1686     return;
1687   }
1688   case HttpTransact::SM_ACTION_API_CACHE_LOOKUP_COMPLETE:
1689   case HttpTransact::SM_ACTION_API_READ_CACHE_HDR:
1690     if (t_state.api_cleanup_cache_read && t_state.api_update_cached_object != HttpTransact::UPDATE_CACHED_OBJECT_PREPARE) {
1691       t_state.api_cleanup_cache_read = false;
1692       t_state.cache_info.object_read = nullptr;
1693       t_state.request_sent_time      = UNDEFINED_TIME;
1694       t_state.response_received_time = UNDEFINED_TIME;
1695       cache_sm.close_read();
1696       transform_cache_sm.close_read();
1697     }
1698     // fallthrough
1699 
1700   case HttpTransact::SM_ACTION_API_PRE_REMAP:
1701   case HttpTransact::SM_ACTION_API_POST_REMAP:
1702   case HttpTransact::SM_ACTION_API_READ_REQUEST_HDR:
1703   case HttpTransact::SM_ACTION_REQUEST_BUFFER_READ_COMPLETE:
1704   case HttpTransact::SM_ACTION_API_OS_DNS:
1705   case HttpTransact::SM_ACTION_API_READ_RESPONSE_HDR:
1706     call_transact_and_set_next_state(nullptr);
1707     return;
1708   case HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR:
1709     setup_server_send_request();
1710     return;
1711   case HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR:
1712     // Set back the inactivity timeout
1713     if (ua_txn) {
1714       ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
1715     }
1716 
1717     // We only follow 3xx when redirect_in_process == false. Otherwise the redirection has already been launched (in
1718     // SM_ACTION_SERVER_READ).redirect_in_process is set before this logic if we need more direction.
1719     // This redirection is only used with the build_error_response. Then, the redirection_tries will be increased by
1720     // state_read_server_response_header and never get into this logic again.
1721     if (enable_redirection && !t_state.redirect_info.redirect_in_process && is_redirect_required()) {
1722       do_redirect();
1723     }
1724     // we have further processing to do
1725     //  based on what t_state.next_action is
1726     break;
1727   case HttpTransact::SM_ACTION_API_SM_SHUTDOWN:
1728     state_remove_from_list(EVENT_NONE, nullptr);
1729     return;
1730   default:
1731     ink_release_assert(!"Not reached");
1732     break;
1733   }
1734 
1735   switch (t_state.next_action) {
1736   case HttpTransact::SM_ACTION_TRANSFORM_READ: {
1737     HttpTunnelProducer *p = setup_transfer_from_transform();
1738     perform_transform_cache_write_action();
1739     tunnel.tunnel_run(p);
1740     break;
1741   }
1742   case HttpTransact::SM_ACTION_SERVER_READ: {
1743     if (unlikely(t_state.did_upgrade_succeed)) {
1744       // We've successfully handled the upgrade, let's now setup
1745       // a blind tunnel.
1746       IOBufferReader *initial_data = nullptr;
1747       if (t_state.is_websocket) {
1748         HTTP_INCREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat);
1749         if (server_session) {
1750           initial_data = server_session->get_reader();
1751         }
1752 
1753         if (ua_txn) {
1754           SMDebug("http_websocket",
1755                   "(client session) Setting websocket active timeout=%" PRId64 "s and inactive timeout=%" PRId64 "s",
1756                   t_state.txn_conf->websocket_active_timeout, t_state.txn_conf->websocket_inactive_timeout);
1757           ua_txn->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_active_timeout));
1758           ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_inactive_timeout));
1759         }
1760 
1761         if (server_session) {
1762           SMDebug("http_websocket",
1763                   "(server session) Setting websocket active timeout=%" PRId64 "s and inactive timeout=%" PRId64 "s",
1764                   t_state.txn_conf->websocket_active_timeout, t_state.txn_conf->websocket_inactive_timeout);
1765           server_session->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_active_timeout));
1766           server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->websocket_inactive_timeout));
1767         }
1768       }
1769 
1770       setup_blind_tunnel(true, initial_data);
1771     } else {
1772       HttpTunnelProducer *p = setup_server_transfer();
1773       perform_cache_write_action();
1774       tunnel.tunnel_run(p);
1775     }
1776     break;
1777   }
1778   case HttpTransact::SM_ACTION_SERVE_FROM_CACHE: {
1779     HttpTunnelProducer *p = setup_cache_read_transfer();
1780     tunnel.tunnel_run(p);
1781     break;
1782   }
1783 
1784   case HttpTransact::SM_ACTION_INTERNAL_CACHE_WRITE: {
1785     if (cache_sm.cache_write_vc) {
1786       setup_internal_transfer(&HttpSM::tunnel_handler_cache_fill);
1787     } else {
1788       setup_internal_transfer(&HttpSM::tunnel_handler);
1789     }
1790     break;
1791   }
1792 
1793   case HttpTransact::SM_ACTION_INTERNAL_CACHE_NOOP:
1794   case HttpTransact::SM_ACTION_INTERNAL_CACHE_DELETE:
1795   case HttpTransact::SM_ACTION_INTERNAL_CACHE_UPDATE_HEADERS:
1796   case HttpTransact::SM_ACTION_SEND_ERROR_CACHE_NOOP: {
1797     setup_internal_transfer(&HttpSM::tunnel_handler);
1798     break;
1799   }
1800 
1801   case HttpTransact::SM_ACTION_REDIRECT_READ: {
1802     // Clean up from any communication with previous servers
1803     release_server_session();
1804 
1805     call_transact_and_set_next_state(HttpTransact::HandleRequest);
1806     break;
1807   }
1808   case HttpTransact::SM_ACTION_SSL_TUNNEL: {
1809     setup_blind_tunnel(true);
1810     break;
1811   }
1812   default: {
1813     ink_release_assert(!"Should not get here");
1814   }
1815   }
1816 }
1817 
1818 //////////////////////////////////////////////////////////////////////////////
1819 //
1820 //  HttpSM::state_http_server_open()
1821 //
1822 //////////////////////////////////////////////////////////////////////////////
1823 int
state_http_server_open(int event,void * data)1824 HttpSM::state_http_server_open(int event, void *data)
1825 {
1826   SMDebug("http_track", "entered inside state_http_server_open");
1827   STATE_ENTER(&HttpSM::state_http_server_open, event);
1828   ink_release_assert(event == EVENT_INTERVAL || event == NET_EVENT_OPEN || event == NET_EVENT_OPEN_FAILED ||
1829                      pending_action.is_empty());
1830   if (event != NET_EVENT_OPEN) {
1831     pending_action = nullptr;
1832   }
1833   milestones[TS_MILESTONE_SERVER_CONNECT_END] = Thread::get_hrtime();
1834   NetVConnection *netvc                       = nullptr;
1835 
1836   switch (event) {
1837   case NET_EVENT_OPEN: {
1838     Http1ServerSession *session = (TS_SERVER_SESSION_SHARING_POOL_THREAD == httpSessionManager.get_pool_type()) ?
1839                                     THREAD_ALLOC_INIT(httpServerSessionAllocator, mutex->thread_holding) :
1840                                     httpServerSessionAllocator.alloc();
1841     session->sharing_pool  = static_cast<TSServerSessionSharingPoolType>(t_state.http_config_param->server_session_sharing_pool);
1842     session->sharing_match = static_cast<TSServerSessionSharingMatchMask>(t_state.txn_conf->server_session_sharing_match);
1843 
1844     netvc = static_cast<NetVConnection *>(data);
1845     session->attach_hostname(t_state.current.server->name);
1846     UnixNetVConnection *vc = static_cast<UnixNetVConnection *>(data);
1847     // Since the UnixNetVConnection::action_ or SocksEntry::action_ may be returned from netProcessor.connect_re, and the
1848     // SocksEntry::action_ will be copied into UnixNetVConnection::action_ before call back NET_EVENT_OPEN from SocksEntry::free(),
1849     // so we just compare the Continuation between pending_action and VC's action_.
1850     ink_release_assert(pending_action.is_empty() || pending_action.get_continuation() == vc->get_action()->continuation);
1851     pending_action = nullptr;
1852 
1853     session->new_connection(vc, nullptr, nullptr);
1854 
1855     ATS_PROBE1(new_origin_server_connection, t_state.current.server->name);
1856 
1857     session->set_active();
1858     ats_ip_copy(&t_state.server_info.src_addr, netvc->get_local_addr());
1859 
1860     // If origin_max_connections or origin_min_keep_alive_connections is set then we are metering
1861     // the max and or min number of connections per host. Transfer responsibility for this to the
1862     // session object.
1863     if (t_state.outbound_conn_track_state.is_active()) {
1864       SMDebug("http_ss", "[%" PRId64 "] max number of outbound connections: %d", sm_id, t_state.txn_conf->outbound_conntrack.max);
1865       session->enable_outbound_connection_tracking(t_state.outbound_conn_track_state.drop());
1866     }
1867 
1868     attach_server_session(session);
1869     if (t_state.current.request_to == HttpTransact::PARENT_PROXY) {
1870       session->to_parent_proxy = true;
1871       HTTP_INCREMENT_DYN_STAT(http_current_parent_proxy_connections_stat);
1872       HTTP_INCREMENT_DYN_STAT(http_total_parent_proxy_connections_stat);
1873     } else {
1874       session->to_parent_proxy = false;
1875     }
1876 
1877     if (plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) {
1878       SMDebug("http", "[%" PRId64 "] setting handler for TCP handshake", sm_id);
1879       // Just want to get a write-ready event so we know that the TCP handshake is complete.
1880       server_entry->vc_handler = &HttpSM::state_http_server_open;
1881 
1882       int64_t nbytes = 1;
1883       if (t_state.txn_conf->proxy_protocol_out >= 0) {
1884         nbytes =
1885           do_outbound_proxy_protocol(server_session->read_buffer, vc, ua_txn->get_netvc(), t_state.txn_conf->proxy_protocol_out);
1886       }
1887 
1888       server_entry->write_vio = server_session->do_io_write(this, nbytes, server_session->get_reader());
1889 
1890       // Pre-emptively set a server connect failure that will be cleared once a WRITE_READY is received from origin or
1891       // bytes are received back
1892       t_state.set_connect_fail(EIO);
1893     } else { // in the case of an intercept plugin don't to the connect timeout change
1894       SMDebug("http", "[%" PRId64 "] not setting handler for TCP handshake", sm_id);
1895       handle_http_server_open();
1896     }
1897 
1898     return 0;
1899   }
1900   case VC_EVENT_READ_COMPLETE:
1901   case VC_EVENT_WRITE_READY:
1902   case VC_EVENT_WRITE_COMPLETE:
1903     // Update the time out to the regular connection timeout.
1904     SMDebug("http_ss", "[%" PRId64 "] TCP Handshake complete", sm_id);
1905     server_entry->vc_handler = &HttpSM::state_send_server_request_header;
1906 
1907     // Reset the timeout to the non-connect timeout
1908     server_session->set_inactivity_timeout(get_server_inactivity_timeout());
1909     t_state.current.server->clear_connect_fail();
1910     handle_http_server_open();
1911     return 0;
1912   case EVENT_INTERVAL: // Delayed call from another thread
1913     if (server_session == nullptr) {
1914       do_http_server_open();
1915     }
1916     break;
1917   case VC_EVENT_INACTIVITY_TIMEOUT:
1918   case VC_EVENT_ACTIVE_TIMEOUT:
1919     t_state.set_connect_fail(ETIMEDOUT);
1920   /* fallthrough */
1921   case VC_EVENT_ERROR:
1922   case NET_EVENT_OPEN_FAILED: {
1923     if (server_session) {
1924       NetVConnection *vc = server_session->get_netvc();
1925       if (vc) {
1926         t_state.set_connect_fail(vc->lerrno);
1927         server_connection_provided_cert = vc->provided_cert();
1928       }
1929     }
1930 
1931     t_state.current.state = HttpTransact::CONNECTION_ERROR;
1932     t_state.outbound_conn_track_state.clear();
1933 
1934     /* If we get this error in transparent mode, then we simply can't bind to the 4-tuple to make the connection.  There's no hope
1935        of retries succeeding in the near future. The best option is to just shut down the connection without further comment. The
1936        only known cause for this is outbound transparency combined with use client target address / source port, as noted in
1937        TS-1424. If the keep alives desync the current connection can be attempting to rebind the 4 tuple simultaneously with the
1938        shut down of an existing connection. Dropping the client side will cause it to pick a new source port and recover from this
1939        issue.
1940     */
1941     if (EADDRNOTAVAIL == t_state.current.server->connect_result && t_state.client_info.is_transparent) {
1942       if (is_debug_tag_set("http_tproxy")) {
1943         ip_port_text_buffer ip_c, ip_s;
1944         Debug("http_tproxy", "Force close of client connect (%s->%s) due to EADDRNOTAVAIL [%" PRId64 "]",
1945               ats_ip_nptop(&t_state.client_info.src_addr.sa, ip_c, sizeof ip_c),
1946               ats_ip_nptop(&t_state.server_info.dst_addr.sa, ip_s, sizeof ip_s), sm_id);
1947       }
1948       t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE; // part of the problem, clear it.
1949       terminate_sm                   = true;
1950     } else if (ENET_THROTTLING == t_state.current.server->connect_result) {
1951       HTTP_INCREMENT_DYN_STAT(http_origin_connections_throttled_stat);
1952       send_origin_throttled_response();
1953     } else {
1954       // Go ahead and release the failed server session.  Since it didn't receive a response, the release logic will
1955       // see that it didn't get a valid response and it will close it rather than returning it to the server session pool
1956       release_server_session();
1957       call_transact_and_set_next_state(HttpTransact::HandleResponse);
1958     }
1959     return 0;
1960   }
1961   default:
1962     Error("[HttpSM::state_http_server_open] Unknown event: %d", event);
1963     ink_release_assert(0);
1964     return 0;
1965   }
1966 
1967   return 0;
1968 }
1969 
1970 int
state_read_server_response_header(int event,void * data)1971 HttpSM::state_read_server_response_header(int event, void *data)
1972 {
1973   STATE_ENTER(&HttpSM::state_read_server_response_header, event);
1974   ink_assert(server_entry->read_vio == (VIO *)data);
1975   ink_assert(t_state.current.server->state == HttpTransact::STATE_UNDEFINED);
1976   ink_assert(t_state.current.state == HttpTransact::STATE_UNDEFINED);
1977 
1978   int bytes_used = 0;
1979   VIO *vio       = static_cast<VIO *>(data);
1980 
1981   switch (event) {
1982   case VC_EVENT_EOS:
1983     server_entry->eos = true;
1984 
1985   // Fall through
1986   case VC_EVENT_READ_READY:
1987   case VC_EVENT_READ_COMPLETE:
1988     // More data to parse
1989     break;
1990 
1991   case VC_EVENT_ERROR:
1992   case VC_EVENT_INACTIVITY_TIMEOUT:
1993   case VC_EVENT_ACTIVE_TIMEOUT:
1994     // Error handling function
1995     handle_server_setup_error(event, data);
1996     return 0;
1997   }
1998 
1999   // Reset the inactivity timeout if this is the first
2000   //   time we've been called.  The timeout had been set to
2001   //   the connect timeout when we set up to read the header
2002   //
2003   if (server_response_hdr_bytes == 0) {
2004     milestones[TS_MILESTONE_SERVER_FIRST_READ] = Thread::get_hrtime();
2005 
2006     server_session->set_inactivity_timeout(get_server_inactivity_timeout());
2007 
2008     // For requests that contain a body, we can cancel the ua inactivity timeout.
2009     if (ua_txn && t_state.hdr_info.request_content_length > 0) {
2010       ua_txn->cancel_inactivity_timeout();
2011     }
2012   }
2013   /////////////////////
2014   // tokenize header //
2015   /////////////////////
2016   ParseResult state =
2017     t_state.hdr_info.server_response.parse_resp(&http_parser, server_buffer_reader, &bytes_used, server_entry->eos);
2018 
2019   server_response_hdr_bytes += bytes_used;
2020 
2021   // Don't allow HTTP 0.9 (unparsable headers) on resued connections.
2022   // And don't allow empty headers from closed connections
2023   if ((state == PARSE_RESULT_DONE && t_state.hdr_info.server_response.version_get() == HTTP_0_9 &&
2024        server_session->get_transact_count() > 1) ||
2025       (server_entry->eos && vio->ndone == 0)) {
2026     state = PARSE_RESULT_ERROR;
2027   }
2028   // Check to see if we are over the hdr size limit
2029   if (server_response_hdr_bytes > t_state.txn_conf->response_hdr_max_size) {
2030     state = PARSE_RESULT_ERROR;
2031   }
2032 
2033   if (state != PARSE_RESULT_CONT) {
2034     // Disable further IO
2035     server_entry->read_vio->nbytes = server_entry->read_vio->ndone;
2036     http_parser_clear(&http_parser);
2037     milestones[TS_MILESTONE_SERVER_READ_HEADER_DONE] = Thread::get_hrtime();
2038   }
2039 
2040   switch (state) {
2041   case PARSE_RESULT_ERROR: {
2042     // Many broken servers send really badly formed 302 redirects.
2043     //  Even if the parser doesn't like the redirect forward
2044     //  if it's got a Location header.  We check the type of the
2045     //  response to make sure that the parser was able to parse
2046     //  something  and didn't just throw up it's hands (INKqa05339)
2047     bool allow_error = false;
2048     if (t_state.hdr_info.server_response.type_get() == HTTP_TYPE_RESPONSE &&
2049         t_state.hdr_info.server_response.status_get() == HTTP_STATUS_MOVED_TEMPORARILY) {
2050       if (t_state.hdr_info.server_response.field_find(MIME_FIELD_LOCATION, MIME_LEN_LOCATION)) {
2051         allow_error = true;
2052       }
2053     }
2054 
2055     if (allow_error == false) {
2056       SMDebug("http_seq", "Error parsing server response header");
2057       t_state.current.state = HttpTransact::PARSE_ERROR;
2058 
2059       // If the server closed prematurely on us, use the
2060       //   server setup error routine since it will forward
2061       //   error to a POST tunnel if any
2062       if (event == VC_EVENT_EOS) {
2063         handle_server_setup_error(VC_EVENT_EOS, data);
2064       } else {
2065         call_transact_and_set_next_state(HttpTransact::HandleResponse);
2066       }
2067       break;
2068     }
2069     // FALLTHROUGH (since we are allowing the parse error)
2070   }
2071     // fallthrough
2072 
2073   case PARSE_RESULT_DONE:
2074 
2075     if (!t_state.hdr_info.server_response.check_hdr_implements()) {
2076       t_state.http_return_code = HTTP_STATUS_BAD_GATEWAY;
2077       call_transact_and_set_next_state(HttpTransact::BadRequest);
2078       break;
2079     }
2080 
2081     SMDebug("http_seq", "Done parsing server response header");
2082 
2083     // Now that we know that we have all of the origin server
2084     // response headers, we can reset the client inactivity
2085     // timeout.
2086     // we now reset the client inactivity timeout only
2087     // when we are ready to send the response headers. In the
2088     // case of transform plugin, this is after the transform
2089     // outputs the 1st byte, which can take a long time if the
2090     // plugin buffers the whole response.
2091     ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
2092 
2093     t_state.current.state         = HttpTransact::CONNECTION_ALIVE;
2094     t_state.transact_return_point = HttpTransact::HandleResponse;
2095     t_state.api_next_action       = HttpTransact::SM_ACTION_API_READ_RESPONSE_HDR;
2096 
2097     // if exceeded limit deallocate postdata buffers and disable redirection
2098     if (!(enable_redirection && (redirection_tries < t_state.txn_conf->number_of_redirections))) {
2099       this->disable_redirect();
2100     }
2101 
2102     do_api_callout();
2103     break;
2104   case PARSE_RESULT_CONT:
2105     ink_assert(server_entry->eos == false);
2106     server_entry->read_vio->reenable();
2107     return VC_EVENT_CONT;
2108 
2109   default:
2110     ink_assert(!"not reached");
2111   }
2112 
2113   return 0;
2114 }
2115 
2116 int
state_send_server_request_header(int event,void * data)2117 HttpSM::state_send_server_request_header(int event, void *data)
2118 {
2119   STATE_ENTER(&HttpSM::state_send_server_request_header, event);
2120   ink_assert(server_entry != nullptr);
2121   ink_assert(server_entry->write_vio == (VIO *)data || server_entry->read_vio == (VIO *)data);
2122 
2123   int method;
2124 
2125   switch (event) {
2126   case VC_EVENT_WRITE_READY:
2127     server_entry->write_vio->reenable();
2128     break;
2129 
2130   case VC_EVENT_WRITE_COMPLETE:
2131     // We are done sending the request header, deallocate
2132     //  our buffer and then decide what to do next
2133     free_MIOBuffer(server_entry->write_buffer);
2134     server_entry->write_buffer = nullptr;
2135     method                     = t_state.hdr_info.server_request.method_get_wksidx();
2136     if (!t_state.api_server_request_body_set && method != HTTP_WKSIDX_TRACE &&
2137         ua_txn->has_request_body(t_state.hdr_info.request_content_length,
2138                                  t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING)) {
2139       if (post_transform_info.vc) {
2140         setup_transform_to_server_transfer();
2141       } else {
2142         do_setup_post_tunnel(HTTP_SERVER_VC);
2143       }
2144     } else {
2145       // It's time to start reading the response
2146       setup_server_read_response_header();
2147     }
2148 
2149     break;
2150 
2151   case VC_EVENT_READ_READY:
2152     // We already did the read for the response header and
2153     //  we got some data.  Wait for the request header
2154     //  send before dealing with it.  However, we need to
2155     //  disable further IO here since the whole response
2156     //  may be in the buffer and we can not switch buffers
2157     //  on the io core later
2158     ink_assert(server_entry->read_vio == (VIO *)data);
2159     // setting nbytes to ndone would disable reads and remove it from the read queue.
2160     // We can't do this in the epoll paradigm because we may be missing epoll errors that would
2161     // prevent us from leaving this state.
2162     // setup_server_read_response_header will trigger READ_READY to itself if there is data in the buffer.
2163 
2164     // server_entry->read_vio->nbytes = server_entry->read_vio->ndone;
2165 
2166     break;
2167 
2168   case VC_EVENT_EOS:
2169     // EOS of stream comes from the read side.  Treat it as
2170     //  as error if there is nothing in the read buffer.  If
2171     //  there is something the server may have blasted back
2172     //  the response before receiving the request.  Happens
2173     //  often with redirects
2174     //
2175     //  If we are in the middle of an api callout, it
2176     //    means we haven't actually sent the request yet
2177     //    so the stuff in the buffer is garbage and we
2178     //    want to ignore it
2179     //
2180     server_entry->eos = true;
2181 
2182     // I'm not sure about the above comment, but if EOS is received on read and we are
2183     // still in this state, we must have not gotten WRITE_COMPLETE.  With epoll we might not receive EOS
2184     // from both read and write sides of a connection so it should be handled correctly (close tunnels,
2185     // deallocate, etc) here with handle_server_setup_error().  Otherwise we might hang due to not shutting
2186     // down and never receiving another event again.
2187     /*if (server_buffer_reader->read_avail() > 0 && callout_state == HTTP_API_NO_CALLOUT) {
2188        break;
2189        } */
2190 
2191     // Nothing in the buffer
2192     // proceed to error
2193     // fallthrough
2194 
2195   case VC_EVENT_ERROR:
2196   case VC_EVENT_ACTIVE_TIMEOUT:
2197   case VC_EVENT_INACTIVITY_TIMEOUT:
2198     handle_server_setup_error(event, data);
2199     break;
2200 
2201   case VC_EVENT_READ_COMPLETE:
2202     // new event expected due to TS-3189
2203     SMDebug("http_ss", "read complete due to 0 byte do_io_read");
2204     break;
2205 
2206   default:
2207     ink_release_assert(0);
2208     break;
2209   }
2210 
2211   return 0;
2212 }
2213 
2214 void
process_srv_info(HostDBInfo * r)2215 HttpSM::process_srv_info(HostDBInfo *r)
2216 {
2217   SMDebug("dns_srv", "beginning process_srv_info");
2218   t_state.hostdb_entry = Ptr<HostDBInfo>(r);
2219 
2220   /* we didn't get any SRV records, continue w normal lookup */
2221   if (!r || !r->is_srv || !r->round_robin) {
2222     t_state.dns_info.srv_hostname[0]    = '\0';
2223     t_state.dns_info.srv_lookup_success = false;
2224     t_state.my_txn_conf().srv_enabled   = false;
2225     SMDebug("dns_srv", "No SRV records were available, continuing to lookup %s", t_state.dns_info.lookup_name);
2226   } else {
2227     HostDBRoundRobin *rr = r->rr();
2228     HostDBInfo *srv      = nullptr;
2229     if (rr) {
2230       srv = rr->select_best_srv(t_state.dns_info.srv_hostname, &mutex->thread_holding->generator, ink_local_time(),
2231                                 static_cast<int>(t_state.txn_conf->down_server_timeout));
2232     }
2233     if (!srv) {
2234       t_state.dns_info.srv_lookup_success = false;
2235       t_state.dns_info.srv_hostname[0]    = '\0';
2236       t_state.my_txn_conf().srv_enabled   = false;
2237       SMDebug("dns_srv", "SRV records empty for %s", t_state.dns_info.lookup_name);
2238     } else {
2239       t_state.dns_info.srv_lookup_success = true;
2240       t_state.dns_info.srv_port           = srv->data.srv.srv_port;
2241       t_state.dns_info.srv_app            = srv->app;
2242       // t_state.dns_info.single_srv = (rr->good == 1);
2243       ink_assert(srv->data.srv.key == makeHostHash(t_state.dns_info.srv_hostname));
2244       SMDebug("dns_srv", "select SRV records %s", t_state.dns_info.srv_hostname);
2245     }
2246   }
2247   return;
2248 }
2249 
2250 void
process_hostdb_info(HostDBInfo * r)2251 HttpSM::process_hostdb_info(HostDBInfo *r)
2252 {
2253   // Increment the refcount to our item, since we are pointing at it
2254   t_state.hostdb_entry = Ptr<HostDBInfo>(r);
2255 
2256   sockaddr const *client_addr = nullptr;
2257   bool use_client_addr        = t_state.http_config_param->use_client_target_addr == 1 && t_state.client_info.is_transparent &&
2258                          t_state.dns_info.os_addr_style == HttpTransact::DNSLookupInfo::OS_Addr::OS_ADDR_TRY_DEFAULT;
2259   if (use_client_addr) {
2260     NetVConnection *vc = ua_txn ? ua_txn->get_netvc() : nullptr;
2261     if (vc) {
2262       client_addr = vc->get_local_addr();
2263       // Regardless of whether the client address matches the DNS record or not,
2264       // we want to use that address.  Therefore, we copy over the client address
2265       // info and skip the assignment from the DNS cache
2266       ats_ip_copy(t_state.host_db_info.ip(), client_addr);
2267       t_state.dns_info.os_addr_style  = HttpTransact::DNSLookupInfo::OS_Addr::OS_ADDR_TRY_CLIENT;
2268       t_state.dns_info.lookup_success = true;
2269       // Leave ret unassigned, so we don't overwrite the host_db_info
2270     } else {
2271       use_client_addr = false;
2272     }
2273   }
2274 
2275   if (r && !r->is_failed()) {
2276     ink_time_t now                    = ink_local_time();
2277     HostDBInfo *ret                   = nullptr;
2278     t_state.dns_info.lookup_success   = true;
2279     t_state.dns_info.lookup_validated = true;
2280 
2281     HostDBRoundRobin *rr = r->round_robin ? r->rr() : nullptr;
2282     if (rr) {
2283       // if use_client_target_addr is set, make sure the client addr is in the results pool
2284       if (use_client_addr && rr->find_ip(client_addr) == nullptr) {
2285         SMDebug("http", "use_client_target_addr == 1. Client specified address is not in the pool, not validated.");
2286         t_state.dns_info.lookup_validated = false;
2287       } else {
2288         // Since the time elapsed between current time and client_request_time
2289         // may be very large, we cannot use client_request_time to approximate
2290         // current time when calling select_best_http().
2291         ret = rr->select_best_http(&t_state.client_info.src_addr.sa, now, static_cast<int>(t_state.txn_conf->down_server_timeout));
2292         // set the srv target`s last_failure
2293         if (t_state.dns_info.srv_lookup_success) {
2294           uint32_t last_failure = 0xFFFFFFFF;
2295           for (int i = 0; i < rr->rrcount && last_failure != 0; ++i) {
2296             if (last_failure > rr->info(i).app.http_data.last_failure) {
2297               last_failure = rr->info(i).app.http_data.last_failure;
2298             }
2299           }
2300 
2301           if (last_failure != 0 && static_cast<uint32_t>(now - t_state.txn_conf->down_server_timeout) < last_failure) {
2302             HostDBApplicationInfo app;
2303             app.allotment.application1 = 0;
2304             app.allotment.application2 = 0;
2305             app.http_data.last_failure = last_failure;
2306             hostDBProcessor.setby_srv(t_state.dns_info.lookup_name, 0, t_state.dns_info.srv_hostname, &app);
2307           }
2308         }
2309       }
2310     } else {
2311       if (use_client_addr && !ats_ip_addr_eq(client_addr, &r->data.ip.sa)) {
2312         SMDebug("http", "use_client_target_addr == 1. Comparing single addresses failed, not validated.");
2313         t_state.dns_info.lookup_validated = false;
2314       } else {
2315         ret = r;
2316       }
2317     }
2318     if (ret) {
2319       t_state.host_db_info = *ret;
2320       ink_release_assert(!t_state.host_db_info.reverse_dns);
2321       ink_release_assert(ats_is_ip(t_state.host_db_info.ip()));
2322     }
2323   } else {
2324     SMDebug("http", "[%" PRId64 "] DNS lookup failed for '%s'", sm_id, t_state.dns_info.lookup_name);
2325 
2326     if (!use_client_addr) {
2327       t_state.dns_info.lookup_success = false;
2328     }
2329     t_state.host_db_info.app.allotment.application1 = 0;
2330     t_state.host_db_info.app.allotment.application2 = 0;
2331     ink_assert(!t_state.host_db_info.round_robin);
2332   }
2333 
2334   milestones[TS_MILESTONE_DNS_LOOKUP_END] = Thread::get_hrtime();
2335 
2336   if (is_debug_tag_set("http_timeout")) {
2337     if (t_state.api_txn_dns_timeout_value != -1) {
2338       int foo = static_cast<int>(milestones.difference_msec(TS_MILESTONE_DNS_LOOKUP_BEGIN, TS_MILESTONE_DNS_LOOKUP_END));
2339       SMDebug("http_timeout", "DNS took: %d msec", foo);
2340     }
2341   }
2342 }
2343 
2344 //////////////////////////////////////////////////////////////////////////////
2345 //
2346 //  HttpSM::state_hostdb_lookup()
2347 //
2348 //////////////////////////////////////////////////////////////////////////////
2349 int
state_hostdb_lookup(int event,void * data)2350 HttpSM::state_hostdb_lookup(int event, void *data)
2351 {
2352   STATE_ENTER(&HttpSM::state_hostdb_lookup, event);
2353   //    ink_assert (m_origin_server_vc == 0);
2354   // REQ_FLAVOR_SCHEDULED_UPDATE can be transformed into
2355   // REQ_FLAVOR_REVPROXY
2356   ink_assert(t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE ||
2357              t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY || ua_entry->vc != nullptr);
2358 
2359   switch (event) {
2360   case EVENT_HOST_DB_LOOKUP:
2361     pending_action = nullptr;
2362     process_hostdb_info(static_cast<HostDBInfo *>(data));
2363     call_transact_and_set_next_state(nullptr);
2364     break;
2365   case EVENT_SRV_LOOKUP: {
2366     pending_action = nullptr;
2367     process_srv_info(static_cast<HostDBInfo *>(data));
2368 
2369     char *host_name = t_state.dns_info.srv_lookup_success ? t_state.dns_info.srv_hostname : t_state.dns_info.lookup_name;
2370     HostDBProcessor::Options opt;
2371     opt.port  = t_state.dns_info.srv_lookup_success ? t_state.dns_info.srv_port : t_state.server_info.dst_addr.host_order_port();
2372     opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS :
2373                                                                                  HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD;
2374     opt.timeout        = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;
2375     opt.host_res_style = ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order);
2376 
2377     pending_action = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info, host_name, 0, opt);
2378     if (pending_action.is_empty()) {
2379       call_transact_and_set_next_state(nullptr);
2380     }
2381   } break;
2382   case EVENT_HOST_DB_IP_REMOVED:
2383     ink_assert(!"Unexpected event from HostDB");
2384     break;
2385   default:
2386     ink_assert(!"Unexpected event");
2387   }
2388 
2389   return 0;
2390 }
2391 
2392 int
state_hostdb_reverse_lookup(int event,void * data)2393 HttpSM::state_hostdb_reverse_lookup(int event, void *data)
2394 {
2395   STATE_ENTER(&HttpSM::state_hostdb_reverse_lookup, event);
2396 
2397   // REQ_FLAVOR_SCHEDULED_UPDATE can be transformed into
2398   // REQ_FLAVOR_REVPROXY
2399   ink_assert(t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE ||
2400              t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY || ua_entry->vc != nullptr);
2401 
2402   switch (event) {
2403   case EVENT_HOST_DB_LOOKUP:
2404     pending_action = nullptr;
2405     if (data) {
2406       t_state.request_data.hostname_str = (static_cast<HostDBInfo *>(data))->hostname();
2407     } else {
2408       SMDebug("http", "[%" PRId64 "] reverse DNS lookup failed for '%s'", sm_id, t_state.dns_info.lookup_name);
2409     }
2410     call_transact_and_set_next_state(nullptr);
2411     break;
2412   default:
2413     ink_assert(!"Unexpected event");
2414   }
2415 
2416   return 0;
2417 }
2418 
2419 //////////////////////////////////////////////////////////////////////////////
2420 //
2421 //  HttpSM:state_mark_os_down()
2422 //
2423 //////////////////////////////////////////////////////////////////////////////
2424 int
state_mark_os_down(int event,void * data)2425 HttpSM::state_mark_os_down(int event, void *data)
2426 {
2427   STATE_ENTER(&HttpSM::state_mark_os_down, event);
2428   HostDBInfo *mark_down = nullptr;
2429 
2430   if (event == EVENT_HOST_DB_LOOKUP && data) {
2431     HostDBInfo *r = static_cast<HostDBInfo *>(data);
2432 
2433     if (r->round_robin) {
2434       // Look for the entry we need mark down in the round robin
2435       ink_assert(t_state.current.server != nullptr);
2436       ink_assert(t_state.current.request_to == HttpTransact::ORIGIN_SERVER);
2437       if (t_state.current.server) {
2438         mark_down = r->rr()->find_ip(&t_state.current.server->dst_addr.sa);
2439       }
2440     } else {
2441       // No longer a round robin, check to see if our address is the same
2442       if (ats_ip_addr_eq(t_state.host_db_info.ip(), r->ip())) {
2443         mark_down = r;
2444       }
2445     }
2446 
2447     if (mark_down) {
2448       mark_host_failure(mark_down, t_state.request_sent_time);
2449     }
2450   }
2451   // We either found our entry or we did not.  Either way find
2452   //  the entry we should use now
2453   return state_hostdb_lookup(event, data);
2454 }
2455 
2456 //////////////////////////////////////////////////////////////////////////
2457 //
2458 //  HttpSM::state_handle_stat_page()
2459 //
2460 //////////////////////////////////////////////////////////////////////////
2461 int
state_handle_stat_page(int event,void * data)2462 HttpSM::state_handle_stat_page(int event, void *data)
2463 {
2464   STATE_ENTER(&HttpSM::state_handle_stat_page, event);
2465   switch (event) {
2466   case STAT_PAGE_SUCCESS:
2467     pending_action = nullptr;
2468 
2469     if (data) {
2470       StatPageData *spd = static_cast<StatPageData *>(data);
2471 
2472       t_state.internal_msg_buffer = spd->data;
2473       if (spd->type) {
2474         t_state.internal_msg_buffer_type = spd->type;
2475       } else {
2476         t_state.internal_msg_buffer_type = nullptr; // Defaults to text/html
2477       }
2478       t_state.internal_msg_buffer_size                = spd->length;
2479       t_state.internal_msg_buffer_fast_allocator_size = -1;
2480     }
2481 
2482     call_transact_and_set_next_state(HttpTransact::HandleStatPage);
2483     break;
2484 
2485   case STAT_PAGE_FAILURE:
2486     pending_action = nullptr;
2487     call_transact_and_set_next_state(HttpTransact::HandleStatPage);
2488     break;
2489 
2490   default:
2491     ink_release_assert(0);
2492     break;
2493   }
2494 
2495   return 0;
2496 }
2497 
2498 /////////////////////////////////////////////////////////////////////////////////
2499 //  HttpSM::state_cache_open_write()
2500 //
2501 //  This state is set by set_next_state() for a cache open write
2502 //  (SERVER_READ_CACHE_WRITE)
2503 //
2504 //////////////////////////////////////////////////////////////////////////
2505 int
state_cache_open_write(int event,void * data)2506 HttpSM::state_cache_open_write(int event, void *data)
2507 {
2508   STATE_ENTER(&HttpSM : state_cache_open_write, event);
2509 
2510   // Make sure we are on the "right" thread
2511   if (ua_txn) {
2512     pending_action = ua_txn->adjust_thread(this, event, data);
2513     if (!pending_action.is_empty()) {
2514       HTTP_INCREMENT_DYN_STAT(http_cache_open_write_adjust_thread_stat);
2515       return 0; // Go away if we reschedule
2516     }
2517     NetVConnection *vc = ua_txn->get_netvc();
2518     ink_release_assert(vc && vc->thread == this_ethread());
2519   }
2520 
2521   pending_action.clear_if_action_is(reinterpret_cast<Action *>(data));
2522 
2523   milestones[TS_MILESTONE_CACHE_OPEN_WRITE_END] = Thread::get_hrtime();
2524   pending_action                                = nullptr;
2525 
2526   switch (event) {
2527   case CACHE_EVENT_OPEN_WRITE:
2528     //////////////////////////////
2529     // OPEN WRITE is successful //
2530     //////////////////////////////
2531     t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_SUCCESS;
2532     break;
2533 
2534   case CACHE_EVENT_OPEN_WRITE_FAILED:
2535     // Failed on the write lock and retrying the vector
2536     //  for reading
2537     if (t_state.redirect_info.redirect_in_process) {
2538       SMDebug("http_redirect", "[%" PRId64 "] CACHE_EVENT_OPEN_WRITE_FAILED during redirect follow", sm_id);
2539       t_state.cache_open_write_fail_action = CACHE_WL_FAIL_ACTION_DEFAULT;
2540       t_state.cache_info.write_lock_state  = HttpTransact::CACHE_WL_FAIL;
2541       break;
2542     }
2543     if (t_state.txn_conf->cache_open_write_fail_action == CACHE_WL_FAIL_ACTION_DEFAULT) {
2544       t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_FAIL;
2545       break;
2546     } else {
2547       t_state.cache_open_write_fail_action = t_state.txn_conf->cache_open_write_fail_action;
2548       if (!t_state.cache_info.object_read ||
2549           (t_state.cache_open_write_fail_action == CACHE_WL_FAIL_ACTION_ERROR_ON_MISS_OR_REVALIDATE)) {
2550         // cache miss, set wl_state to fail
2551         SMDebug("http", "[%" PRId64 "] cache object read %p, cache_wl_fail_action %d", sm_id, t_state.cache_info.object_read,
2552                 t_state.cache_open_write_fail_action);
2553         t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_FAIL;
2554         break;
2555       }
2556     }
2557   // INTENTIONAL FALL THROUGH
2558   // Allow for stale object to be served
2559   case CACHE_EVENT_OPEN_READ:
2560     if (!t_state.cache_info.object_read) {
2561       t_state.cache_open_write_fail_action = t_state.txn_conf->cache_open_write_fail_action;
2562       // Note that CACHE_LOOKUP_COMPLETE may be invoked more than once
2563       // if CACHE_WL_FAIL_ACTION_READ_RETRY is configured
2564       ink_assert(t_state.cache_open_write_fail_action == CACHE_WL_FAIL_ACTION_READ_RETRY);
2565       t_state.cache_lookup_result         = HttpTransact::CACHE_LOOKUP_NONE;
2566       t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_READ_RETRY;
2567       break;
2568     }
2569     // The write vector was locked and the cache_sm retried
2570     // and got the read vector again.
2571     cache_sm.cache_read_vc->get_http_info(&t_state.cache_info.object_read);
2572     // ToDo: Should support other levels of cache hits here, but the cache does not support it (yet)
2573     if (cache_sm.cache_read_vc->is_ram_cache_hit()) {
2574       t_state.cache_info.hit_miss_code = SQUID_HIT_RAM;
2575     } else {
2576       t_state.cache_info.hit_miss_code = SQUID_HIT_DISK;
2577     }
2578 
2579     ink_assert(t_state.cache_info.object_read != nullptr);
2580     t_state.source = HttpTransact::SOURCE_CACHE;
2581     // clear up CACHE_LOOKUP_MISS, let Freshness function decide
2582     // hit status
2583     t_state.cache_lookup_result         = HttpTransact::CACHE_LOOKUP_NONE;
2584     t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_READ_RETRY;
2585     break;
2586 
2587   case HTTP_TUNNEL_EVENT_DONE:
2588     // In the case where we have issued a cache write for the
2589     //  transformed copy, the tunnel from the origin server to
2590     //  the transform may complete while we are waiting for
2591     //  the cache write.  If this is the case, forward the event
2592     //  to the transform read state as it will know how to
2593     //  handle it
2594     if (t_state.next_action == HttpTransact::SM_ACTION_CACHE_ISSUE_WRITE_TRANSFORM) {
2595       state_common_wait_for_transform_read(&transform_info, &HttpSM::tunnel_handler, event, data);
2596 
2597       return 0;
2598     }
2599   // Fallthrough
2600   default:
2601     ink_release_assert(0);
2602   }
2603 
2604   // The write either succeeded or failed, notify transact
2605   call_transact_and_set_next_state(nullptr);
2606 
2607   return 0;
2608 }
2609 
2610 inline void
setup_cache_lookup_complete_api()2611 HttpSM::setup_cache_lookup_complete_api()
2612 {
2613   t_state.api_next_action = HttpTransact::SM_ACTION_API_CACHE_LOOKUP_COMPLETE;
2614   do_api_callout();
2615 }
2616 
2617 //////////////////////////////////////////////////////////////////////////
2618 //
2619 //  HttpSM::state_cache_open_read()
2620 //
2621 //  This state handles the result of CacheProcessor::open_read()
2622 //  that attempts to do cache lookup and open a particular cached
2623 //  object for reading.
2624 //
2625 //////////////////////////////////////////////////////////////////////////
2626 int
state_cache_open_read(int event,void * data)2627 HttpSM::state_cache_open_read(int event, void *data)
2628 {
2629   STATE_ENTER(&HttpSM::state_cache_open_read, event);
2630 
2631   pending_action.clear_if_action_is(reinterpret_cast<Action *>(data));
2632 
2633   ink_assert(server_entry == nullptr);
2634   ink_assert(t_state.cache_info.object_read == nullptr);
2635 
2636   switch (event) {
2637   case CACHE_EVENT_OPEN_READ: {
2638     pending_action = nullptr;
2639 
2640     SMDebug("http", "[%" PRId64 "] cache_open_read - CACHE_EVENT_OPEN_READ", sm_id);
2641 
2642     /////////////////////////////////
2643     // lookup/open is successful. //
2644     /////////////////////////////////
2645     ink_assert(cache_sm.cache_read_vc != nullptr);
2646     t_state.source = HttpTransact::SOURCE_CACHE;
2647 
2648     cache_sm.cache_read_vc->get_http_info(&t_state.cache_info.object_read);
2649     // ToDo: Should support other levels of cache hits here, but the cache does not support it (yet)
2650     if (cache_sm.cache_read_vc->is_ram_cache_hit()) {
2651       t_state.cache_info.hit_miss_code = SQUID_HIT_RAM;
2652     } else {
2653       t_state.cache_info.hit_miss_code = SQUID_HIT_DISK;
2654     }
2655 
2656     ink_assert(t_state.cache_info.object_read != nullptr);
2657     call_transact_and_set_next_state(HttpTransact::HandleCacheOpenRead);
2658     break;
2659   }
2660   case CACHE_EVENT_OPEN_READ_FAILED:
2661     pending_action = nullptr;
2662 
2663     SMDebug("http", "[%" PRId64 "] cache_open_read - CACHE_EVENT_OPEN_READ_FAILED with %s (%d)", sm_id,
2664             InkStrerror(-cache_sm.get_last_error()), -cache_sm.get_last_error());
2665 
2666     SMDebug("http", "[state_cache_open_read] open read failed.");
2667     // Inform HttpTransact somebody else is updating the document
2668     // HttpCacheSM already waited so transact should go ahead.
2669     if (cache_sm.get_last_error() == -ECACHE_DOC_BUSY) {
2670       t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_DOC_BUSY;
2671     } else {
2672       t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_MISS;
2673     }
2674 
2675     ink_assert(t_state.transact_return_point == nullptr);
2676     t_state.transact_return_point = HttpTransact::HandleCacheOpenRead;
2677     setup_cache_lookup_complete_api();
2678     break;
2679 
2680   default:
2681     ink_release_assert(!"Unknown event");
2682     break;
2683   }
2684 
2685   milestones[TS_MILESTONE_CACHE_OPEN_READ_END] = Thread::get_hrtime();
2686 
2687   return 0;
2688 }
2689 
2690 int
main_handler(int event,void * data)2691 HttpSM::main_handler(int event, void *data)
2692 {
2693   ink_release_assert(magic == HTTP_SM_MAGIC_ALIVE);
2694 
2695   HttpSMHandler jump_point = nullptr;
2696   ink_assert(reentrancy_count >= 0);
2697   reentrancy_count++;
2698 
2699   // Don't use the state enter macro since it uses history
2700   //  space that we don't care about
2701   SMDebug("http", "[%" PRId64 "] [HttpSM::main_handler, %s]", sm_id, HttpDebugNames::get_event_name(event));
2702 
2703   HttpVCTableEntry *vc_entry = nullptr;
2704 
2705   if (data != nullptr) {
2706     // Only search the VC table if the event could have to
2707     //  do with a VIO to save a few cycles
2708 
2709     if (event < VC_EVENT_EVENTS_START + 100) {
2710       vc_entry = vc_table.find_entry(static_cast<VIO *>(data));
2711     }
2712   }
2713 
2714   if (vc_entry) {
2715     jump_point = vc_entry->vc_handler;
2716     ink_assert(jump_point != (HttpSMHandler) nullptr);
2717     ink_assert(vc_entry->vc != (VConnection *)nullptr);
2718     (this->*jump_point)(event, data);
2719   } else {
2720     ink_assert(default_handler != (HttpSMHandler) nullptr);
2721     (this->*default_handler)(event, data);
2722   }
2723 
2724   // The sub-handler signals when it is time for the state
2725   //  machine to exit.  We can only exit if we are not reentrantly
2726   //  called otherwise when the our call unwinds, we will be
2727   //  running on a dead state machine
2728   //
2729   // Because of the need for an api shutdown hook, kill_this()
2730   // is also reentrant.  As such, we don't want to decrement
2731   // the reentrancy count until after we run kill_this()
2732   //
2733   if (terminate_sm == true && reentrancy_count == 1) {
2734     kill_this();
2735   } else {
2736     reentrancy_count--;
2737     ink_assert(reentrancy_count >= 0);
2738   }
2739 
2740   return (VC_EVENT_CONT);
2741 }
2742 
2743 // void HttpSM::tunnel_handler_post_or_put()
2744 //
2745 //   Handles the common cleanup tasks for Http post/put
2746 //   to prevent code duplication
2747 //
2748 void
tunnel_handler_post_or_put(HttpTunnelProducer * p)2749 HttpSM::tunnel_handler_post_or_put(HttpTunnelProducer *p)
2750 {
2751   ink_assert(p->vc_type == HT_HTTP_CLIENT || (p->handler_state == HTTP_SM_POST_UA_FAIL && p->vc_type == HT_BUFFER_READ));
2752   HttpTunnelConsumer *c;
2753 
2754   // If there is a post transform, remove it's entry from the State
2755   //  Machine's VC table
2756   //
2757   // MUST NOT clear the vc pointer from post_transform_info
2758   //    as this causes a double close of the transform vc in transform_cleanup
2759   //
2760   if (post_transform_info.vc != nullptr) {
2761     ink_assert(post_transform_info.entry->in_tunnel == true);
2762     ink_assert(post_transform_info.vc == post_transform_info.entry->vc);
2763     vc_table.cleanup_entry(post_transform_info.entry);
2764     post_transform_info.entry = nullptr;
2765   }
2766 
2767   switch (p->handler_state) {
2768   case HTTP_SM_POST_SERVER_FAIL:
2769     c = tunnel.get_consumer(server_entry->vc);
2770     ink_assert(c->write_success == false);
2771     break;
2772   case HTTP_SM_POST_UA_FAIL:
2773     // UA quit - shutdown the SM
2774     ink_assert(p->read_success == false);
2775     terminate_sm = true;
2776     break;
2777   case HTTP_SM_POST_SUCCESS:
2778     // The post succeeded
2779     ink_assert(p->read_success == true);
2780     ink_assert(p->consumer_list.head->write_success == true);
2781     tunnel.deallocate_buffers();
2782     tunnel.reset();
2783     // When the ua completed sending it's data we must have
2784     //  removed it from the tunnel
2785     ua_entry->in_tunnel     = false;
2786     server_entry->in_tunnel = false;
2787 
2788     break;
2789   default:
2790     ink_release_assert(0);
2791   }
2792 }
2793 
2794 // int HttpSM::tunnel_handler_post(int event, void* data)
2795 //
2796 //   Handles completion of any http request body tunnel
2797 //     Having 'post' in its name is a misnomer
2798 //
2799 int
tunnel_handler_post(int event,void * data)2800 HttpSM::tunnel_handler_post(int event, void *data)
2801 {
2802   STATE_ENTER(&HttpSM::tunnel_handler_post, event);
2803 
2804   HttpTunnelProducer *p = ua_txn != nullptr ? tunnel.get_producer(ua_txn) : tunnel.get_producer(HT_HTTP_CLIENT);
2805   if (!p) {
2806     return 0; // Cannot do anything if there is no producer
2807   }
2808 
2809   switch (event) {
2810   case HTTP_TUNNEL_EVENT_DONE: // Tunnel done.
2811     if (p->handler_state == HTTP_SM_POST_UA_FAIL) {
2812       // post failed
2813       switch (t_state.client_info.state) {
2814       case HttpTransact::ACTIVE_TIMEOUT:
2815         call_transact_and_set_next_state(HttpTransact::PostActiveTimeoutResponse);
2816         return 0;
2817       case HttpTransact::INACTIVE_TIMEOUT:
2818         call_transact_and_set_next_state(HttpTransact::PostInactiveTimeoutResponse);
2819         return 0;
2820       default:
2821         break;
2822       }
2823     }
2824     break;
2825   case VC_EVENT_WRITE_READY: // iocore may callback first before send.
2826     return 0;
2827   case VC_EVENT_EOS:                // SSLNetVC may callback EOS during write error (6.0.x or early)
2828   case VC_EVENT_ERROR:              // Send HTTP 408 error
2829   case VC_EVENT_WRITE_COMPLETE:     // tunnel_handler_post_ua has sent HTTP 408 response
2830   case VC_EVENT_INACTIVITY_TIMEOUT: // ua_txn timeout during sending the HTTP 408 response
2831   case VC_EVENT_ACTIVE_TIMEOUT:     // ua_txn timeout
2832     if (ua_entry->write_buffer) {
2833       free_MIOBuffer(ua_entry->write_buffer);
2834       ua_entry->write_buffer = nullptr;
2835     }
2836     if (!p->handler_state) {
2837       p->handler_state = HTTP_SM_POST_UA_FAIL;
2838     }
2839     break;
2840   case VC_EVENT_READ_READY:
2841   case VC_EVENT_READ_COMPLETE:
2842   default:
2843     ink_assert(!"not reached");
2844     return 0;
2845   }
2846 
2847   ink_assert(event == HTTP_TUNNEL_EVENT_DONE);
2848   ink_assert(data == &tunnel);
2849   // The tunnel calls this when it is done
2850 
2851   int p_handler_state = p->handler_state;
2852   if (is_waiting_for_full_body && !this->is_postbuf_valid()) {
2853     p_handler_state = HTTP_SM_POST_SERVER_FAIL;
2854   }
2855   if (p->vc_type != HT_BUFFER_READ) {
2856     tunnel_handler_post_or_put(p);
2857   }
2858 
2859   switch (p_handler_state) {
2860   case HTTP_SM_POST_SERVER_FAIL:
2861     handle_post_failure();
2862     break;
2863   case HTTP_SM_POST_UA_FAIL:
2864     // Client side failed.  Shutdown and go home.  No need to communicate back to UA
2865     terminate_sm = true;
2866     break;
2867   case HTTP_SM_POST_SUCCESS:
2868     // It's time to start reading the response
2869     if (is_waiting_for_full_body) {
2870       is_waiting_for_full_body  = false;
2871       is_using_post_buffer      = true;
2872       client_request_body_bytes = this->postbuf_buffer_avail();
2873 
2874       call_transact_and_set_next_state(HttpTransact::HandleRequestBufferDone);
2875       break;
2876     }
2877     setup_server_read_response_header();
2878     break;
2879   default:
2880     ink_release_assert(0);
2881   }
2882 
2883   return 0;
2884 }
2885 
2886 int
tunnel_handler_cache_fill(int event,void * data)2887 HttpSM::tunnel_handler_cache_fill(int event, void *data)
2888 {
2889   STATE_ENTER(&HttpSM::tunnel_handler_cache_fill, event);
2890 
2891   ink_assert(event == HTTP_TUNNEL_EVENT_DONE);
2892   ink_assert(data == &tunnel);
2893 
2894   ink_release_assert(cache_sm.cache_write_vc);
2895 
2896   tunnel.deallocate_buffers();
2897   this->postbuf_clear();
2898   tunnel.reset();
2899 
2900   setup_server_transfer_to_cache_only();
2901   tunnel.tunnel_run();
2902 
2903   return 0;
2904 }
2905 
2906 int
tunnel_handler_100_continue(int event,void * data)2907 HttpSM::tunnel_handler_100_continue(int event, void *data)
2908 {
2909   STATE_ENTER(&HttpSM::tunnel_handler_100_continue, event);
2910 
2911   ink_assert(event == HTTP_TUNNEL_EVENT_DONE);
2912   ink_assert(data == &tunnel);
2913 
2914   // We're done sending the 100 continue.  If we succeeded,
2915   //   we set up to parse the next server response.  If we
2916   //   failed, shutdown the state machine
2917   HttpTunnelConsumer *c = tunnel.get_consumer(ua_txn);
2918 
2919   if (c->write_success) {
2920     // Note: we must use destroy() here since clear()
2921     //  does not free the memory from the header
2922     t_state.hdr_info.client_response.destroy();
2923     tunnel.deallocate_buffers();
2924     this->postbuf_clear();
2925     tunnel.reset();
2926 
2927     if (server_entry->eos) {
2928       // if the server closed while sending the
2929       //    100 continue header, handle it here so we
2930       //    don't assert later
2931       SMDebug("http",
2932               "[%" PRId64 "] tunnel_handler_100_continue - server already "
2933               "closed, terminating connection",
2934               sm_id);
2935 
2936       // Since 100 isn't a final (loggable) response header
2937       //   kill the 100 continue header and create an empty one
2938       t_state.hdr_info.server_response.destroy();
2939       t_state.hdr_info.server_response.create(HTTP_TYPE_RESPONSE);
2940       handle_server_setup_error(VC_EVENT_EOS, server_entry->read_vio);
2941     } else {
2942       setup_server_read_response_header();
2943     }
2944   } else {
2945     terminate_sm = true;
2946   }
2947 
2948   return 0;
2949 }
2950 
2951 int
tunnel_handler_push(int event,void * data)2952 HttpSM::tunnel_handler_push(int event, void *data)
2953 {
2954   STATE_ENTER(&HttpSM::tunnel_handler_push, event);
2955 
2956   ink_assert(event == HTTP_TUNNEL_EVENT_DONE);
2957   ink_assert(data == &tunnel);
2958 
2959   // Check to see if the client is still around
2960   HttpTunnelProducer *ua = (ua_txn) ? tunnel.get_producer(ua_txn) : tunnel.get_producer(HT_HTTP_CLIENT);
2961 
2962   if (ua && !ua->read_success) {
2963     // Client failed to send the body, it's gone.  Kill the
2964     // state machine
2965     terminate_sm = true;
2966     return 0;
2967   }
2968 
2969   HttpTunnelConsumer *cache = ua->consumer_list.head;
2970   ink_release_assert(cache->vc_type == HT_CACHE_WRITE);
2971   bool cache_write_success = cache->write_success;
2972 
2973   // Reset tunneling state since we need to send a response
2974   //  to client as whether we succeeded
2975   tunnel.deallocate_buffers();
2976   this->postbuf_clear();
2977   tunnel.reset();
2978 
2979   if (cache_write_success) {
2980     call_transact_and_set_next_state(HttpTransact::HandlePushTunnelSuccess);
2981   } else {
2982     call_transact_and_set_next_state(HttpTransact::HandlePushTunnelFailure);
2983   }
2984 
2985   return 0;
2986 }
2987 
2988 int
tunnel_handler(int event,void * data)2989 HttpSM::tunnel_handler(int event, void *data)
2990 {
2991   STATE_ENTER(&HttpSM::tunnel_handler, event);
2992 
2993   ink_assert(event == HTTP_TUNNEL_EVENT_DONE);
2994   // The tunnel calls this when it is done
2995   terminate_sm = true;
2996 
2997   if (unlikely(t_state.is_websocket)) {
2998     HTTP_DECREMENT_DYN_STAT(http_websocket_current_active_client_connections_stat);
2999   }
3000 
3001   return 0;
3002 }
3003 
3004 /****************************************************
3005    TUNNELING HANDLERS
3006    ******************************************************/
3007 
3008 bool
is_http_server_eos_truncation(HttpTunnelProducer * p)3009 HttpSM::is_http_server_eos_truncation(HttpTunnelProducer *p)
3010 {
3011   if ((p->do_dechunking || p->do_chunked_passthru) && p->chunked_handler.truncation) {
3012     return true;
3013   }
3014 
3015   //////////////////////////////////////////////////////////////
3016   // If we did not get or did not trust the origin server's   //
3017   //  content-length, read_content_length is unset.  The      //
3018   //  only way the end of the document is signaled is the     //
3019   //  origin server closing the connection.  However, we      //
3020   //  need to protect against the document getting truncated  //
3021   //  because the origin server crashed.  The following       //
3022   //  tabled outlines when we mark the server read as failed  //
3023   //                                                          //
3024   //    No C-L               :  read success                  //
3025   //    Received byts < C-L  :  read failed (=> Cache Abort)  //
3026   //    Received byts == C-L :  read success                  //
3027   //    Received byts > C-L  :  read success                  //
3028   //////////////////////////////////////////////////////////////
3029   int64_t cl = t_state.hdr_info.server_response.get_content_length();
3030 
3031   if (cl != UNDEFINED_COUNT && cl > server_response_body_bytes) {
3032     SMDebug("http", "[%" PRId64 "] server EOS after %" PRId64 " bytes, expected %" PRId64, sm_id, server_response_body_bytes, cl);
3033     return true;
3034   } else {
3035     return false;
3036   }
3037 }
3038 
3039 int
tunnel_handler_server(int event,HttpTunnelProducer * p)3040 HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p)
3041 {
3042   STATE_ENTER(&HttpSM::tunnel_handler_server, event);
3043 
3044   // An intercept handler may not set TS_MILESTONE_SERVER_CONNECT
3045   // by default. Therefore we only set TS_MILESTONE_SERVER_CLOSE if
3046   // TS_MILESTONE_SERVER_CONNECT is set (non-zero), lest certain time
3047   // statistics are calculated from epoch time.
3048   if (0 != milestones[TS_MILESTONE_SERVER_CONNECT]) {
3049     milestones[TS_MILESTONE_SERVER_CLOSE] = Thread::get_hrtime();
3050   }
3051 
3052   bool close_connection = false;
3053 
3054   if (t_state.current.server->keep_alive == HTTP_KEEPALIVE && server_entry->eos == false &&
3055       plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL && t_state.txn_conf->keep_alive_enabled_out == 1) {
3056     close_connection = false;
3057   } else {
3058     if (t_state.current.server->keep_alive != HTTP_KEEPALIVE) {
3059       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_server_no_keep_alive);
3060     } else if (server_entry->eos == true) {
3061       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_server_eos);
3062     } else {
3063       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_server_plugin_tunnel);
3064     }
3065     close_connection = true;
3066   }
3067 
3068   switch (event) {
3069   case VC_EVENT_INACTIVITY_TIMEOUT:
3070   case VC_EVENT_ACTIVE_TIMEOUT:
3071   case VC_EVENT_ERROR:
3072     t_state.squid_codes.log_code  = SQUID_LOG_ERR_READ_TIMEOUT;
3073     t_state.squid_codes.hier_code = SQUID_HIER_TIMEOUT_DIRECT;
3074     /* fallthru */
3075 
3076   case VC_EVENT_EOS:
3077 
3078     switch (event) {
3079     case VC_EVENT_INACTIVITY_TIMEOUT:
3080       t_state.current.server->state = HttpTransact::INACTIVE_TIMEOUT;
3081       break;
3082     case VC_EVENT_ACTIVE_TIMEOUT:
3083       t_state.current.server->state = HttpTransact::ACTIVE_TIMEOUT;
3084       break;
3085     case VC_EVENT_ERROR:
3086       t_state.current.server->state = HttpTransact::CONNECTION_ERROR;
3087       break;
3088     case VC_EVENT_EOS:
3089       t_state.current.server->state = HttpTransact::TRANSACTION_COMPLETE;
3090       break;
3091     }
3092 
3093     HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_server);
3094     close_connection = true;
3095 
3096     ink_assert(p->vc_type == HT_HTTP_SERVER);
3097 
3098     if (is_http_server_eos_truncation(p)) {
3099       SMDebug("http", "[%" PRId64 "] [HttpSM::tunnel_handler_server] aborting HTTP tunnel due to server truncation", sm_id);
3100       tunnel.chain_abort_all(p);
3101       // UA session may not be in the tunnel yet, don't NULL out the pointer in that case.
3102       // Note: This is a hack. The correct solution is for the UA session to signal back to the SM
3103       // when the UA is about to be destroyed and clean up the pointer there. That should be done once
3104       // the TS-3612 changes are in place (and similarly for the server session).
3105       /*if (ua_entry->in_tunnel)
3106         ua_txn = NULL; */
3107 
3108       t_state.current.server->abort      = HttpTransact::ABORTED;
3109       t_state.client_info.keep_alive     = HTTP_NO_KEEPALIVE;
3110       t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE;
3111       if (event == VC_EVENT_EOS) {
3112         t_state.squid_codes.log_code = SQUID_LOG_ERR_READ_ERROR;
3113       }
3114     } else {
3115       SMDebug("http", "[%" PRId64 "] [HttpSM::tunnel_handler_server] finishing HTTP tunnel", sm_id);
3116       p->read_success               = true;
3117       t_state.current.server->abort = HttpTransact::DIDNOT_ABORT;
3118       // Appending reason to a response without Content-Length will result in
3119       // the reason string being written to the client and a bad CL when reading from cache.
3120       // I didn't find anywhere this appended reason is being used, so commenting it out.
3121       /*
3122         if (t_state.is_cacheable_due_to_negative_caching_configuration && p->bytes_read == 0) {
3123         int reason_len;
3124         const char *reason = t_state.hdr_info.server_response.reason_get(&reason_len);
3125         if (reason == NULL)
3126         tunnel.append_message_to_producer_buffer(p, "Negative Response", sizeof("Negative Response") - 1);
3127         else
3128         tunnel.append_message_to_producer_buffer(p, reason, reason_len);
3129         }
3130       */
3131       tunnel.local_finish_all(p);
3132     }
3133     break;
3134 
3135   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
3136   case VC_EVENT_READ_COMPLETE:
3137     //
3138     // The transfer completed successfully
3139     //    If there is still data in the buffer, the server
3140     //    sent too much indicating a failed transfer
3141     p->read_success               = true;
3142     t_state.current.server->state = HttpTransact::TRANSACTION_COMPLETE;
3143     t_state.current.server->abort = HttpTransact::DIDNOT_ABORT;
3144 
3145     if (p->do_dechunking || p->do_chunked_passthru) {
3146       if (p->chunked_handler.truncation) {
3147         tunnel.abort_cache_write_finish_others(p);
3148         // We couldn't read all chunks successfully:
3149         // Disable keep-alive.
3150         t_state.client_info.keep_alive     = HTTP_NO_KEEPALIVE;
3151         t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE;
3152       } else {
3153         tunnel.local_finish_all(p);
3154       }
3155     }
3156     break;
3157 
3158   case HTTP_TUNNEL_EVENT_CONSUMER_DETACH:
3159     // All consumers are prematurely gone.  Shutdown
3160     //    the server connection
3161     p->read_success               = true;
3162     t_state.current.server->state = HttpTransact::TRANSACTION_COMPLETE;
3163     t_state.current.server->abort = HttpTransact::DIDNOT_ABORT;
3164     HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_server_detach);
3165     close_connection = true;
3166     break;
3167 
3168   case VC_EVENT_READ_READY:
3169   case VC_EVENT_WRITE_READY:
3170   case VC_EVENT_WRITE_COMPLETE:
3171   default:
3172     // None of these events should ever come our way
3173     ink_assert(0);
3174     break;
3175   }
3176 
3177   // turn off negative caching in case there are multiple server contacts
3178   if (t_state.is_cacheable_due_to_negative_caching_configuration) {
3179     t_state.is_cacheable_due_to_negative_caching_configuration = false;
3180   }
3181 
3182   // If we had a ground fill, check update our status
3183   if (background_fill == BACKGROUND_FILL_STARTED) {
3184     background_fill = p->read_success ? BACKGROUND_FILL_COMPLETED : BACKGROUND_FILL_ABORTED;
3185     HTTP_DECREMENT_DYN_STAT(http_background_fill_current_count_stat);
3186   }
3187   // We handled the event.  Now either shutdown the connection or
3188   //   setup it up for keep-alive
3189   ink_assert(server_entry->vc == p->vc);
3190   ink_assert(p->vc_type == HT_HTTP_SERVER);
3191   ink_assert(p->vc == server_session);
3192 
3193   // The server session has been released. Clean all pointer
3194   // Calling remove_entry instead of server_entry because we don't
3195   // want to close the server VC at this point
3196   vc_table.remove_entry(server_entry);
3197 
3198   if (close_connection) {
3199     p->vc->do_io_close();
3200     p->read_vio = nullptr;
3201     /* TS-1424: if we're outbound transparent and using the client
3202        source port for the outbound connection we must effectively
3203        propagate server closes back to the client. Part of that is
3204        disabling KeepAlive if the server closes.
3205     */
3206     if (ua_txn && ua_txn->is_outbound_transparent() && t_state.http_config_param->use_client_source_port) {
3207       t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE;
3208     }
3209   } else {
3210     server_session->attach_hostname(t_state.current.server->name);
3211     HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat);
3212 
3213     // If the option to attach the server session to the client session is set
3214     // and if the client is still around and the client is keep-alive, attach the
3215     // server session to so the next ka request can use it.  Server sessions will
3216     // be placed into the shared pool if the next incoming request is for a different
3217     // origin server
3218     bool release_origin_connection = true;
3219     if (t_state.txn_conf->attach_server_session_to_client == 1 && ua_txn && t_state.client_info.keep_alive == HTTP_KEEPALIVE) {
3220       Debug("http", "attaching server session to the client");
3221       if (ua_txn->attach_server_session(server_session)) {
3222         release_origin_connection = false;
3223       }
3224     }
3225     if (release_origin_connection) {
3226       // Release the session back into the shared session pool
3227       server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out));
3228       server_session->release(nullptr);
3229     }
3230   }
3231 
3232   server_session = nullptr; // Because p->vc == server_session
3233   server_entry   = nullptr;
3234 
3235   return 0;
3236 }
3237 
3238 // int HttpSM::tunnel_handler_100_continue_ua(int event, HttpTunnelConsumer* c)
3239 //
3240 //     Used for tunneling the 100 continue response.  The tunnel
3241 //       should not close or release the user agent unless there is
3242 //       an error since the real response is yet to come
3243 //
3244 int
tunnel_handler_100_continue_ua(int event,HttpTunnelConsumer * c)3245 HttpSM::tunnel_handler_100_continue_ua(int event, HttpTunnelConsumer *c)
3246 {
3247   STATE_ENTER(&HttpSM::tunnel_handler_100_continue_ua, event);
3248 
3249   ink_assert(c->vc == ua_txn);
3250 
3251   switch (event) {
3252   case VC_EVENT_EOS:
3253     ua_entry->eos = true;
3254   // FALL-THROUGH
3255   case VC_EVENT_INACTIVITY_TIMEOUT:
3256   case VC_EVENT_ACTIVE_TIMEOUT:
3257   case VC_EVENT_ERROR:
3258     set_ua_abort(HttpTransact::ABORTED, event);
3259     c->vc->do_io_close();
3260     break;
3261   case VC_EVENT_WRITE_COMPLETE:
3262     // mark the vc as no longer in tunnel
3263     //   so we don't get hosed if the ua abort before
3264     //   real response header is received
3265     ua_entry->in_tunnel = false;
3266     c->write_success    = true;
3267   }
3268 
3269   return 0;
3270 }
3271 
3272 bool
is_bg_fill_necessary(HttpTunnelConsumer * c)3273 HttpSM::is_bg_fill_necessary(HttpTunnelConsumer *c)
3274 {
3275   ink_assert(c->vc_type == HT_HTTP_CLIENT);
3276 
3277   if (c->producer->alive &&          // something there to read
3278                                      //      server_entry && server_entry->vc &&              // from an origin server
3279                                      //      server_session && server_session->get_netvc() && // which is still open and valid
3280       c->producer->num_consumers > 1 // with someone else reading it
3281   ) {
3282     HttpTunnelProducer *p = nullptr;
3283 
3284     if (!server_entry || !server_entry->vc || !server_session || !server_session->get_netvc()) {
3285       // return true if we have finished the reading from OS when client aborted
3286       p = c->producer->self_consumer ? c->producer->self_consumer->producer : c->producer;
3287       if (p->vc_type == HT_HTTP_SERVER && p->read_success) {
3288         return true;
3289       } else {
3290         return false;
3291       }
3292     }
3293     // If threshold is 0.0 or negative then do background
3294     //   fill regardless of the content length.  Since this
3295     //   is floating point just make sure the number is near zero
3296     if (t_state.txn_conf->background_fill_threshold <= 0.001) {
3297       return true;
3298     }
3299 
3300     int64_t ua_cl = t_state.hdr_info.client_response.get_content_length();
3301 
3302     if (ua_cl > 0) {
3303       int64_t ua_body_done = c->bytes_written - client_response_hdr_bytes;
3304       float pDone          = static_cast<float>(ua_body_done) / ua_cl;
3305 
3306       // If we got a good content length.  Check to make sure that we haven't already
3307       //  done more the content length since that would indicate the content-length
3308       //  is bogus.  If we've done more than the threshold, continue the background fill
3309       if (pDone <= 1.0 && pDone > t_state.txn_conf->background_fill_threshold) {
3310         return true;
3311       } else {
3312         SMDebug("http", "[%" PRId64 "] no background.  Only %%%f of %%%f done [%" PRId64 " / %" PRId64 " ]", sm_id, pDone,
3313                 t_state.txn_conf->background_fill_threshold, ua_body_done, ua_cl);
3314       }
3315     }
3316   }
3317 
3318   return false;
3319 }
3320 
3321 int
tunnel_handler_ua(int event,HttpTunnelConsumer * c)3322 HttpSM::tunnel_handler_ua(int event, HttpTunnelConsumer *c)
3323 {
3324   bool close_connection     = true;
3325   HttpTunnelProducer *p     = nullptr;
3326   HttpTunnelConsumer *selfc = nullptr;
3327 
3328   STATE_ENTER(&HttpSM::tunnel_handler_ua, event);
3329   ink_assert(c->vc == ua_txn);
3330   milestones[TS_MILESTONE_UA_CLOSE] = Thread::get_hrtime();
3331 
3332   switch (event) {
3333   case VC_EVENT_EOS:
3334     ua_entry->eos = true;
3335 
3336   // FALL-THROUGH
3337   case VC_EVENT_INACTIVITY_TIMEOUT:
3338   case VC_EVENT_ACTIVE_TIMEOUT:
3339   case VC_EVENT_ERROR:
3340 
3341     // The user agent died or aborted.  Check to
3342     //  see if we should setup a background fill
3343     set_ua_abort(HttpTransact::ABORTED, event);
3344 
3345     if (is_bg_fill_necessary(c)) {
3346       p = c->producer->self_consumer ? c->producer->self_consumer->producer : c->producer;
3347       SMDebug("http", "[%" PRId64 "] Initiating background fill", sm_id);
3348       // check whether to finish the reading.
3349       background_fill = p->read_success ? BACKGROUND_FILL_COMPLETED : BACKGROUND_FILL_STARTED;
3350 
3351       // There is another consumer (cache write) so
3352       //  detach the user agent
3353       if (background_fill == BACKGROUND_FILL_STARTED) {
3354         HTTP_INCREMENT_DYN_STAT(http_background_fill_current_count_stat);
3355         HTTP_INCREMENT_DYN_STAT(http_background_fill_total_count_stat);
3356 
3357         ink_assert(server_entry->vc == server_session);
3358         ink_assert(c->is_downstream_from(server_session));
3359         server_session->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->background_fill_active_timeout));
3360       }
3361 
3362       // Even with the background fill, the client side should go down
3363       c->write_vio = nullptr;
3364       c->vc->do_io_close(EHTTP_ERROR);
3365       c->alive = false;
3366 
3367     } else {
3368       // No background fill
3369       p = c->producer;
3370       tunnel.chain_abort_all(c->producer);
3371       selfc = p->self_consumer;
3372       if (selfc) {
3373         // This is the case where there is a transformation between ua and os
3374         p = selfc->producer;
3375         // if producer is the cache or OS, close the producer.
3376         // Otherwise in case of large docs, producer iobuffer gets filled up,
3377         // waiting for a consumer to consume data and the connection is never closed.
3378         if (p->alive && ((p->vc_type == HT_CACHE_READ) || (p->vc_type == HT_HTTP_SERVER))) {
3379           tunnel.chain_abort_all(p);
3380         }
3381       }
3382     }
3383     break;
3384 
3385   case VC_EVENT_WRITE_COMPLETE:
3386     c->write_success          = true;
3387     t_state.client_info.abort = HttpTransact::DIDNOT_ABORT;
3388     if (t_state.client_info.keep_alive == HTTP_KEEPALIVE) {
3389       if (t_state.www_auth_content != HttpTransact::CACHE_AUTH_SERVE || ua_txn->get_server_session()) {
3390         // successful keep-alive
3391         close_connection = false;
3392       }
3393     }
3394     break;
3395   case VC_EVENT_WRITE_READY:
3396   case VC_EVENT_READ_READY:
3397   case VC_EVENT_READ_COMPLETE:
3398   default:
3399     // None of these events should ever come our way
3400     ink_assert(0);
3401     break;
3402   }
3403 
3404   client_response_body_bytes = c->bytes_written - client_response_hdr_bytes;
3405 
3406   if (client_response_body_bytes < 0) {
3407     client_response_body_bytes = 0;
3408   }
3409 
3410   // attribute the size written to the client from various sources
3411   // NOTE: responses that go through a range transform are attributed
3412   // to their original sources
3413   // all other transforms attribute the total number of input bytes
3414   // to a source in HttpSM::tunnel_handler_transform_write
3415   //
3416   HttpTransact::Source_t original_source = t_state.source;
3417   if (HttpTransact::SOURCE_TRANSFORM == original_source && t_state.range_setup != HttpTransact::RANGE_NONE) {
3418     original_source = t_state.pre_transform_source;
3419   }
3420 
3421   switch (original_source) {
3422   case HttpTransact::SOURCE_HTTP_ORIGIN_SERVER:
3423     server_response_body_bytes = client_response_body_bytes;
3424     break;
3425   case HttpTransact::SOURCE_CACHE:
3426     cache_response_body_bytes = client_response_body_bytes;
3427     break;
3428   default:
3429     break;
3430   }
3431 
3432   ink_assert(ua_entry->vc == c->vc);
3433   if (close_connection) {
3434     // If the client could be pipelining or is doing a POST, we need to
3435     //   set the ua_txn into half close mode
3436 
3437     // only external POSTs should be subject to this logic; ruling out internal POSTs here
3438     bool is_eligible_post_request = ((t_state.method == HTTP_WKSIDX_POST) && !is_internal);
3439 
3440     if (is_eligible_post_request && c->producer->vc_type != HT_STATIC && event == VC_EVENT_WRITE_COMPLETE) {
3441       ua_txn->set_half_close_flag(true);
3442     }
3443 
3444     vc_table.remove_entry(this->ua_entry);
3445     ua_txn->do_io_close();
3446   } else {
3447     ink_assert(ua_buffer_reader != nullptr);
3448     ua_txn->release(ua_buffer_reader);
3449     ua_txn->get_proxy_ssn()->release(ua_txn);
3450     ua_buffer_reader = nullptr;
3451     // ua_txn       = NULL;
3452   }
3453 
3454   return 0;
3455 }
3456 
3457 int
tunnel_handler_ua_push(int event,HttpTunnelProducer * p)3458 HttpSM::tunnel_handler_ua_push(int event, HttpTunnelProducer *p)
3459 {
3460   STATE_ENTER(&HttpSM::tunnel_handler_ua_push, event);
3461 
3462   pushed_response_body_bytes += p->bytes_read;
3463   client_request_body_bytes += p->bytes_read;
3464 
3465   switch (event) {
3466   case VC_EVENT_INACTIVITY_TIMEOUT:
3467   case VC_EVENT_ACTIVE_TIMEOUT:
3468   case VC_EVENT_ERROR:
3469   case VC_EVENT_EOS:
3470     // Transfer terminated.  Bail on the cache write.
3471     set_ua_abort(HttpTransact::ABORTED, event);
3472     p->vc->do_io_close(EHTTP_ERROR);
3473     p->read_vio = nullptr;
3474     tunnel.chain_abort_all(p);
3475     break;
3476 
3477   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
3478   case VC_EVENT_READ_COMPLETE:
3479     //
3480     // The transfer completed successfully
3481     p->read_success     = true;
3482     ua_entry->in_tunnel = false;
3483     break;
3484 
3485   case VC_EVENT_READ_READY:
3486   case VC_EVENT_WRITE_READY:
3487   case VC_EVENT_WRITE_COMPLETE:
3488   default:
3489     // None of these events should ever come our way
3490     ink_assert(0);
3491     break;
3492   }
3493 
3494   return 0;
3495 }
3496 
3497 int
tunnel_handler_cache_read(int event,HttpTunnelProducer * p)3498 HttpSM::tunnel_handler_cache_read(int event, HttpTunnelProducer *p)
3499 {
3500   STATE_ENTER(&HttpSM::tunnel_handler_cache_read, event);
3501 
3502   switch (event) {
3503   case VC_EVENT_ERROR:
3504   case VC_EVENT_EOS:
3505     ink_assert(t_state.cache_info.object_read->valid());
3506     if (t_state.cache_info.object_read->object_size_get() != INT64_MAX || event == VC_EVENT_ERROR) {
3507       // Abnormal termination
3508       t_state.squid_codes.log_code = SQUID_LOG_TCP_SWAPFAIL;
3509       p->vc->do_io_close(EHTTP_ERROR);
3510       p->read_vio = nullptr;
3511       tunnel.chain_abort_all(p);
3512       HTTP_INCREMENT_DYN_STAT(http_cache_read_errors);
3513       break;
3514     } else {
3515       tunnel.local_finish_all(p);
3516       // fall through for the case INT64_MAX read with VC_EVENT_EOS
3517       // callback (read successful)
3518     }
3519     // fallthrough
3520 
3521   case VC_EVENT_READ_COMPLETE:
3522   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
3523   case HTTP_TUNNEL_EVENT_CONSUMER_DETACH:
3524     p->read_success = true;
3525     p->vc->do_io_close();
3526     p->read_vio = nullptr;
3527     break;
3528   default:
3529     ink_release_assert(0);
3530     break;
3531   }
3532 
3533   HTTP_DECREMENT_DYN_STAT(http_current_cache_connections_stat);
3534   return 0;
3535 }
3536 
3537 int
tunnel_handler_cache_write(int event,HttpTunnelConsumer * c)3538 HttpSM::tunnel_handler_cache_write(int event, HttpTunnelConsumer *c)
3539 {
3540   STATE_ENTER(&HttpSM::tunnel_handler_cache_write, event);
3541 
3542   HttpTransact::CacheWriteStatus_t *status_ptr =
3543     (c->producer->vc_type == HT_TRANSFORM) ? &t_state.cache_info.transform_write_status : &t_state.cache_info.write_status;
3544 
3545   switch (event) {
3546   case VC_EVENT_ERROR:
3547   case VC_EVENT_EOS:
3548     // Abnormal termination
3549     *status_ptr  = HttpTransact::CACHE_WRITE_ERROR;
3550     c->write_vio = nullptr;
3551     c->vc->do_io_close(EHTTP_ERROR);
3552 
3553     HTTP_INCREMENT_DYN_STAT(http_cache_write_errors);
3554     SMDebug("http", "[%" PRId64 "] aborting cache write due %s event from cache", sm_id, HttpDebugNames::get_event_name(event));
3555     // abort the producer if the cache_writevc is the only consumer.
3556     if (c->producer->alive && c->producer->num_consumers == 1) {
3557       tunnel.chain_abort_all(c->producer);
3558     }
3559     break;
3560   case VC_EVENT_WRITE_COMPLETE:
3561     // if we've never initiated a cache write
3562     //   abort the cache since it's finicky about a close
3563     //   in this case.  This case can only occur
3564     //   we got a truncated header from the origin server
3565     //   but decided to accept it anyways
3566     if (c->write_vio == nullptr) {
3567       *status_ptr      = HttpTransact::CACHE_WRITE_ERROR;
3568       c->write_success = false;
3569       c->vc->do_io_close(EHTTP_ERROR);
3570     } else {
3571       *status_ptr      = HttpTransact::CACHE_WRITE_COMPLETE;
3572       c->write_success = true;
3573       c->vc->do_io_close();
3574       c->write_vio = nullptr;
3575     }
3576     break;
3577   default:
3578     // All other events indicate problems
3579     ink_assert(0);
3580     break;
3581   }
3582 
3583   if (background_fill != BACKGROUND_FILL_NONE) {
3584     server_response_body_bytes = c->bytes_written;
3585   }
3586 
3587   HTTP_DECREMENT_DYN_STAT(http_current_cache_connections_stat);
3588   return 0;
3589 }
3590 
3591 int
tunnel_handler_post_ua(int event,HttpTunnelProducer * p)3592 HttpSM::tunnel_handler_post_ua(int event, HttpTunnelProducer *p)
3593 {
3594   STATE_ENTER(&HttpSM::tunnel_handler_post_ua, event);
3595   client_request_body_bytes = p->init_bytes_done + p->bytes_read;
3596 
3597   switch (event) {
3598   case VC_EVENT_INACTIVITY_TIMEOUT:
3599   case VC_EVENT_ACTIVE_TIMEOUT:
3600     if (client_response_hdr_bytes == 0) {
3601       p->handler_state = HTTP_SM_POST_UA_FAIL;
3602       set_ua_abort(HttpTransact::ABORTED, event);
3603 
3604       SMDebug("http_tunnel", "send 408 response to client to vc %p, tunnel vc %p", ua_txn->get_netvc(), p->vc);
3605 
3606       tunnel.chain_abort_all(p);
3607       server_session = nullptr;
3608       // Reset the inactivity timeout, otherwise the InactivityCop will callback again in the next second.
3609       ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
3610       // if it is active timeout case, we need to give another chance to send 408 response;
3611       ua_txn->set_active_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_active_timeout_in));
3612 
3613       return 0;
3614     }
3615   // fall through
3616   case VC_EVENT_EOS:
3617   // My reading of spec says that user agents can not terminate
3618   //  posts with a half close so this is an error
3619   case VC_EVENT_ERROR:
3620     //  Did not complete post tunneling.  Abort the
3621     //   server and close the ua
3622     p->handler_state = HTTP_SM_POST_UA_FAIL;
3623     set_ua_abort(HttpTransact::ABORTED, event);
3624     tunnel.chain_abort_all(p);
3625     server_session = nullptr;
3626     // the in_tunnel status on both the ua & and
3627     //   it's consumer must already be set to true.  Previously
3628     //   we were setting it again to true but incorrectly in
3629     //   the case of a transform
3630     hsm_release_assert(ua_entry->in_tunnel == true);
3631     if (p->consumer_list.head && p->consumer_list.head->vc_type == HT_TRANSFORM) {
3632       hsm_release_assert(post_transform_info.entry->in_tunnel == true);
3633     } // server side may have completed before the user agent side, so it may no longer be in tunnel
3634 
3635     // In the error case, start to take down the client session. There should
3636     // be no reuse here
3637     vc_table.remove_entry(this->ua_entry);
3638     ua_txn->do_io_close();
3639     break;
3640 
3641   case VC_EVENT_READ_COMPLETE:
3642   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
3643     p->handler_state    = HTTP_SM_POST_SUCCESS;
3644     p->read_success     = true;
3645     ua_entry->in_tunnel = false;
3646 
3647     if (p->do_dechunking || p->do_chunked_passthru) {
3648       if (p->chunked_handler.truncation) {
3649         tunnel.abort_cache_write_finish_others(p);
3650       } else {
3651         tunnel.local_finish_all(p);
3652       }
3653     }
3654 
3655     // Now that we have communicated the post body, turn off the inactivity timeout
3656     // until the server starts sending data back
3657     if (ua_txn && t_state.hdr_info.request_content_length > 0) {
3658       ua_txn->cancel_inactivity_timeout();
3659     }
3660 
3661     // Initiate another read to catch aborts
3662     ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort;
3663     ua_entry->read_vio   = p->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf);
3664     break;
3665   default:
3666     ink_release_assert(0);
3667   }
3668 
3669   return 0;
3670 }
3671 
3672 // YTS Team, yamsat Plugin
3673 // Tunnel handler to deallocate the tunnel buffers and
3674 // set redirect_in_process=false
3675 // Copy partial POST data to buffers. Check for the various parameters including
3676 // the maximum configured post data size
3677 int
tunnel_handler_for_partial_post(int event,void *)3678 HttpSM::tunnel_handler_for_partial_post(int event, void * /* data ATS_UNUSED */)
3679 {
3680   STATE_ENTER(&HttpSM::tunnel_handler_for_partial_post, event);
3681   tunnel.deallocate_buffers();
3682   tunnel.reset();
3683 
3684   t_state.redirect_info.redirect_in_process = false;
3685   is_using_post_buffer                      = false;
3686 
3687   if (post_failed) {
3688     post_failed = false;
3689     handle_post_failure();
3690   } else {
3691     do_setup_post_tunnel(HTTP_SERVER_VC);
3692   }
3693 
3694   return 0;
3695 }
3696 
3697 int
tunnel_handler_post_server(int event,HttpTunnelConsumer * c)3698 HttpSM::tunnel_handler_post_server(int event, HttpTunnelConsumer *c)
3699 {
3700   STATE_ENTER(&HttpSM::tunnel_handler_post_server, event);
3701 
3702   server_request_body_bytes = c->bytes_written;
3703 
3704   switch (event) {
3705   case VC_EVENT_EOS:
3706   case VC_EVENT_ERROR:
3707   case VC_EVENT_INACTIVITY_TIMEOUT:
3708   case VC_EVENT_ACTIVE_TIMEOUT:
3709 
3710     switch (event) {
3711     case VC_EVENT_INACTIVITY_TIMEOUT:
3712       t_state.current.state = HttpTransact::INACTIVE_TIMEOUT;
3713       t_state.set_connect_fail(ETIMEDOUT);
3714       break;
3715     case VC_EVENT_ACTIVE_TIMEOUT:
3716       t_state.current.state = HttpTransact::ACTIVE_TIMEOUT;
3717       t_state.set_connect_fail(ETIMEDOUT);
3718       break;
3719     case VC_EVENT_EOS:
3720       t_state.current.state = HttpTransact::CONNECTION_CLOSED;
3721       t_state.set_connect_fail(EPIPE);
3722       break;
3723     case VC_EVENT_ERROR:
3724       t_state.current.state = HttpTransact::CONNECTION_CLOSED;
3725       t_state.set_connect_fail(server_session->get_netvc()->lerrno);
3726       break;
3727     default:
3728       break;
3729     }
3730 
3731     //  Did not complete post tunneling
3732     //
3733     //    In the http case, we don't want to close
3734     //    the connection because the
3735     //    destroys the header buffer which may
3736     //    a response even though the tunnel failed.
3737 
3738     // Shutdown both sides of the connection.  This prevents us
3739     //  from getting any further events and signals to client
3740     //  that POST data will not be forwarded to the server.  Doing
3741     //  shutdown on the write side will likely generate a TCP
3742     //  reset to the client but if the proxy wasn't here this is
3743     //  exactly what would happen.
3744     // we should wait to shutdown read side of the
3745     // client to prevent sending a reset
3746     server_entry->eos = true;
3747     c->vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
3748 
3749     // We may be reading from a transform.  In that case, we
3750     //   want to close the transform
3751     HttpTunnelProducer *ua_producer;
3752     if (c->producer->vc_type == HT_TRANSFORM) {
3753       if (c->producer->handler_state == HTTP_SM_TRANSFORM_OPEN) {
3754         ink_assert(c->producer->vc == post_transform_info.vc);
3755         c->producer->vc->do_io_close();
3756         c->producer->alive                = false;
3757         c->producer->self_consumer->alive = false;
3758       }
3759       ua_producer = c->producer->self_consumer->producer;
3760     } else {
3761       ua_producer = c->producer;
3762     }
3763     ink_assert(ua_producer->vc_type == HT_HTTP_CLIENT);
3764     ink_assert(ua_producer->vc == ua_txn);
3765     ink_assert(ua_producer->vc == ua_entry->vc);
3766 
3767     // Before shutting down, initiate another read
3768     //  on the user agent in order to get timeouts
3769     //  coming to the state machine and not the tunnel
3770     ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort;
3771 
3772     // YTS Team, yamsat Plugin
3773     // When event is VC_EVENT_ERROR,and when redirection is enabled
3774     // do not shut down the client read
3775     if (enable_redirection) {
3776       if (ua_producer->vc_type == HT_STATIC && event != VC_EVENT_ERROR && event != VC_EVENT_EOS) {
3777         ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf);
3778         // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ);
3779       } else {
3780         if (ua_producer->vc_type == HT_STATIC && t_state.redirect_info.redirect_in_process) {
3781           post_failed = true;
3782         }
3783       }
3784     } else {
3785       ua_entry->read_vio = ua_producer->vc->do_io_read(this, INT64_MAX, ua_buffer_reader->mbuf);
3786       // we should not shutdown read side of the client here to prevent sending a reset
3787       // ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ);
3788     } // end of added logic
3789 
3790     // We want to shutdown the tunnel here and see if there
3791     //   is a response on from the server.  Mark the user
3792     //   agent as down so that tunnel concludes.
3793     ua_producer->alive         = false;
3794     ua_producer->handler_state = HTTP_SM_POST_SERVER_FAIL;
3795     ink_assert(tunnel.is_tunnel_alive() == false);
3796     break;
3797 
3798   case VC_EVENT_WRITE_COMPLETE:
3799     // Completed successfully
3800     c->write_success        = true;
3801     server_entry->in_tunnel = false;
3802     break;
3803   default:
3804     ink_release_assert(0);
3805   }
3806 
3807   return 0;
3808 }
3809 
3810 int
tunnel_handler_ssl_producer(int event,HttpTunnelProducer * p)3811 HttpSM::tunnel_handler_ssl_producer(int event, HttpTunnelProducer *p)
3812 {
3813   STATE_ENTER(&HttpSM::tunnel_handler_ssl_producer, event);
3814 
3815   switch (event) {
3816   case VC_EVENT_EOS:
3817     // The write side of this connection is still alive
3818     //  so half-close the read
3819     if (p->self_consumer->alive) {
3820       p->vc->do_io_shutdown(IO_SHUTDOWN_READ);
3821       tunnel.local_finish_all(p);
3822       break;
3823     }
3824   // FALL THROUGH - both sides of the tunnel are dea
3825   case VC_EVENT_ERROR:
3826   case VC_EVENT_INACTIVITY_TIMEOUT:
3827   case VC_EVENT_ACTIVE_TIMEOUT:
3828     // The other side of the connection is either already dead
3829     //   or rendered inoperative by the error on the connection
3830     //   Note: use tunnel close vc so the tunnel knows we are
3831     //    nuking the of the connection as well
3832     tunnel.close_vc(p);
3833     tunnel.local_finish_all(p);
3834 
3835     // Because we've closed the net vc this error came in, it's write
3836     //  direction is now dead as well.  If that side still being fed data,
3837     //  we need to kill that pipe as well
3838     if (p->self_consumer->producer->alive) {
3839       p->self_consumer->producer->alive = false;
3840       if (p->self_consumer->producer->self_consumer->alive) {
3841         p->self_consumer->producer->vc->do_io_shutdown(IO_SHUTDOWN_READ);
3842       } else {
3843         tunnel.close_vc(p->self_consumer->producer);
3844       }
3845     }
3846     break;
3847   case VC_EVENT_READ_COMPLETE:
3848   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
3849   // We should never get these event since we don't know
3850   //  how long the stream is
3851   default:
3852     ink_release_assert(0);
3853   }
3854 
3855   // Update stats
3856   switch (p->vc_type) {
3857   case HT_HTTP_SERVER:
3858     server_response_body_bytes += p->bytes_read;
3859     break;
3860   case HT_HTTP_CLIENT:
3861     client_request_body_bytes += p->bytes_read;
3862     break;
3863   default:
3864     // Covered here:
3865     // HT_CACHE_READ, HT_CACHE_WRITE,
3866     // HT_TRANSFORM, HT_STATIC.
3867     break;
3868   }
3869 
3870   return 0;
3871 }
3872 
3873 int
tunnel_handler_ssl_consumer(int event,HttpTunnelConsumer * c)3874 HttpSM::tunnel_handler_ssl_consumer(int event, HttpTunnelConsumer *c)
3875 {
3876   STATE_ENTER(&HttpSM::tunnel_handler_ssl_consumer, event);
3877 
3878   switch (event) {
3879   case VC_EVENT_ERROR:
3880   case VC_EVENT_EOS:
3881   case VC_EVENT_INACTIVITY_TIMEOUT:
3882   case VC_EVENT_ACTIVE_TIMEOUT:
3883     // we need to mark the producer dead
3884     // otherwise it can stay alive forever.
3885     if (c->producer->alive) {
3886       c->producer->alive = false;
3887       if (c->producer->self_consumer->alive) {
3888         c->producer->vc->do_io_shutdown(IO_SHUTDOWN_READ);
3889       } else {
3890         tunnel.close_vc(c->producer);
3891       }
3892     }
3893     // Since we are changing the state of the self_producer
3894     //  we must have the tunnel shutdown the vc
3895     tunnel.close_vc(c);
3896     tunnel.local_finish_all(c->self_producer);
3897     break;
3898 
3899   case VC_EVENT_WRITE_COMPLETE:
3900     // If we get this event, it means that the producer
3901     //  has finished and we wrote the remaining data
3902     //  to the consumer
3903     //
3904     // If the read side of this connection has not yet
3905     //  closed, do a write half-close and then wait for
3906     //  read side to close so that we don't cut off
3907     //  pipelined responses with TCP resets
3908     //
3909     // ink_assert(c->producer->alive == false);
3910     c->write_success = true;
3911     if (c->self_producer->alive == true) {
3912       c->vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
3913     } else {
3914       c->vc->do_io_close();
3915     }
3916     break;
3917 
3918   default:
3919     ink_release_assert(0);
3920   }
3921 
3922   // Update stats
3923   switch (c->vc_type) {
3924   case HT_HTTP_SERVER:
3925     server_request_body_bytes += c->bytes_written;
3926     break;
3927   case HT_HTTP_CLIENT:
3928     client_response_body_bytes += c->bytes_written;
3929     break;
3930   default:
3931     // Handled here:
3932     // HT_CACHE_READ, HT_CACHE_WRITE, HT_TRANSFORM,
3933     // HT_STATIC
3934     break;
3935   }
3936 
3937   return 0;
3938 }
3939 
3940 int
tunnel_handler_transform_write(int event,HttpTunnelConsumer * c)3941 HttpSM::tunnel_handler_transform_write(int event, HttpTunnelConsumer *c)
3942 {
3943   STATE_ENTER(&HttpSM::tunnel_handler_transform_write, event);
3944 
3945   HttpTransformInfo *i;
3946 
3947   // Figure out if this the request or response transform
3948   // : use post_transform_info.entry because post_transform_info.vc
3949   // is not set to NULL after the post transform is done.
3950   if (post_transform_info.entry) {
3951     i = &post_transform_info;
3952     ink_assert(c->vc == i->entry->vc);
3953   } else {
3954     i = &transform_info;
3955     ink_assert(c->vc == i->vc);
3956     ink_assert(c->vc == i->entry->vc);
3957   }
3958 
3959   switch (event) {
3960   case VC_EVENT_ERROR:
3961     // Transform error
3962     tunnel.chain_abort_all(c->producer);
3963     c->handler_state = HTTP_SM_TRANSFORM_FAIL;
3964     c->vc->do_io_close(EHTTP_ERROR);
3965     break;
3966   case VC_EVENT_EOS:
3967     //   It possible the transform quit
3968     //   before the producer finished.  If this is true
3969     //   we need shut  down the producer if it doesn't
3970     //   have other consumers to serve or else it will
3971     //   fill up buffer and get hung
3972     if (c->producer->alive && c->producer->num_consumers == 1) {
3973       // Send a tunnel detach event to the producer
3974       //   to shut it down but indicates it should not abort
3975       //   downstream (on the other side of the transform)
3976       //   cache writes
3977       tunnel.producer_handler(HTTP_TUNNEL_EVENT_CONSUMER_DETACH, c->producer);
3978     }
3979   // FALLTHROUGH
3980   case VC_EVENT_WRITE_COMPLETE:
3981     // write to transform complete - shutdown the write side
3982     c->write_success = true;
3983     c->vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
3984 
3985     // If the read side has not started up yet, then the
3986     //  this transform_vc is no longer owned by the tunnel
3987     if (c->self_producer == nullptr) {
3988       i->entry->in_tunnel = false;
3989     } else if (c->self_producer->alive == false) {
3990       // The read side of the Transform
3991       //   has already completed (possible when the
3992       //   transform intentionally truncates the response).
3993       //   So close it
3994       c->vc->do_io_close();
3995     }
3996     break;
3997   default:
3998     ink_release_assert(0);
3999   }
4000 
4001   // attribute the size written to the transform from various sources
4002   // NOTE: the range transform is excluded from this accounting and
4003   // is instead handled in HttpSM::tunnel_handler_ua
4004   //
4005   // the reasoning is that the range transform is internal functionality
4006   // in support of HTTP 1.1 compliance, therefore part of "normal" operation
4007   // all other transforms are plugin driven and the difference between
4008   // source data and final data should represent the transformation delta
4009   //
4010   if (t_state.range_setup == HttpTransact::RANGE_NONE) {
4011     switch (t_state.pre_transform_source) {
4012     case HttpTransact::SOURCE_HTTP_ORIGIN_SERVER:
4013       server_response_body_bytes = client_response_body_bytes;
4014       break;
4015     case HttpTransact::SOURCE_CACHE:
4016       cache_response_body_bytes = client_response_body_bytes;
4017       break;
4018     default:
4019       break;
4020     }
4021   }
4022 
4023   return 0;
4024 }
4025 
4026 int
tunnel_handler_transform_read(int event,HttpTunnelProducer * p)4027 HttpSM::tunnel_handler_transform_read(int event, HttpTunnelProducer *p)
4028 {
4029   STATE_ENTER(&HttpSM::tunnel_handler_transform_read, event);
4030 
4031   ink_assert(p->vc == transform_info.vc || p->vc == post_transform_info.vc);
4032 
4033   switch (event) {
4034   case VC_EVENT_ERROR:
4035     // Transform error
4036     tunnel.chain_abort_all(p->self_consumer->producer);
4037     break;
4038   case VC_EVENT_EOS:
4039     // If we did not get enough data from the transform abort the
4040     //    cache write otherwise fallthrough to the transform
4041     //    completing successfully
4042     if (t_state.hdr_info.transform_response_cl != HTTP_UNDEFINED_CL &&
4043         p->read_vio->nbytes < t_state.hdr_info.transform_response_cl) {
4044       tunnel.abort_cache_write_finish_others(p);
4045       break;
4046     }
4047   // FALL-THROUGH
4048   case VC_EVENT_READ_COMPLETE:
4049   case HTTP_TUNNEL_EVENT_PRECOMPLETE:
4050     // Transform complete
4051     p->read_success = true;
4052     tunnel.local_finish_all(p);
4053     break;
4054   default:
4055     ink_release_assert(0);
4056   }
4057 
4058   // it's possible that the write side of the
4059   //  transform hasn't detached yet.  If it is still alive,
4060   //  don't close the transform vc
4061   if (p->self_consumer->alive == false) {
4062     HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_tunnel_transform_read);
4063     p->vc->do_io_close();
4064   }
4065   p->handler_state = HTTP_SM_TRANSFORM_CLOSED;
4066 
4067   return 0;
4068 }
4069 
4070 int
tunnel_handler_plugin_agent(int event,HttpTunnelConsumer * c)4071 HttpSM::tunnel_handler_plugin_agent(int event, HttpTunnelConsumer *c)
4072 {
4073   STATE_ENTER(&HttpSM::tunnel_handler_plugin_client, event);
4074 
4075   switch (event) {
4076   case VC_EVENT_ERROR:
4077     c->vc->do_io_close(EHTTP_ERROR); // close up
4078     // Signal producer if we're the last consumer.
4079     if (c->producer->alive && c->producer->num_consumers == 1) {
4080       tunnel.producer_handler(HTTP_TUNNEL_EVENT_CONSUMER_DETACH, c->producer);
4081     }
4082     break;
4083   case VC_EVENT_EOS:
4084     if (c->producer->alive && c->producer->num_consumers == 1) {
4085       tunnel.producer_handler(HTTP_TUNNEL_EVENT_CONSUMER_DETACH, c->producer);
4086     }
4087   // FALLTHROUGH
4088   case VC_EVENT_WRITE_COMPLETE:
4089     c->write_success = true;
4090     c->vc->do_io_close();
4091     break;
4092   default:
4093     ink_release_assert(0);
4094   }
4095 
4096   return 0;
4097 }
4098 
4099 int
state_remap_request(int event,void *)4100 HttpSM::state_remap_request(int event, void * /* data ATS_UNUSED */)
4101 {
4102   STATE_ENTER(&HttpSM::state_remap_request, event);
4103 
4104   switch (event) {
4105   case EVENT_REMAP_ERROR: {
4106     ink_assert(!"this doesn't happen");
4107     pending_action = nullptr;
4108     Error("error remapping request [see previous errors]");
4109     call_transact_and_set_next_state(HttpTransact::HandleRequest); // HandleRequest skips EndRemapRequest
4110     break;
4111   }
4112 
4113   case EVENT_REMAP_COMPLETE: {
4114     pending_action = nullptr;
4115     SMDebug("url_rewrite", "completed processor-based remapping request for [%" PRId64 "]", sm_id);
4116     t_state.url_remap_success = remapProcessor.finish_remap(&t_state, m_remap);
4117     call_transact_and_set_next_state(nullptr);
4118     break;
4119   }
4120 
4121   default:
4122     ink_assert(!"Unexpected event inside state_remap_request");
4123     break;
4124   }
4125 
4126   return 0;
4127 }
4128 
4129 // This check must be called before remap.  Otherwise, the client_request host
4130 // name may be changed.
4131 void
check_sni_host()4132 HttpSM::check_sni_host()
4133 {
4134   // Check that the SNI and host name fields match, if it matters
4135   // Issue warning or mark the transaction to be terminated as necessary
4136   int host_len;
4137   const char *host_name = t_state.hdr_info.client_request.host_get(&host_len);
4138   if (host_name && host_len) {
4139     if (ua_txn->support_sni()) {
4140       int host_sni_policy   = t_state.http_config_param->http_host_sni_policy;
4141       NetVConnection *netvc = ua_txn->get_netvc();
4142       if (netvc) {
4143         IpEndpoint ip = netvc->get_remote_endpoint();
4144         if (SNIConfig::TestClientAction(std::string{host_name, static_cast<size_t>(host_len)}.c_str(), ip, host_sni_policy) &&
4145             host_sni_policy > 0) {
4146           // In a SNI/Host mismatch where the Host would have triggered SNI policy, mark the transaction
4147           // to be considered for rejection after the remap phase passes.  Gives the opportunity to conf_remap
4148           // override the policy.:w
4149           //
4150           //
4151           // to be rejected
4152           // in the end_remap logic
4153           const char *sni_value    = netvc->get_server_name();
4154           const char *action_value = host_sni_policy == 2 ? "terminate" : "continue";
4155           if (!sni_value || sni_value[0] == '\0') { // No SNI
4156             Warning("No SNI for TLS request with hostname %.*s action=%s", host_len, host_name, action_value);
4157             if (host_sni_policy == 2) {
4158               this->t_state.client_connection_enabled = false;
4159             }
4160           } else if (strncmp(host_name, sni_value, host_len) != 0) { // Name mismatch
4161             Warning("SNI/hostname mismatch sni=%s host=%.*s action=%s", sni_value, host_len, host_name, action_value);
4162             if (host_sni_policy == 2) {
4163               this->t_state.client_connection_enabled = false;
4164             }
4165           }
4166         }
4167       }
4168     }
4169   }
4170 }
4171 
4172 void
do_remap_request(bool run_inline)4173 HttpSM::do_remap_request(bool run_inline)
4174 {
4175   SMDebug("http_seq", "[HttpSM::do_remap_request] Remapping request");
4176   SMDebug("url_rewrite", "Starting a possible remapping for request [%" PRId64 "]", sm_id);
4177   bool ret = remapProcessor.setup_for_remap(&t_state, m_remap);
4178 
4179   check_sni_host();
4180 
4181   // Preserve effective url before remap
4182   t_state.unmapped_url.create(t_state.hdr_info.client_request.url_get()->m_heap);
4183   t_state.unmapped_url.copy(t_state.hdr_info.client_request.url_get());
4184   // Depending on a variety of factors the HOST field may or may not have been promoted to the
4185   // client request URL. The unmapped URL should always have that promotion done. If the HOST field
4186   // is not already there, promote it only in the unmapped_url. This avoids breaking any logic that
4187   // depends on the lack of promotion in the client request URL.
4188   if (!t_state.unmapped_url.m_url_impl->m_ptr_host) {
4189     MIMEField *host_field = t_state.hdr_info.client_request.field_find(MIME_FIELD_HOST, MIME_LEN_HOST);
4190     if (host_field) {
4191       int host_len;
4192       const char *host_name = host_field->value_get(&host_len);
4193       if (host_name && host_len) {
4194         t_state.unmapped_url.host_set(host_name, host_len);
4195       }
4196     }
4197   }
4198 
4199   if (!ret) {
4200     SMDebug("url_rewrite", "Could not find a valid remapping entry for this request [%" PRId64 "]", sm_id);
4201     if (!run_inline) {
4202       handleEvent(EVENT_REMAP_COMPLETE, nullptr);
4203     }
4204     return;
4205   }
4206 
4207   SMDebug("url_rewrite", "Found a remap map entry for [%" PRId64 "], attempting to remap request and call any plugins", sm_id);
4208   pending_action = remapProcessor.perform_remap(this, &t_state);
4209 
4210   return;
4211 }
4212 
4213 void
do_hostdb_lookup()4214 HttpSM::do_hostdb_lookup()
4215 {
4216   ink_assert(t_state.dns_info.lookup_name != nullptr);
4217   ink_assert(pending_action.is_empty());
4218 
4219   milestones[TS_MILESTONE_DNS_LOOKUP_BEGIN] = Thread::get_hrtime();
4220 
4221   if (t_state.txn_conf->srv_enabled) {
4222     char d[MAXDNAME];
4223 
4224     // Look at the next_hop_scheme to determine what scheme to put in the SRV lookup
4225     unsigned int scheme_len = sprintf(d, "_%s._tcp.", hdrtoken_index_to_wks(t_state.next_hop_scheme));
4226     ink_strlcpy(d + scheme_len, t_state.server_info.name, sizeof(d) - scheme_len);
4227 
4228     SMDebug("dns_srv", "Beginning lookup of SRV records for origin %s", d);
4229 
4230     HostDBProcessor::Options opt;
4231     if (t_state.api_txn_dns_timeout_value != -1) {
4232       opt.timeout = t_state.api_txn_dns_timeout_value;
4233     }
4234     pending_action = hostDBProcessor.getSRVbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_srv_info, d, 0, opt);
4235     if (pending_action.is_empty()) {
4236       char *host_name = t_state.dns_info.srv_lookup_success ? t_state.dns_info.srv_hostname : t_state.dns_info.lookup_name;
4237       opt.port        = t_state.dns_info.srv_lookup_success ?
4238                    t_state.dns_info.srv_port :
4239                    t_state.server_info.dst_addr.isValid() ? t_state.server_info.dst_addr.host_order_port() :
4240                                                             t_state.hdr_info.client_request.port_get();
4241       opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS :
4242                                                                                    HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD;
4243       opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;
4244       opt.host_res_style =
4245         ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order);
4246 
4247       pending_action = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info, host_name, 0, opt);
4248       if (pending_action.is_empty()) {
4249         call_transact_and_set_next_state(nullptr);
4250       }
4251     }
4252     return;
4253   } else { /* we aren't using SRV stuff... */
4254     SMDebug("http_seq", "[HttpSM::do_hostdb_lookup] Doing DNS Lookup");
4255 
4256     // If there is not a current server, we must be looking up the origin
4257     //  server at the beginning of the transaction
4258     int server_port = 0;
4259     if (t_state.current.server && t_state.current.server->dst_addr.isValid()) {
4260       server_port = t_state.current.server->dst_addr.host_order_port();
4261     } else if (t_state.server_info.dst_addr.isValid()) {
4262       server_port = t_state.server_info.dst_addr.host_order_port();
4263     } else {
4264       server_port = t_state.hdr_info.client_request.port_get();
4265     }
4266 
4267     if (t_state.api_txn_dns_timeout_value != -1) {
4268       SMDebug("http_timeout", "beginning DNS lookup. allowing %d mseconds for DNS lookup", t_state.api_txn_dns_timeout_value);
4269     }
4270 
4271     HostDBProcessor::Options opt;
4272     opt.port  = server_port;
4273     opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS :
4274                                                                                  HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD;
4275     opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;
4276 
4277     opt.host_res_style = ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order);
4278 
4279     pending_action = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info,
4280                                                    t_state.dns_info.lookup_name, 0, opt);
4281     if (pending_action.is_empty()) {
4282       call_transact_and_set_next_state(nullptr);
4283     }
4284     return;
4285   }
4286   ink_assert(!"not reached");
4287   return;
4288 }
4289 
4290 void
do_hostdb_reverse_lookup()4291 HttpSM::do_hostdb_reverse_lookup()
4292 {
4293   ink_assert(t_state.dns_info.lookup_name != nullptr);
4294   ink_assert(pending_action.is_empty());
4295 
4296   SMDebug("http_seq", "[HttpSM::do_hostdb_reverse_lookup] Doing reverse DNS Lookup");
4297 
4298   IpEndpoint addr;
4299   ats_ip_pton(t_state.dns_info.lookup_name, &addr.sa);
4300   pending_action = hostDBProcessor.getbyaddr_re(this, &addr.sa);
4301 
4302   return;
4303 }
4304 
4305 bool
track_connect_fail() const4306 HttpSM::track_connect_fail() const
4307 {
4308   bool retval = false;
4309   if (t_state.current.server->had_connect_fail()) {
4310     // What does our policy say?
4311     if (t_state.txn_conf->connect_dead_policy == 2) { // Any connection error through TLS handshake
4312       retval = true;
4313     } else if (t_state.txn_conf->connect_dead_policy == 1) { // Any connection error through TCP
4314       retval = t_state.current.server->connect_result != -ENET_SSL_CONNECT_FAILED;
4315     }
4316   }
4317   return retval;
4318 }
4319 
4320 void
do_hostdb_update_if_necessary()4321 HttpSM::do_hostdb_update_if_necessary()
4322 {
4323   int issue_update = 0;
4324 
4325   if (t_state.current.server == nullptr || plugin_tunnel_type != HTTP_NO_PLUGIN_TUNNEL) {
4326     // No server, so update is not necessary
4327     return;
4328   }
4329   // If we failed back over to the origin server, we don't have our
4330   //   hostdb information anymore which means we shouldn't update the hostdb
4331   if (!ats_ip_addr_eq(&t_state.current.server->dst_addr.sa, t_state.host_db_info.ip())) {
4332     SMDebug("http", "[%" PRId64 "] skipping hostdb update due to server failover", sm_id);
4333     return;
4334   }
4335 
4336   if (t_state.updated_server_version != HTTP_INVALID) {
4337     // we may have incorrectly assumed that the hostdb had the wrong version of
4338     // http for the server because our first few connect attempts to the server
4339     // failed, causing us to downgrade our requests to a lower version and changing
4340     // our information about the server version.
4341     //
4342     // This test therefore just issues the update only if the hostdb version is
4343     // in fact different from the version we want the value to be updated to.
4344     if (t_state.host_db_info.app.http_data.http_version != t_state.updated_server_version) {
4345       t_state.host_db_info.app.http_data.http_version = t_state.updated_server_version;
4346       issue_update |= 1;
4347     }
4348 
4349     t_state.updated_server_version = HTTP_INVALID;
4350   }
4351   // Check to see if we need to report or clear a connection failure
4352   if (track_connect_fail()) {
4353     issue_update |= 1;
4354     mark_host_failure(&t_state.host_db_info, t_state.client_request_time);
4355   } else {
4356     if (t_state.host_db_info.app.http_data.last_failure != 0) {
4357       t_state.host_db_info.app.http_data.last_failure = 0;
4358       t_state.host_db_info.app.http_data.fail_count   = 0;
4359       issue_update |= 1;
4360       char addrbuf[INET6_ADDRPORTSTRLEN];
4361       SMDebug("http", "[%" PRId64 "] hostdb update marking IP: %s as up", sm_id,
4362               ats_ip_nptop(&t_state.current.server->dst_addr.sa, addrbuf, sizeof(addrbuf)));
4363     }
4364 
4365     if (t_state.dns_info.srv_lookup_success && t_state.dns_info.srv_app.http_data.last_failure != 0) {
4366       t_state.dns_info.srv_app.http_data.last_failure = 0;
4367       hostDBProcessor.setby_srv(t_state.dns_info.lookup_name, 0, t_state.dns_info.srv_hostname, &t_state.dns_info.srv_app);
4368       SMDebug("http", "[%" PRId64 "] hostdb update marking SRV: %s as up", sm_id, t_state.dns_info.srv_hostname);
4369     }
4370   }
4371 
4372   if (issue_update) {
4373     hostDBProcessor.setby(t_state.current.server->name, strlen(t_state.current.server->name), &t_state.current.server->dst_addr.sa,
4374                           &t_state.host_db_info.app);
4375   }
4376 
4377   char addrbuf[INET6_ADDRPORTSTRLEN];
4378   SMDebug("http", "server info = %s", ats_ip_nptop(&t_state.current.server->dst_addr.sa, addrbuf, sizeof(addrbuf)));
4379   return;
4380 }
4381 
4382 /*
4383  * range entry valid [a,b] (a >= 0 and b >= 0 and a <= b)
4384  * HttpTransact::RANGE_NONE if the content length of cached copy is zero or
4385  * no range entry
4386  * HttpTransact::RANGE_NOT_SATISFIABLE iff all range entries are valid but
4387  * none overlap the current extent of the cached copy
4388  * HttpTransact::RANGE_NOT_HANDLED if out-of-order Range entries or
4389  * the cached copy`s content_length is INT64_MAX (e.g. read_from_writer and trunked)
4390  * HttpTransact::RANGE_REQUESTED if all sub range entries are valid and
4391  * in order (remove the entries that not overlap the extent of cache copy)
4392  */
4393 void
parse_range_and_compare(MIMEField * field,int64_t content_length)4394 HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length)
4395 {
4396   int prev_good_range = -1;
4397   const char *value;
4398   int value_len;
4399   int n_values;
4400   int nr          = 0; // number of valid ranges, also index to range array.
4401   int not_satisfy = 0;
4402   HdrCsvIter csv;
4403   const char *s, *e, *tmp;
4404   RangeRecord *ranges = nullptr;
4405   int64_t start, end;
4406 
4407   ink_assert(field != nullptr && t_state.range_setup == HttpTransact::RANGE_NONE && t_state.ranges == nullptr);
4408 
4409   if (content_length <= 0) {
4410     return;
4411   }
4412 
4413   // ToDo: Can this really happen?
4414   if (content_length == INT64_MAX) {
4415     t_state.range_setup = HttpTransact::RANGE_NOT_HANDLED;
4416     return;
4417   }
4418 
4419   if (parse_range_done) {
4420     Debug("http_range", "parse_range already done, t_state.range_setup %d", t_state.range_setup);
4421     return;
4422   }
4423   parse_range_done = true;
4424 
4425   n_values = 0;
4426   value    = csv.get_first(field, &value_len);
4427   while (value) {
4428     ++n_values;
4429     value = csv.get_next(&value_len);
4430   }
4431 
4432   value = csv.get_first(field, &value_len);
4433   if (n_values <= 0 || ptr_len_ncmp(value, value_len, "bytes=", 6)) {
4434     return;
4435   }
4436 
4437   ranges = new RangeRecord[n_values];
4438   value += 6; // skip leading 'bytes='
4439   value_len -= 6;
4440 
4441   // assume range_in_cache
4442   t_state.range_in_cache = true;
4443 
4444   for (; value; value = csv.get_next(&value_len)) {
4445     if (!(tmp = static_cast<const char *>(memchr(value, '-', value_len)))) {
4446       t_state.range_setup = HttpTransact::RANGE_NONE;
4447       goto Lfaild;
4448     }
4449 
4450     // process start value
4451     s = value;
4452     e = tmp;
4453     // skip leading white spaces
4454     for (; s < e && ParseRules::is_ws(*s); ++s) {
4455       ;
4456     }
4457 
4458     if (s >= e) {
4459       start = -1;
4460     } else {
4461       for (start = 0; s < e && *s >= '0' && *s <= '9'; ++s) {
4462         // check the int64 overflow in case of high gcc with O3 option
4463         // thinking the start is always positive
4464         int64_t new_start = start * 10 + (*s - '0');
4465 
4466         if (new_start < start) { // Overflow
4467           t_state.range_setup = HttpTransact::RANGE_NONE;
4468           goto Lfaild;
4469         }
4470         start = new_start;
4471       }
4472       // skip last white spaces
4473       for (; s < e && ParseRules::is_ws(*s); ++s) {
4474         ;
4475       }
4476 
4477       if (s < e) {
4478         t_state.range_setup = HttpTransact::RANGE_NONE;
4479         goto Lfaild;
4480       }
4481     }
4482 
4483     // process end value
4484     s = tmp + 1;
4485     e = value + value_len;
4486     // skip leading white spaces
4487     for (; s < e && ParseRules::is_ws(*s); ++s) {
4488       ;
4489     }
4490 
4491     if (s >= e) {
4492       if (start < 0) {
4493         t_state.range_setup = HttpTransact::RANGE_NONE;
4494         goto Lfaild;
4495       } else if (start >= content_length) {
4496         not_satisfy++;
4497         continue;
4498       }
4499       end = content_length - 1;
4500     } else {
4501       for (end = 0; s < e && *s >= '0' && *s <= '9'; ++s) {
4502         // check the int64 overflow in case of high gcc with O3 option
4503         // thinking the start is always positive
4504         int64_t new_end = end * 10 + (*s - '0');
4505 
4506         if (new_end < end) { // Overflow
4507           t_state.range_setup = HttpTransact::RANGE_NONE;
4508           goto Lfaild;
4509         }
4510         end = new_end;
4511       }
4512       // skip last white spaces
4513       for (; s < e && ParseRules::is_ws(*s); ++s) {
4514         ;
4515       }
4516 
4517       if (s < e) {
4518         t_state.range_setup = HttpTransact::RANGE_NONE;
4519         goto Lfaild;
4520       }
4521 
4522       if (start < 0) {
4523         if (end >= content_length) {
4524           end = content_length;
4525         }
4526         start = content_length - end;
4527         end   = content_length - 1;
4528       } else if (start >= content_length && start <= end) {
4529         not_satisfy++;
4530         continue;
4531       }
4532 
4533       if (end >= content_length) {
4534         end = content_length - 1;
4535       }
4536     }
4537 
4538     if (start > end) {
4539       t_state.range_setup = HttpTransact::RANGE_NONE;
4540       goto Lfaild;
4541     }
4542 
4543     if (prev_good_range >= 0 && start <= ranges[prev_good_range]._end) {
4544       t_state.range_setup = HttpTransact::RANGE_NOT_HANDLED;
4545       goto Lfaild;
4546     }
4547 
4548     ink_assert(start >= 0 && end >= 0 && start < content_length && end < content_length);
4549 
4550     prev_good_range   = nr;
4551     ranges[nr]._start = start;
4552     ranges[nr]._end   = end;
4553     ++nr;
4554 
4555     if (!cache_sm.cache_read_vc->is_pread_capable() && cache_config_read_while_writer == 2) {
4556       // write in progress, check if request range not in cache yet
4557       HTTPInfo::FragOffset *frag_offset_tbl = t_state.cache_info.object_read->get_frag_table();
4558       int frag_offset_cnt                   = t_state.cache_info.object_read->get_frag_offset_count();
4559 
4560       if (!frag_offset_tbl || !frag_offset_cnt || (frag_offset_tbl[frag_offset_cnt - 1] < static_cast<uint64_t>(end))) {
4561         Debug("http_range", "request range in cache, end %" PRId64 ", frg_offset_cnt %d" PRId64, end, frag_offset_cnt);
4562         t_state.range_in_cache = false;
4563       }
4564     }
4565   }
4566 
4567   if (nr > 0) {
4568     t_state.range_setup      = HttpTransact::RANGE_REQUESTED;
4569     t_state.ranges           = ranges;
4570     t_state.num_range_fields = nr;
4571     return;
4572   }
4573 
4574   if (not_satisfy) {
4575     t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
4576   }
4577 
4578 Lfaild:
4579   t_state.range_in_cache   = false;
4580   t_state.num_range_fields = -1;
4581   delete[] ranges;
4582   return;
4583 }
4584 
4585 void
calculate_output_cl(int64_t num_chars_for_ct,int64_t num_chars_for_cl)4586 HttpSM::calculate_output_cl(int64_t num_chars_for_ct, int64_t num_chars_for_cl)
4587 {
4588   if (t_state.range_setup != HttpTransact::RANGE_REQUESTED && t_state.range_setup != HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED) {
4589     return;
4590   }
4591 
4592   ink_assert(t_state.ranges);
4593 
4594   if (t_state.num_range_fields == 1) {
4595     t_state.range_output_cl = t_state.ranges[0]._end - t_state.ranges[0]._start + 1;
4596   } else {
4597     for (int i = 0; i < t_state.num_range_fields; i++) {
4598       if (t_state.ranges[i]._start >= 0) {
4599         t_state.range_output_cl += boundary_size;
4600         t_state.range_output_cl += sub_header_size + num_chars_for_ct;
4601         t_state.range_output_cl +=
4602           num_chars_for_int(t_state.ranges[i]._start) + num_chars_for_int(t_state.ranges[i]._end) + num_chars_for_cl + 2;
4603         t_state.range_output_cl += t_state.ranges[i]._end - t_state.ranges[i]._start + 1;
4604         t_state.range_output_cl += 2;
4605       }
4606     }
4607 
4608     t_state.range_output_cl += boundary_size + 2;
4609   }
4610 
4611   Debug("http_range", "Pre-calculated Content-Length for Range response is %" PRId64, t_state.range_output_cl);
4612 }
4613 
4614 void
do_range_parse(MIMEField * range_field)4615 HttpSM::do_range_parse(MIMEField *range_field)
4616 {
4617   int num_chars_for_ct = 0;
4618   t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &num_chars_for_ct);
4619 
4620   int64_t content_length   = t_state.cache_info.object_read->object_size_get();
4621   int64_t num_chars_for_cl = num_chars_for_int(content_length);
4622 
4623   parse_range_and_compare(range_field, content_length);
4624   calculate_output_cl(num_chars_for_ct, num_chars_for_cl);
4625 }
4626 
4627 // this function looks for any Range: headers, parses them and either
4628 // sets up a transform processor to handle the request OR defers to the
4629 // HttpTunnel
4630 void
do_range_setup_if_necessary()4631 HttpSM::do_range_setup_if_necessary()
4632 {
4633   MIMEField *field;
4634 
4635   ink_assert(t_state.cache_info.object_read != nullptr);
4636 
4637   field = t_state.hdr_info.client_request.field_find(MIME_FIELD_RANGE, MIME_LEN_RANGE);
4638   ink_assert(field != nullptr);
4639 
4640   t_state.range_setup = HttpTransact::RANGE_NONE;
4641 
4642   if (t_state.method == HTTP_WKSIDX_GET && t_state.hdr_info.client_request.version_get() == HTTP_1_1) {
4643     do_range_parse(field);
4644 
4645     if (t_state.range_setup == HttpTransact::RANGE_REQUESTED) {
4646       bool do_transform = false;
4647 
4648       if (!t_state.range_in_cache) {
4649         Debug("http_range", "range can't be satisfied from cache, force origin request");
4650         t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_MISS;
4651         return;
4652       }
4653 
4654       if (t_state.num_range_fields > 1) {
4655         if (0 == t_state.txn_conf->allow_multi_range) {
4656           t_state.range_setup = HttpTransact::RANGE_NONE;                                 // No Range required (not allowed)
4657           t_state.hdr_info.client_request.field_delete(MIME_FIELD_RANGE, MIME_LEN_RANGE); // ... and nuke the Range header too
4658           t_state.num_range_fields = 0;
4659         } else if (1 == t_state.txn_conf->allow_multi_range) {
4660           do_transform = true;
4661         } else {
4662           t_state.num_range_fields = 0;
4663           t_state.range_setup      = HttpTransact::RANGE_NOT_SATISFIABLE;
4664         }
4665       } else {
4666         if (cache_sm.cache_read_vc->is_pread_capable()) {
4667           // If only one range entry and pread is capable, no need transform range
4668           t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED;
4669         } else {
4670           do_transform = true;
4671         }
4672       }
4673 
4674       // We have to do the transform on (allowed) multi-range request, *or* if the VC is not pread capable
4675       if (do_transform) {
4676         if (api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == nullptr) {
4677           int field_content_type_len = -1;
4678           const char *content_type   = t_state.cache_info.object_read->response_get()->value_get(
4679             MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &field_content_type_len);
4680 
4681           Debug("http_trans", "Unable to accelerate range request, fallback to transform");
4682 
4683           // create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges)
4684           INKVConnInternal *range_trans = transformProcessor.range_transform(
4685             mutex.get(), t_state.ranges, t_state.num_range_fields, &t_state.hdr_info.transform_response, content_type,
4686             field_content_type_len, t_state.cache_info.object_read->object_size_get());
4687           api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans);
4688         } else {
4689           // ToDo: Do we do something here? The theory is that multiple transforms do not behave well with
4690           // the range transform needed here.
4691         }
4692       }
4693     }
4694   }
4695 }
4696 
4697 void
do_cache_lookup_and_read()4698 HttpSM::do_cache_lookup_and_read()
4699 {
4700   // TODO decide whether to uncomment after finish testing redirect
4701   // ink_assert(server_session == NULL);
4702   ink_assert(pending_action.is_empty());
4703 
4704   HTTP_INCREMENT_DYN_STAT(http_cache_lookups_stat);
4705 
4706   milestones[TS_MILESTONE_CACHE_OPEN_READ_BEGIN] = Thread::get_hrtime();
4707   t_state.cache_lookup_result                    = HttpTransact::CACHE_LOOKUP_NONE;
4708   t_state.cache_info.lookup_count++;
4709   // YTS Team, yamsat Plugin
4710   // Changed the lookup_url to c_url which enables even
4711   // the new redirect url to perform a CACHE_LOOKUP
4712   URL *c_url;
4713   if (t_state.redirect_info.redirect_in_process && !t_state.txn_conf->redirect_use_orig_cache_key) {
4714     c_url = t_state.hdr_info.client_request.url_get();
4715   } else {
4716     c_url = t_state.cache_info.lookup_url;
4717   }
4718 
4719   SMDebug("http_seq", "[HttpSM::do_cache_lookup_and_read] [%" PRId64 "] Issuing cache lookup for URL %s", sm_id,
4720           c_url->string_get(&t_state.arena));
4721 
4722   HttpCacheKey key;
4723   Cache::generate_key(&key, c_url, t_state.txn_conf->cache_generation_number);
4724 
4725   pending_action = cache_sm.open_read(
4726     &key, c_url, &t_state.hdr_info.client_request, t_state.txn_conf,
4727     static_cast<time_t>((t_state.cache_control.pin_in_cache_for < 0) ? 0 : t_state.cache_control.pin_in_cache_for));
4728   //
4729   // pin_in_cache value is an open_write parameter.
4730   // It is passed in open_read to allow the cluster to
4731   // optimize the typical open_read/open_read failed/open_write
4732   // sequence.
4733   //
4734   REMEMBER((long)pending_action.get(), reentrancy_count);
4735 
4736   return;
4737 }
4738 
4739 void
do_cache_delete_all_alts(Continuation * cont)4740 HttpSM::do_cache_delete_all_alts(Continuation *cont)
4741 {
4742   // Do not delete a non-existent object.
4743   ink_assert(t_state.cache_info.object_read);
4744 
4745   SMDebug("http_seq", "[HttpSM::do_cache_delete_all_alts] Issuing cache delete for %s",
4746           t_state.cache_info.lookup_url->string_get_ref());
4747 
4748   HttpCacheKey key;
4749   Cache::generate_key(&key, t_state.cache_info.lookup_url, t_state.txn_conf->cache_generation_number);
4750   pending_action = cacheProcessor.remove(cont, &key);
4751 
4752   return;
4753 }
4754 
4755 inline void
do_cache_prepare_write()4756 HttpSM::do_cache_prepare_write()
4757 {
4758   milestones[TS_MILESTONE_CACHE_OPEN_WRITE_BEGIN] = Thread::get_hrtime();
4759   do_cache_prepare_action(&cache_sm, t_state.cache_info.object_read, true);
4760 }
4761 
4762 inline void
do_cache_prepare_write_transform()4763 HttpSM::do_cache_prepare_write_transform()
4764 {
4765   if (cache_sm.cache_write_vc != nullptr || tunnel.has_cache_writer()) {
4766     do_cache_prepare_action(&transform_cache_sm, nullptr, false, true);
4767   } else {
4768     do_cache_prepare_action(&transform_cache_sm, nullptr, false);
4769   }
4770 }
4771 
4772 void
do_cache_prepare_update()4773 HttpSM::do_cache_prepare_update()
4774 {
4775   if (t_state.cache_info.object_read != nullptr && t_state.cache_info.object_read->valid() &&
4776       t_state.cache_info.object_store.valid() && t_state.cache_info.object_store.response_get() != nullptr &&
4777       t_state.cache_info.object_store.response_get()->valid() &&
4778       t_state.hdr_info.client_request.method_get_wksidx() == HTTP_WKSIDX_GET) {
4779     t_state.cache_info.object_store.request_set(t_state.cache_info.object_read->request_get());
4780     // t_state.cache_info.object_read = NULL;
4781     // cache_sm.close_read();
4782 
4783     t_state.transact_return_point = HttpTransact::HandleUpdateCachedObject;
4784     ink_assert(cache_sm.cache_write_vc == nullptr);
4785     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_cache_open_write);
4786     // don't retry read for update
4787     do_cache_prepare_action(&cache_sm, t_state.cache_info.object_read, false);
4788   } else {
4789     t_state.api_modifiable_cached_resp = false;
4790     call_transact_and_set_next_state(HttpTransact::HandleApiErrorJump);
4791   }
4792 }
4793 
4794 void
do_cache_prepare_action(HttpCacheSM * c_sm,CacheHTTPInfo * object_read_info,bool retry,bool allow_multiple)4795 HttpSM::do_cache_prepare_action(HttpCacheSM *c_sm, CacheHTTPInfo *object_read_info, bool retry, bool allow_multiple)
4796 {
4797   URL *o_url, *s_url;
4798   bool restore_client_request = false;
4799 
4800   ink_assert(pending_action.is_empty());
4801 
4802   if (t_state.redirect_info.redirect_in_process) {
4803     o_url = &(t_state.redirect_info.original_url);
4804     ink_assert(o_url->valid());
4805     restore_client_request = true;
4806     s_url                  = o_url;
4807   } else {
4808     o_url = &(t_state.cache_info.original_url);
4809     if (o_url->valid()) {
4810       s_url = o_url;
4811     } else {
4812       s_url = t_state.cache_info.lookup_url;
4813     }
4814   }
4815 
4816   // modify client request to make it have the url we are going to
4817   // store into the cache
4818   if (restore_client_request) {
4819     URL *c_url = t_state.hdr_info.client_request.url_get();
4820     s_url->copy(c_url);
4821   }
4822 
4823   ink_assert(s_url != nullptr && s_url->valid());
4824   SMDebug("http_cache_write", "[%" PRId64 "] writing to cache with URL %s", sm_id, s_url->string_get(&t_state.arena));
4825 
4826   HttpCacheKey key;
4827   Cache::generate_key(&key, s_url, t_state.txn_conf->cache_generation_number);
4828 
4829   pending_action =
4830     c_sm->open_write(&key, s_url, &t_state.hdr_info.client_request, object_read_info,
4831                      static_cast<time_t>((t_state.cache_control.pin_in_cache_for < 0) ? 0 : t_state.cache_control.pin_in_cache_for),
4832                      retry, allow_multiple);
4833 }
4834 
4835 void
send_origin_throttled_response()4836 HttpSM::send_origin_throttled_response()
4837 {
4838   // if the request is to a parent proxy, do not reset
4839   // t_state.current.attempts so that another parent or
4840   // NextHop may be tried.
4841   if (t_state.current.request_to != HttpTransact::PARENT_PROXY) {
4842     t_state.current.attempts = t_state.txn_conf->connect_attempts_max_retries;
4843   }
4844   t_state.current.state = HttpTransact::OUTBOUND_CONGESTION;
4845   call_transact_and_set_next_state(HttpTransact::HandleResponse);
4846 }
4847 
4848 static void
set_tls_options(NetVCOptions & opt,const OverridableHttpConfigParams * txn_conf)4849 set_tls_options(NetVCOptions &opt, const OverridableHttpConfigParams *txn_conf)
4850 {
4851   char *verify_server = nullptr;
4852   if (txn_conf->ssl_client_verify_server_policy == nullptr) {
4853     opt.verifyServerPolicy = YamlSNIConfig::Policy::UNSET;
4854   } else {
4855     verify_server = txn_conf->ssl_client_verify_server_policy;
4856     if (strcmp(verify_server, "DISABLED") == 0) {
4857       opt.verifyServerPolicy = YamlSNIConfig::Policy::DISABLED;
4858     } else if (strcmp(verify_server, "PERMISSIVE") == 0) {
4859       opt.verifyServerPolicy = YamlSNIConfig::Policy::PERMISSIVE;
4860     } else if (strcmp(verify_server, "ENFORCED") == 0) {
4861       opt.verifyServerPolicy = YamlSNIConfig::Policy::ENFORCED;
4862     } else {
4863       Warning("%s is invalid for proxy.config.ssl.client.verify.server.policy.  Should be one of DISABLED, PERMISSIVE, or ENFORCED",
4864               verify_server);
4865       opt.verifyServerPolicy = YamlSNIConfig::Policy::UNSET;
4866     }
4867   }
4868   if (txn_conf->ssl_client_verify_server_properties == nullptr) {
4869     opt.verifyServerProperties = YamlSNIConfig::Property::UNSET;
4870   } else {
4871     verify_server = txn_conf->ssl_client_verify_server_properties;
4872     if (strcmp(verify_server, "SIGNATURE") == 0) {
4873       opt.verifyServerProperties = YamlSNIConfig::Property::SIGNATURE_MASK;
4874     } else if (strcmp(verify_server, "NAME") == 0) {
4875       opt.verifyServerProperties = YamlSNIConfig::Property::NAME_MASK;
4876     } else if (strcmp(verify_server, "ALL") == 0) {
4877       opt.verifyServerProperties = YamlSNIConfig::Property::ALL_MASK;
4878     } else if (strcmp(verify_server, "NONE") == 0) {
4879       opt.verifyServerProperties = YamlSNIConfig::Property::NONE;
4880     } else {
4881       Warning("%s is invalid for proxy.config.ssl.client.verify.server.properties.  Should be one of SIGNATURE, NAME, or ALL",
4882               verify_server);
4883       opt.verifyServerProperties = YamlSNIConfig::Property::NONE;
4884     }
4885   }
4886 }
4887 
4888 std::string_view
get_outbound_cert() const4889 HttpSM::get_outbound_cert() const
4890 {
4891   const char *cert_name = t_state.txn_conf->ssl_client_cert_filename;
4892   if (cert_name == nullptr) {
4893     cert_name = "";
4894   }
4895   return std::string_view(cert_name);
4896 }
4897 
4898 std::string_view
get_outbound_sni() const4899 HttpSM::get_outbound_sni() const
4900 {
4901   using namespace ts::literals;
4902   ts::TextView zret;
4903   ts::TextView policy{t_state.txn_conf->ssl_client_sni_policy, ts::TextView::npos};
4904   if (policy.empty() || !strcmp(policy, "host"_tv)) {
4905     // By default the host header field value is used for the SNI.
4906     int len;
4907     char const *ptr = t_state.hdr_info.server_request.host_get(&len);
4908     zret.assign(ptr, len);
4909   } else if (ua_txn && !strcmp(policy, "server_name"_tv)) {
4910     zret.assign(ua_txn->get_netvc()->get_server_name(), ts::TextView::npos);
4911   } else if (policy.front() == '@') { // guaranteed non-empty from previous clause
4912     zret = policy.remove_prefix(1);
4913   } else {
4914     // If other is specified, like "remap" and "verify_with_name_source", the remapped origin name is used for the SNI value
4915     zret.assign(t_state.server_info.name, ts::TextView::npos);
4916   }
4917   return zret;
4918 }
4919 
4920 //////////////////////////////////////////////////////////////////////////
4921 //
4922 //  HttpSM::do_http_server_open()
4923 //
4924 //////////////////////////////////////////////////////////////////////////
4925 void
do_http_server_open(bool raw)4926 HttpSM::do_http_server_open(bool raw)
4927 {
4928   int ip_family = t_state.current.server->dst_addr.sa.sa_family;
4929   auto fam_name = ats_ip_family_name(ip_family);
4930   SMDebug("http_track", "entered inside do_http_server_open ][%.*s]", static_cast<int>(fam_name.size()), fam_name.data());
4931 
4932   NetVConnection *vc = ua_txn->get_netvc();
4933   ink_release_assert(vc && vc->thread == this_ethread());
4934   pending_action = nullptr;
4935 
4936   // Clean up connection tracking info if any. Need to do it now so the selected group
4937   // is consistent with the actual upstream in case of retry.
4938   t_state.outbound_conn_track_state.clear();
4939 
4940   // ua_entry can be null if a scheduled update is also a reverse proxy
4941   // request. Added REVPROXY to the assert below, and then changed checks
4942   // to be based on ua_txn != NULL instead of req_flavor value.
4943   ink_assert(ua_entry != nullptr || t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE ||
4944              t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY);
4945 
4946   ink_assert(pending_action.is_empty());
4947   ink_assert(t_state.current.server->dst_addr.port() != 0);
4948 
4949   char addrbuf[INET6_ADDRPORTSTRLEN];
4950   SMDebug("http", "[%" PRId64 "] open connection to %s: %s", sm_id, t_state.current.server->name,
4951           ats_ip_nptop(&t_state.current.server->dst_addr.sa, addrbuf, sizeof(addrbuf)));
4952 
4953   if (plugin_tunnel) {
4954     PluginVCCore *t           = plugin_tunnel;
4955     plugin_tunnel             = nullptr;
4956     Action *pvc_action_handle = t->connect_re(this);
4957 
4958     // This connect call is always reentrant
4959     ink_release_assert(pvc_action_handle == ACTION_RESULT_DONE);
4960     return;
4961   }
4962 
4963   SMDebug("http_seq", "[HttpSM::do_http_server_open] Sending request to server");
4964 
4965   milestones[TS_MILESTONE_SERVER_CONNECT] = Thread::get_hrtime();
4966   if (milestones[TS_MILESTONE_SERVER_FIRST_CONNECT] == 0) {
4967     milestones[TS_MILESTONE_SERVER_FIRST_CONNECT] = milestones[TS_MILESTONE_SERVER_CONNECT];
4968   }
4969 
4970   // Check for remap rule. If so, only apply ip_allow filter if it is activated (ip_allow_check_enabled_p set).
4971   // Otherwise, if no remap rule is defined, apply the ip_allow filter.
4972   if (!t_state.url_remap_success || t_state.url_map.getMapping()->ip_allow_check_enabled_p) {
4973     // Method allowed on dest IP address check
4974     sockaddr *server_ip    = &t_state.current.server->dst_addr.sa;
4975     IpAllow::ACL acl       = IpAllow::match(server_ip, IpAllow::DST_ADDR);
4976     bool deny_request      = false; // default is fail open.
4977     int method             = t_state.hdr_info.server_request.method_get_wksidx();
4978     int method_str_len     = 0;
4979     const char *method_str = nullptr;
4980 
4981     if (acl.isValid()) {
4982       if (acl.isDenyAll()) {
4983         deny_request = true;
4984       } else if (!acl.isAllowAll()) {
4985         if (method != -1) {
4986           deny_request = !acl.isMethodAllowed(method);
4987         } else {
4988           method_str   = t_state.hdr_info.server_request.method_get(&method_str_len);
4989           deny_request = !acl.isNonstandardMethodAllowed(std::string_view(method_str, method_str_len));
4990         }
4991       }
4992     }
4993 
4994     if (deny_request) {
4995       if (is_debug_tag_set("ip-allow")) {
4996         ip_text_buffer ipb;
4997         if (method != -1) {
4998           method_str     = hdrtoken_index_to_wks(method);
4999           method_str_len = strlen(method_str);
5000         } else if (!method_str) {
5001           method_str = t_state.hdr_info.client_request.method_get(&method_str_len);
5002         }
5003         Warning("server '%s' prohibited by ip-allow policy at line %d", ats_ip_ntop(server_ip, ipb, sizeof(ipb)),
5004                 acl.source_line());
5005         Debug("ip-allow", "Line %d denial for '%.*s' from %s", acl.source_line(), method_str_len, method_str,
5006               ats_ip_ntop(server_ip, ipb, sizeof(ipb)));
5007       }
5008       t_state.current.attempts = t_state.txn_conf->connect_attempts_max_retries; // prevent any more retries with this IP
5009       call_transact_and_set_next_state(HttpTransact::Forbidden);
5010       return;
5011     }
5012 
5013     if (HttpTransact::is_server_negative_cached(&t_state) == true &&
5014         t_state.txn_conf->connect_attempts_max_retries_dead_server <= 0) {
5015       call_transact_and_set_next_state(HttpTransact::OriginDead);
5016       return;
5017     }
5018   }
5019 
5020   // Check for self loop.
5021   if (HttpTransact::will_this_request_self_loop(&t_state)) {
5022     call_transact_and_set_next_state(HttpTransact::SelfLoop);
5023     return;
5024   }
5025 
5026   // If this is not a raw connection, we try to get a session from the
5027   //  shared session pool.  Raw connections are for SSLs tunnel and
5028   //  require a new connection
5029   //
5030 
5031   // This problem with POST requests is a bug.  Because of the issue of the
5032   // race with us sending a request after server has closed but before the FIN
5033   // gets to us, we should open a new connection for POST.  I believe TS used
5034   // to do this but as far I can tell the code that prevented keep-alive if
5035   // there is a request body has been removed.
5036 
5037   // If we are sending authorizations headers, mark the connection private
5038   //
5039   // We do this here because it means that we will not waste a connection from the pool if we already
5040   // know that the session will be private. This is overridable meaning that if a plugin later decides
5041   // it shouldn't be private it can still be returned to a shared pool.
5042   //
5043   if (t_state.txn_conf->auth_server_session_private == 1 &&
5044       t_state.hdr_info.server_request.presence(MIME_PRESENCE_AUTHORIZATION | MIME_PRESENCE_PROXY_AUTHORIZATION |
5045                                                MIME_PRESENCE_WWW_AUTHENTICATE)) {
5046     SMDebug("http_ss_auth", "Setting server session to private for authorization header");
5047     will_be_private_ss = true;
5048   }
5049 
5050   if (t_state.method == HTTP_WKSIDX_POST || t_state.method == HTTP_WKSIDX_PUT) {
5051     // don't share the session if keep-alive for post is not on
5052     if (t_state.txn_conf->keep_alive_post_out == 0) {
5053       SMDebug("http_ss", "Setting server session to private because of keep-alive post out");
5054       will_be_private_ss = true;
5055     }
5056   }
5057 
5058   // If there is already an attached server session mark it as private.
5059   if (server_session != nullptr && will_be_private_ss) {
5060     server_session->set_private();
5061   }
5062 
5063   if ((raw == false) && TS_SERVER_SESSION_SHARING_MATCH_NONE != t_state.txn_conf->server_session_sharing_match &&
5064       (t_state.txn_conf->keep_alive_post_out == 1 || t_state.hdr_info.request_content_length <= 0) && !is_private() &&
5065       ua_txn != nullptr) {
5066     HSMresult_t shared_result;
5067     shared_result = httpSessionManager.acquire_session(this,                                 // state machine
5068                                                        &t_state.current.server->dst_addr.sa, // ip + port
5069                                                        t_state.current.server->name,         // hostname
5070                                                        ua_txn,                               // has ptr to bound ua sessions
5071                                                        this                                  // sm
5072     );
5073 
5074     switch (shared_result) {
5075     case HSM_DONE:
5076       hsm_release_assert(server_session != nullptr);
5077       handle_http_server_open();
5078       return;
5079     case HSM_NOT_FOUND:
5080       hsm_release_assert(server_session == nullptr);
5081       break;
5082     case HSM_RETRY:
5083       //  Could not get shared pool lock
5084       //   FIX: should retry lock
5085       break;
5086     default:
5087       hsm_release_assert(0);
5088     }
5089   }
5090   // Avoid a problem where server session sharing is disabled and we have keep-alive, we are trying to open a new server
5091   // session when we already have an attached server session.
5092   else if ((TS_SERVER_SESSION_SHARING_MATCH_NONE == t_state.txn_conf->server_session_sharing_match || is_private()) &&
5093            (ua_txn != nullptr)) {
5094     PoolableSession *existing_ss = ua_txn->get_server_session();
5095 
5096     if (existing_ss) {
5097       // [amc] Not sure if this is the best option, but we don't get here unless session sharing is disabled
5098       // so there's no point in further checking on the match or pool values. But why check anything? The
5099       // client has already exchanged a request with this specific origin server and has sent another one
5100       // shouldn't we just automatically keep the association?
5101       if (ats_ip_addr_port_eq(existing_ss->get_remote_addr(), &t_state.current.server->dst_addr.sa)) {
5102         ua_txn->attach_server_session(nullptr);
5103         existing_ss->set_active();
5104         this->attach_server_session(existing_ss);
5105         hsm_release_assert(server_session != nullptr);
5106         handle_http_server_open();
5107         return;
5108       } else {
5109         // As this is in the non-sharing configuration, we want to close
5110         // the existing connection and call connect_re to get a new one
5111         existing_ss->get_netvc()->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out));
5112         existing_ss->release(nullptr);
5113         ua_txn->attach_server_session(nullptr);
5114       }
5115     }
5116   }
5117   // Otherwise, we release the existing connection and call connect_re
5118   // to get a new one.
5119   // ua_txn is null when t_state.req_flavor == REQ_FLAVOR_SCHEDULED_UPDATE
5120   else if (ua_txn != nullptr) {
5121     PoolableSession *existing_ss = ua_txn->get_server_session();
5122     if (existing_ss) {
5123       existing_ss->get_netvc()->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out));
5124       existing_ss->release(nullptr);
5125       ua_txn->attach_server_session(nullptr);
5126     }
5127   }
5128   // Check to see if we have reached the max number of connections.
5129   // Atomically read the current number of connections and check to see
5130   // if we have gone above the max allowed.
5131   if (t_state.http_config_param->server_max_connections > 0) {
5132     int64_t sum;
5133 
5134     HTTP_READ_GLOBAL_DYN_SUM(http_current_server_connections_stat, sum);
5135 
5136     // Note that there is a potential race condition here where
5137     // the value of the http_current_server_connections_stat gets changed
5138     // between the statement above and the check below.
5139     // If this happens, we might go over the max by 1 but this is ok.
5140     if (sum >= t_state.http_config_param->server_max_connections) {
5141       httpSessionManager.purge_keepalives();
5142       // Eventually may want to have a queue as the origin_max_connection does to allow for a combination
5143       // of retries and errors.  But at this point, we are just going to allow the error case.
5144       t_state.current.state = HttpTransact::CONNECTION_ERROR;
5145       call_transact_and_set_next_state(HttpTransact::HandleResponse);
5146       return;
5147     }
5148   }
5149 
5150   // See if the outbound connection tracker data is needed. If so, get it here for consistency.
5151   if (t_state.txn_conf->outbound_conntrack.max > 0 || t_state.txn_conf->outbound_conntrack.min > 0) {
5152     t_state.outbound_conn_track_state = OutboundConnTrack::obtain(
5153       t_state.txn_conf->outbound_conntrack, std::string_view{t_state.current.server->name}, t_state.current.server->dst_addr);
5154   }
5155 
5156   // Check to see if we have reached the max number of connections on this upstream host.
5157   if (t_state.txn_conf->outbound_conntrack.max > 0) {
5158     auto &ct_state = t_state.outbound_conn_track_state;
5159     auto ccount    = ct_state.reserve();
5160     if (ccount > t_state.txn_conf->outbound_conntrack.max) {
5161       ct_state.release();
5162 
5163       ink_assert(pending_action.is_empty()); // in case of reschedule must not have already pending.
5164 
5165       // If the queue is disabled, reschedule.
5166       if (t_state.http_config_param->outbound_conntrack.queue_size < 0) {
5167         ct_state.enqueue();
5168         ct_state.rescheduled();
5169         pending_action =
5170           eventProcessor.schedule_in(this, HRTIME_MSECONDS(t_state.http_config_param->outbound_conntrack.queue_delay.count()));
5171       } else if (t_state.http_config_param->outbound_conntrack.queue_size > 0) { // queue enabled, check for a slot
5172         auto wcount = ct_state.enqueue();
5173         if (wcount < t_state.http_config_param->outbound_conntrack.queue_size) {
5174           ct_state.rescheduled();
5175           SMDebug("http", "%s", lbw().print("[{}] queued for {}\0", sm_id, t_state.current.server->dst_addr).data());
5176           pending_action =
5177             eventProcessor.schedule_in(this, HRTIME_MSECONDS(t_state.http_config_param->outbound_conntrack.queue_delay.count()));
5178         } else {              // the queue is full
5179           ct_state.dequeue(); // release the queue slot
5180           ct_state.blocked(); // note the blockage.
5181           HTTP_INCREMENT_DYN_STAT(http_origin_connections_throttled_stat);
5182           send_origin_throttled_response();
5183         }
5184       } else { // queue size is 0, always block.
5185         ct_state.blocked();
5186         HTTP_INCREMENT_DYN_STAT(http_origin_connections_throttled_stat);
5187         ct_state.Warn_Blocked(&t_state.txn_conf->outbound_conntrack, sm_id, ccount - 1, &t_state.current.server->dst_addr.sa,
5188                               debug_on && is_debug_tag_set("http") ? "http" : nullptr);
5189         send_origin_throttled_response();
5190       }
5191 
5192       return;
5193     } else {
5194       ct_state.Note_Unblocked(&t_state.txn_conf->outbound_conntrack, ccount, &t_state.current.server->dst_addr.sa);
5195     }
5196 
5197     ct_state.update_max_count(ccount);
5198   }
5199 
5200   // We did not manage to get an existing session and need to open a new connection
5201   NetVCOptions opt;
5202   opt.f_blocking_connect = false;
5203   opt.set_sock_param(t_state.txn_conf->sock_recv_buffer_size_out, t_state.txn_conf->sock_send_buffer_size_out,
5204                      t_state.txn_conf->sock_option_flag_out, t_state.txn_conf->sock_packet_mark_out,
5205                      t_state.txn_conf->sock_packet_tos_out);
5206 
5207   set_tls_options(opt, t_state.txn_conf);
5208 
5209   opt.ip_family = ip_family;
5210 
5211   int scheme_to_use = t_state.scheme; // get initial scheme
5212   bool tls_upstream = scheme_to_use == URL_WKSIDX_HTTPS;
5213   if (ua_txn) {
5214     SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(ua_txn->get_netvc());
5215     if (ssl_vc && raw) {
5216       tls_upstream = ssl_vc->upstream_tls();
5217 
5218       // ALPN on TLS Partial Blind Tunnel - set negotiated ALPN id
5219       if (ssl_vc->tunnel_type() == SNIRoutingType::PARTIAL_BLIND) {
5220         int pid = ssl_vc->get_negotiated_protocol_id();
5221         if (pid != SessionProtocolNameRegistry::INVALID) {
5222           opt.alpn_protos = SessionProtocolNameRegistry::convert_openssl_alpn_wire_format(pid);
5223         }
5224       }
5225     }
5226     opt.local_port = ua_txn->get_outbound_port();
5227 
5228     const IpAddr &outbound_ip = AF_INET6 == opt.ip_family ? ua_txn->get_outbound_ip6() : ua_txn->get_outbound_ip4();
5229     if (outbound_ip.isValid()) {
5230       opt.addr_binding = NetVCOptions::INTF_ADDR;
5231       opt.local_ip     = outbound_ip;
5232     } else if (ua_txn->is_outbound_transparent()) {
5233       opt.addr_binding = NetVCOptions::FOREIGN_ADDR;
5234       opt.local_ip     = t_state.client_info.src_addr;
5235       /* If the connection is server side transparent, we can bind to the
5236          port that the client chose instead of randomly assigning one at
5237          the proxy.  This is controlled by the 'use_client_source_port'
5238          configuration parameter.
5239       */
5240 
5241       NetVConnection *client_vc = ua_txn->get_netvc();
5242       if (t_state.http_config_param->use_client_source_port && nullptr != client_vc) {
5243         opt.local_port = client_vc->get_remote_port();
5244       }
5245     }
5246   }
5247 
5248   if (!t_state.is_websocket) { // if not websocket, then get scheme from server request
5249     int new_scheme_to_use = t_state.hdr_info.server_request.url_get()->scheme_get_wksidx();
5250     // if the server_request url scheme was never set, try the client_request
5251     if (new_scheme_to_use < 0) {
5252       new_scheme_to_use = t_state.hdr_info.client_request.url_get()->scheme_get_wksidx();
5253     }
5254     if (new_scheme_to_use >= 0) { // found a new scheme, use it
5255       scheme_to_use = new_scheme_to_use;
5256     }
5257     if (!raw || !tls_upstream) {
5258       tls_upstream = scheme_to_use == URL_WKSIDX_HTTPS;
5259     }
5260   }
5261 
5262   // draft-stenberg-httpbis-tcp recommends only enabling TFO on idempotent methods or
5263   // those with intervening protocol layers (eg. TLS).
5264 
5265   if (tls_upstream || HttpTransactHeaders::is_method_idempotent(t_state.method)) {
5266     opt.f_tcp_fastopen = (t_state.txn_conf->sock_option_flag_out & NetVCOptions::SOCK_OPT_TCP_FAST_OPEN);
5267   }
5268 
5269   opt.set_ssl_client_cert_name(t_state.txn_conf->ssl_client_cert_filename);
5270   opt.ssl_client_private_key_name = t_state.txn_conf->ssl_client_private_key_filename;
5271   opt.ssl_client_ca_cert_name     = t_state.txn_conf->ssl_client_ca_cert_filename;
5272 
5273   if (tls_upstream) {
5274     SMDebug("http", "calling sslNetProcessor.connect_re");
5275 
5276     std::string_view sni_name = this->get_outbound_sni();
5277     if (sni_name.length() > 0) {
5278       opt.set_sni_servername(sni_name.data(), sni_name.length());
5279     }
5280     int len = 0;
5281     if (t_state.txn_conf->ssl_client_sni_policy != nullptr &&
5282         !strcmp(t_state.txn_conf->ssl_client_sni_policy, "verify_with_name_source")) {
5283       // also set sni_hostname with host header from server request in this policy
5284       const char *host = t_state.hdr_info.server_request.host_get(&len);
5285       if (host && len > 0) {
5286         opt.set_sni_hostname(host, len);
5287       }
5288     }
5289     if (t_state.server_info.name) {
5290       opt.set_ssl_servername(t_state.server_info.name);
5291     }
5292 
5293     pending_action = sslNetProcessor.connect_re(this,                                 // state machine
5294                                                 &t_state.current.server->dst_addr.sa, // addr + port
5295                                                 &opt);
5296   } else {
5297     SMDebug("http", "calling netProcessor.connect_re");
5298     pending_action = netProcessor.connect_re(this,                                 // state machine
5299                                              &t_state.current.server->dst_addr.sa, // addr + port
5300                                              &opt);
5301   }
5302 
5303   return;
5304 }
5305 
5306 int
do_api_callout_internal()5307 HttpSM::do_api_callout_internal()
5308 {
5309   switch (t_state.api_next_action) {
5310   case HttpTransact::SM_ACTION_API_SM_START:
5311     cur_hook_id = TS_HTTP_TXN_START_HOOK;
5312     break;
5313   case HttpTransact::SM_ACTION_API_PRE_REMAP:
5314     cur_hook_id = TS_HTTP_PRE_REMAP_HOOK;
5315     break;
5316   case HttpTransact::SM_ACTION_API_POST_REMAP:
5317     cur_hook_id = TS_HTTP_POST_REMAP_HOOK;
5318     break;
5319   case HttpTransact::SM_ACTION_API_READ_REQUEST_HDR:
5320     cur_hook_id = TS_HTTP_READ_REQUEST_HDR_HOOK;
5321     break;
5322   case HttpTransact::SM_ACTION_REQUEST_BUFFER_READ_COMPLETE:
5323     cur_hook_id = TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK;
5324     break;
5325   case HttpTransact::SM_ACTION_API_OS_DNS:
5326     cur_hook_id = TS_HTTP_OS_DNS_HOOK;
5327     break;
5328   case HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR:
5329     cur_hook_id = TS_HTTP_SEND_REQUEST_HDR_HOOK;
5330     break;
5331   case HttpTransact::SM_ACTION_API_READ_CACHE_HDR:
5332     cur_hook_id = TS_HTTP_READ_CACHE_HDR_HOOK;
5333     break;
5334   case HttpTransact::SM_ACTION_API_CACHE_LOOKUP_COMPLETE:
5335     cur_hook_id = TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK;
5336     break;
5337   case HttpTransact::SM_ACTION_API_READ_RESPONSE_HDR:
5338     cur_hook_id = TS_HTTP_READ_RESPONSE_HDR_HOOK;
5339     break;
5340   case HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR:
5341     cur_hook_id                             = TS_HTTP_SEND_RESPONSE_HDR_HOOK;
5342     milestones[TS_MILESTONE_UA_BEGIN_WRITE] = Thread::get_hrtime();
5343     break;
5344   case HttpTransact::SM_ACTION_API_SM_SHUTDOWN:
5345     if (callout_state == HTTP_API_IN_CALLOUT || callout_state == HTTP_API_DEFERED_SERVER_ERROR) {
5346       callout_state = HTTP_API_DEFERED_CLOSE;
5347       return 0;
5348     } else {
5349       cur_hook_id = TS_HTTP_TXN_CLOSE_HOOK;
5350     }
5351     break;
5352   default:
5353     cur_hook_id = static_cast<TSHttpHookID>(-1);
5354     ink_assert(!"not reached");
5355   }
5356 
5357   hook_state.init(cur_hook_id, http_global_hooks, ua_txn ? ua_txn->feature_hooks() : nullptr, &api_hooks);
5358   cur_hook  = nullptr;
5359   cur_hooks = 0;
5360   return state_api_callout(0, nullptr);
5361 }
5362 
5363 VConnection *
do_post_transform_open()5364 HttpSM::do_post_transform_open()
5365 {
5366   ink_assert(post_transform_info.vc == nullptr);
5367 
5368   if (is_action_tag_set("http_post_nullt")) {
5369     txn_hook_add(TS_HTTP_REQUEST_TRANSFORM_HOOK, transformProcessor.null_transform(mutex.get()));
5370   }
5371 
5372   post_transform_info.vc = transformProcessor.open(this, api_hooks.get(TS_HTTP_REQUEST_TRANSFORM_HOOK));
5373   if (post_transform_info.vc) {
5374     // Record the transform VC in our table
5375     post_transform_info.entry          = vc_table.new_entry();
5376     post_transform_info.entry->vc      = post_transform_info.vc;
5377     post_transform_info.entry->vc_type = HTTP_TRANSFORM_VC;
5378   }
5379 
5380   return post_transform_info.vc;
5381 }
5382 
5383 VConnection *
do_transform_open()5384 HttpSM::do_transform_open()
5385 {
5386   ink_assert(transform_info.vc == nullptr);
5387   APIHook *hooks;
5388 
5389   if (is_action_tag_set("http_nullt")) {
5390     txn_hook_add(TS_HTTP_RESPONSE_TRANSFORM_HOOK, transformProcessor.null_transform(mutex.get()));
5391   }
5392 
5393   hooks = api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK);
5394   if (hooks) {
5395     transform_info.vc = transformProcessor.open(this, hooks);
5396 
5397     // Record the transform VC in our table
5398     transform_info.entry          = vc_table.new_entry();
5399     transform_info.entry->vc      = transform_info.vc;
5400     transform_info.entry->vc_type = HTTP_TRANSFORM_VC;
5401   } else {
5402     transform_info.vc = nullptr;
5403   }
5404 
5405   return transform_info.vc;
5406 }
5407 
5408 void
mark_host_failure(HostDBInfo * info,time_t time_down)5409 HttpSM::mark_host_failure(HostDBInfo *info, time_t time_down)
5410 {
5411   char addrbuf[INET6_ADDRPORTSTRLEN];
5412 
5413   if (time_down) {
5414     // Increment the fail_count
5415     ++info->app.http_data.fail_count;
5416     if (info->app.http_data.fail_count >= t_state.txn_conf->connect_attempts_rr_retries) {
5417       if (info->app.http_data.last_failure == 0) {
5418         char *url_str = t_state.hdr_info.client_request.url_string_get(&t_state.arena, nullptr);
5419         int host_len;
5420         const char *host_name_ptr = t_state.unmapped_url.host_get(&host_len);
5421         std::string_view host_name{host_name_ptr, size_t(host_len)};
5422         Log::error("%s", lbw()
5423                            .clip(1)
5424                            .print("CONNECT: {::s} connecting to {} for host='{}' url='{}' marking down",
5425                                   ts::bwf::Errno(t_state.current.server->connect_result), t_state.current.server->dst_addr,
5426                                   host_name, ts::bwf::FirstOf(url_str, "<none>"))
5427                            .extend(1)
5428                            .write('\0')
5429                            .data());
5430 
5431         if (url_str) {
5432           t_state.arena.str_free(url_str);
5433         }
5434       }
5435       info->app.http_data.last_failure = time_down;
5436       SMDebug("http", "[%" PRId64 "] hostdb update marking IP: %s as down", sm_id,
5437               ats_ip_nptop(&t_state.current.server->dst_addr.sa, addrbuf, sizeof(addrbuf)));
5438     } else {
5439       SMDebug("http", "[%" PRId64 "] hostdb increment IP failcount %s to %d", sm_id,
5440               ats_ip_nptop(&t_state.current.server->dst_addr.sa, addrbuf, sizeof(addrbuf)), info->app.http_data.fail_count);
5441     }
5442   } else { // Clear the failure
5443     info->app.http_data.fail_count   = 0;
5444     info->app.http_data.last_failure = time_down;
5445   }
5446 
5447 #ifdef DEBUG
5448   ink_assert(ink_local_time() + t_state.txn_conf->down_server_timeout > time_down);
5449 #endif
5450 }
5451 
5452 void
set_ua_abort(HttpTransact::AbortState_t ua_abort,int event)5453 HttpSM::set_ua_abort(HttpTransact::AbortState_t ua_abort, int event)
5454 {
5455   t_state.client_info.abort = ua_abort;
5456 
5457   switch (ua_abort) {
5458   case HttpTransact::ABORTED:
5459     // More detailed client side abort logging based on event
5460     switch (event) {
5461     case VC_EVENT_ERROR:
5462       t_state.squid_codes.log_code = SQUID_LOG_ERR_CLIENT_READ_ERROR;
5463       break;
5464     case VC_EVENT_EOS:
5465     case VC_EVENT_ACTIVE_TIMEOUT:     // Won't matter. Server will hangup
5466     case VC_EVENT_INACTIVITY_TIMEOUT: // Won't matter. Send back 408
5467     // Fall-through
5468     default:
5469       t_state.squid_codes.log_code = SQUID_LOG_ERR_CLIENT_ABORT;
5470       break;
5471     }
5472     break;
5473   default:
5474     // Handled here:
5475     // HttpTransact::ABORT_UNDEFINED, HttpTransact::DIDNOT_ABORT
5476     break;
5477   }
5478 
5479   // Set the connection attribute code for the client so that
5480   //   we log the client finish code correctly
5481   switch (event) {
5482   case VC_EVENT_ACTIVE_TIMEOUT:
5483     t_state.client_info.state = HttpTransact::ACTIVE_TIMEOUT;
5484     break;
5485   case VC_EVENT_INACTIVITY_TIMEOUT:
5486     t_state.client_info.state = HttpTransact::INACTIVE_TIMEOUT;
5487     break;
5488   case VC_EVENT_ERROR:
5489     t_state.client_info.state = HttpTransact::CONNECTION_ERROR;
5490     break;
5491   }
5492 }
5493 
5494 // void HttpSM::release_server_session()
5495 //
5496 //  Called when we are not tunneling a response from the
5497 //   server.  If the session is keep alive, release it back to the
5498 //   shared pool, otherwise close it
5499 //
5500 void
release_server_session(bool serve_from_cache)5501 HttpSM::release_server_session(bool serve_from_cache)
5502 {
5503   if (server_session == nullptr) {
5504     return;
5505   }
5506 
5507   if (TS_SERVER_SESSION_SHARING_MATCH_NONE != t_state.txn_conf->server_session_sharing_match && t_state.current.server != nullptr &&
5508       t_state.current.server->keep_alive == HTTP_KEEPALIVE && t_state.hdr_info.server_response.valid() &&
5509       t_state.hdr_info.server_request.valid() &&
5510       (t_state.hdr_info.server_response.status_get() == HTTP_STATUS_NOT_MODIFIED ||
5511        (t_state.hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD &&
5512         t_state.www_auth_content != HttpTransact::CACHE_AUTH_NONE)) &&
5513       plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) {
5514     HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat);
5515     server_session->attach_hostname(t_state.current.server->name);
5516     if (t_state.www_auth_content == HttpTransact::CACHE_AUTH_NONE || serve_from_cache == false) {
5517       // Must explicitly set the keep_alive_no_activity time before doing the release
5518       server_session->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->keep_alive_no_activity_timeout_out));
5519       server_session->release(nullptr);
5520     } else {
5521       // an authenticated server connection - attach to the local client
5522       // we are serving from cache for the current transaction
5523       t_state.www_auth_content = HttpTransact::CACHE_AUTH_SERVE;
5524       ua_txn->attach_server_session(server_session, false);
5525     }
5526   } else {
5527     if (TS_SERVER_SESSION_SHARING_MATCH_NONE == t_state.txn_conf->server_session_sharing_match) {
5528       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_no_sharing);
5529     } else if (t_state.current.server == nullptr) {
5530       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_no_server);
5531     } else if (t_state.current.server->keep_alive != HTTP_KEEPALIVE) {
5532       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_no_keep_alive);
5533     } else if (!t_state.hdr_info.server_response.valid()) {
5534       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_invalid_response);
5535     } else if (!t_state.hdr_info.server_request.valid()) {
5536       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_invalid_request);
5537     } else if (t_state.hdr_info.server_response.status_get() != HTTP_STATUS_NOT_MODIFIED &&
5538                (t_state.hdr_info.server_request.method_get_wksidx() != HTTP_WKSIDX_HEAD ||
5539                 t_state.www_auth_content == HttpTransact::CACHE_AUTH_NONE)) {
5540       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_modified);
5541     } else {
5542       HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_release_misc);
5543     }
5544     server_session->do_io_close();
5545   }
5546 
5547   ink_assert(server_entry->vc == server_session);
5548   server_entry->in_tunnel = true;
5549   vc_table.cleanup_entry(server_entry);
5550   server_entry   = nullptr;
5551   server_session = nullptr;
5552 }
5553 
5554 // void HttpSM::handle_post_failure()
5555 //
5556 //   We failed in our attempt post (or put) a document
5557 //    to the server.  Two cases happen here.  The normal
5558 //    one is the server died, in which case we ought to
5559 //    return an error to the client.  The second one is
5560 //    stupid.  The server returned a response without reading
5561 //    all the post data.  In order to be as transparent as
5562 //    possible process the server's response
5563 void
handle_post_failure()5564 HttpSM::handle_post_failure()
5565 {
5566   STATE_ENTER(&HttpSM::handle_post_failure, VC_EVENT_NONE);
5567 
5568   ink_assert(ua_entry->vc == ua_txn);
5569   ink_assert(is_waiting_for_full_body || server_entry->eos == true);
5570 
5571   if (is_waiting_for_full_body) {
5572     call_transact_and_set_next_state(HttpTransact::Forbidden);
5573     return;
5574   }
5575   // First order of business is to clean up from
5576   //  the tunnel
5577   // note: since the tunnel is providing the buffer for a lingering
5578   // client read (for abort watching purposes), we need to stop
5579   // the read
5580   if (false == t_state.redirect_info.redirect_in_process) {
5581     ua_entry->read_vio = ua_txn->do_io_read(this, 0, nullptr);
5582   }
5583   ua_entry->in_tunnel     = false;
5584   server_entry->in_tunnel = false;
5585 
5586   // disable redirection in case we got a partial response and then EOS, because the buffer might not
5587   // have the full post and it's deallocating the post buffers here
5588   this->disable_redirect();
5589 
5590   // Don't even think about doing keep-alive after this debacle
5591   t_state.client_info.keep_alive     = HTTP_NO_KEEPALIVE;
5592   t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE;
5593 
5594   if (server_buffer_reader->read_avail() > 0) {
5595     tunnel.deallocate_buffers();
5596     tunnel.reset();
5597     // There's data from the server so try to read the header
5598     setup_server_read_response_header();
5599   } else {
5600     tunnel.deallocate_buffers();
5601     tunnel.reset();
5602     // Server died
5603     if (t_state.current.state == HttpTransact::STATE_UNDEFINED || t_state.current.state == HttpTransact::CONNECTION_ALIVE) {
5604       t_state.set_connect_fail(server_session->get_netvc()->lerrno);
5605       t_state.current.state = HttpTransact::CONNECTION_CLOSED;
5606     }
5607     call_transact_and_set_next_state(HttpTransact::HandleResponse);
5608   }
5609 }
5610 
5611 // void HttpSM::handle_http_server_open()
5612 //
5613 //   The server connection is now open.  If there is a POST or PUT,
5614 //    we need setup a transform is there is one otherwise we need
5615 //    to send the request header
5616 //
5617 void
handle_http_server_open()5618 HttpSM::handle_http_server_open()
5619 {
5620   // The request is now not queued. This is important because server retries reuse the t_state.
5621   t_state.outbound_conn_track_state.dequeue();
5622 
5623   // [bwyatt] applying per-transaction OS netVC options here
5624   //          IFF they differ from the netVC's current options.
5625   //          This should keep this from being redundant on a
5626   //          server session's first transaction.
5627   if (nullptr != server_session) {
5628     NetVConnection *vc = server_session->get_netvc();
5629     if (vc) {
5630       server_connection_provided_cert = vc->provided_cert();
5631       if (vc->options.sockopt_flags != t_state.txn_conf->sock_option_flag_out ||
5632           vc->options.packet_mark != t_state.txn_conf->sock_packet_mark_out ||
5633           vc->options.packet_tos != t_state.txn_conf->sock_packet_tos_out) {
5634         vc->options.sockopt_flags = t_state.txn_conf->sock_option_flag_out;
5635         vc->options.packet_mark   = t_state.txn_conf->sock_packet_mark_out;
5636         vc->options.packet_tos    = t_state.txn_conf->sock_packet_tos_out;
5637         vc->apply_options();
5638       }
5639     }
5640   }
5641 
5642   int method = t_state.hdr_info.server_request.method_get_wksidx();
5643   if (method != HTTP_WKSIDX_TRACE &&
5644       (t_state.hdr_info.request_content_length > 0 || t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING) &&
5645       do_post_transform_open()) {
5646     do_setup_post_tunnel(HTTP_TRANSFORM_VC);
5647   } else if (server_session != nullptr) {
5648     setup_server_send_request_api();
5649   }
5650 }
5651 
5652 // void HttpSM::handle_server_setup_error(int event, void* data)
5653 //
5654 //   Handles setting t_state.current.state and calling
5655 //    Transact in between opening an origin server connection
5656 //    and receiving the response header (in the case of the
5657 //    POST, a post tunnel happens in between the sending
5658 //    request header and reading the response header
5659 //
5660 void
handle_server_setup_error(int event,void * data)5661 HttpSM::handle_server_setup_error(int event, void *data)
5662 {
5663   VIO *vio = static_cast<VIO *>(data);
5664   ink_assert(vio != nullptr);
5665 
5666   STATE_ENTER(&HttpSM::handle_server_setup_error, event);
5667 
5668   // If there is POST or PUT tunnel wait for the tunnel
5669   //  to figure out that things have gone to hell
5670 
5671   if (tunnel.is_tunnel_active()) {
5672     ink_assert(server_entry->read_vio == data || server_entry->write_vio == data);
5673     SMDebug("http",
5674             "[%" PRId64 "] [handle_server_setup_error] "
5675             "forwarding event %s to post tunnel",
5676             sm_id, HttpDebugNames::get_event_name(event));
5677     HttpTunnelConsumer *c = tunnel.get_consumer(server_entry->vc);
5678     // it is possible only user agent post->post transform is set up
5679     // this happened for Linux iocore where NET_EVENT_OPEN was returned
5680     // for a non-existing listening port. the hack is to pass the error
5681     // event for server connection to post_transform_info
5682     if (c == nullptr && post_transform_info.vc) {
5683       c = tunnel.get_consumer(post_transform_info.vc);
5684       // c->handler_state = HTTP_SM_TRANSFORM_FAIL;
5685 
5686       // No point in proceeding if there is no consumer
5687       // Do we need to do additional clean up in the c == NULL case?
5688       if (c != nullptr) {
5689         HttpTunnelProducer *ua_producer = c->producer;
5690         ink_assert(ua_entry->vc == ua_producer->vc);
5691 
5692         ua_entry->vc_handler = &HttpSM::state_watch_for_client_abort;
5693         ua_entry->read_vio   = ua_producer->vc->do_io_read(this, INT64_MAX, c->producer->read_buffer);
5694         ua_producer->vc->do_io_shutdown(IO_SHUTDOWN_READ);
5695 
5696         ua_producer->alive         = false;
5697         ua_producer->handler_state = HTTP_SM_POST_SERVER_FAIL;
5698         tunnel.handleEvent(VC_EVENT_ERROR, c->write_vio);
5699         return;
5700       }
5701     } else {
5702       // c could be null here as well
5703       if (c != nullptr) {
5704         tunnel.handleEvent(event, c->write_vio);
5705         return;
5706       }
5707     }
5708     // If there is no consumer, let the event pass through to shutdown
5709   } else {
5710     if (post_transform_info.vc) {
5711       HttpTunnelConsumer *c = tunnel.get_consumer(post_transform_info.vc);
5712       if (c && c->handler_state == HTTP_SM_TRANSFORM_OPEN) {
5713         vc_table.cleanup_entry(post_transform_info.entry);
5714         post_transform_info.entry = nullptr;
5715         tunnel.deallocate_buffers();
5716         tunnel.reset();
5717       }
5718     }
5719   }
5720 
5721   switch (event) {
5722   case VC_EVENT_EOS:
5723     t_state.current.state = HttpTransact::CONNECTION_CLOSED;
5724     t_state.set_connect_fail(EPIPE);
5725     break;
5726   case VC_EVENT_ERROR:
5727     t_state.current.state = HttpTransact::CONNECTION_ERROR;
5728     t_state.set_connect_fail(server_session->get_netvc()->lerrno);
5729     break;
5730   case VC_EVENT_ACTIVE_TIMEOUT:
5731     t_state.set_connect_fail(ETIMEDOUT);
5732     t_state.current.state = HttpTransact::ACTIVE_TIMEOUT;
5733     break;
5734 
5735   case VC_EVENT_INACTIVITY_TIMEOUT:
5736     // If we're writing the request and get an inactivity timeout
5737     //   before any bytes are written, the connection to the
5738     //   server failed
5739     // In case of TIMEOUT, the iocore sends back
5740     // server_entry->read_vio instead of the write_vio
5741     t_state.set_connect_fail(ETIMEDOUT);
5742     if (server_entry->write_vio && server_entry->write_vio->nbytes > 0 && server_entry->write_vio->ndone == 0) {
5743       t_state.current.state = HttpTransact::CONNECTION_ERROR;
5744     } else {
5745       t_state.current.state = HttpTransact::INACTIVE_TIMEOUT;
5746     }
5747     break;
5748   default:
5749     ink_release_assert(0);
5750   }
5751 
5752   if (event == VC_EVENT_INACTIVITY_TIMEOUT || event == VC_EVENT_ERROR) {
5753     // Clean up the vc_table entry so any events in play to the timed out server vio
5754     // don't get handled.  The connection isn't there.
5755     if (server_entry) {
5756       ink_assert(server_entry->vc_type == HTTP_SERVER_VC);
5757       vc_table.cleanup_entry(server_entry);
5758       server_entry   = nullptr;
5759       server_session = nullptr;
5760     }
5761   }
5762 
5763   // Closedown server connection and deallocate buffers
5764   ink_assert(!server_entry || server_entry->in_tunnel == false);
5765 
5766   // if we are waiting on a plugin callout for
5767   //   HTTP_API_SEND_REQUEST_HDR defer calling transact until
5768   //   after we've finished processing the plugin callout
5769   switch (callout_state) {
5770   case HTTP_API_NO_CALLOUT:
5771     // Normal fast path case, no api callouts in progress
5772     break;
5773   case HTTP_API_IN_CALLOUT:
5774   case HTTP_API_DEFERED_SERVER_ERROR:
5775     // Callout in progress note that we are in deferring
5776     //   the server error
5777     callout_state = HTTP_API_DEFERED_SERVER_ERROR;
5778     return;
5779   case HTTP_API_DEFERED_CLOSE:
5780     // The user agent has shutdown killing the sm
5781     //   but we are stuck waiting for the server callout
5782     //   to finish so do nothing here.  We don't care
5783     //   about the server connection at this and are
5784     //   just waiting till we can execute the close hook
5785     return;
5786   default:
5787     ink_release_assert(0);
5788   }
5789 
5790   call_transact_and_set_next_state(HttpTransact::HandleResponse);
5791 }
5792 
5793 void
setup_transform_to_server_transfer()5794 HttpSM::setup_transform_to_server_transfer()
5795 {
5796   ink_assert(post_transform_info.vc != nullptr);
5797   ink_assert(post_transform_info.entry->vc == post_transform_info.vc);
5798 
5799   int64_t nbytes            = t_state.hdr_info.transform_request_cl;
5800   int64_t alloc_index       = buffer_size_to_index(nbytes, t_state.http_config_param->max_payload_iobuf_index);
5801   MIOBuffer *post_buffer    = new_MIOBuffer(alloc_index);
5802   IOBufferReader *buf_start = post_buffer->alloc_reader();
5803 
5804   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_post);
5805 
5806   HttpTunnelConsumer *c = tunnel.get_consumer(post_transform_info.vc);
5807 
5808   HttpTunnelProducer *p = tunnel.add_producer(post_transform_info.vc, nbytes, buf_start, &HttpSM::tunnel_handler_transform_read,
5809                                               HT_TRANSFORM, "post transform");
5810   tunnel.chain(c, p);
5811   post_transform_info.entry->in_tunnel = true;
5812 
5813   tunnel.add_consumer(server_entry->vc, post_transform_info.vc, &HttpSM::tunnel_handler_post_server, HT_HTTP_SERVER,
5814                       "http server post");
5815   server_entry->in_tunnel = true;
5816 
5817   tunnel.tunnel_run(p);
5818 }
5819 
5820 void
do_drain_request_body(HTTPHdr & response)5821 HttpSM::do_drain_request_body(HTTPHdr &response)
5822 {
5823   int64_t content_length = t_state.hdr_info.client_request.get_content_length();
5824   int64_t avail          = ua_buffer_reader->read_avail();
5825 
5826   if (t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING) {
5827     SMDebug("http", "Chunked body, setting the response to non-keepalive");
5828     goto close_connection;
5829   }
5830 
5831   if (content_length > 0) {
5832     if (avail >= content_length) {
5833       SMDebug("http", "entire body is in the buffer, consuming");
5834       int64_t act_on            = (avail < content_length) ? avail : content_length;
5835       client_request_body_bytes = act_on;
5836       ua_buffer_reader->consume(act_on);
5837     } else {
5838       SMDebug("http", "entire body is not in the buffer, setting the response to non-keepalive");
5839       goto close_connection;
5840     }
5841   }
5842   return;
5843 
5844 close_connection:
5845   t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE;
5846   response.value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, "close", 5);
5847 }
5848 
5849 void
do_setup_post_tunnel(HttpVC_t to_vc_type)5850 HttpSM::do_setup_post_tunnel(HttpVC_t to_vc_type)
5851 {
5852   bool chunked = t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING ||
5853                  t_state.hdr_info.request_content_length == HTTP_UNDEFINED_CL;
5854   bool post_redirect = false;
5855 
5856   HttpTunnelProducer *p = nullptr;
5857   // YTS Team, yamsat Plugin
5858   // if redirect_in_process and redirection is enabled add static producer
5859 
5860   if (is_using_post_buffer ||
5861       (t_state.redirect_info.redirect_in_process && enable_redirection && this->_postbuf.postdata_copy_buffer_start != nullptr)) {
5862     post_redirect = true;
5863     // copy the post data into a new producer buffer for static producer
5864     MIOBuffer *postdata_producer_buffer      = new_empty_MIOBuffer(t_state.http_config_param->max_payload_iobuf_index);
5865     IOBufferReader *postdata_producer_reader = postdata_producer_buffer->alloc_reader();
5866 
5867     postdata_producer_buffer->write(this->_postbuf.postdata_copy_buffer_start);
5868     int64_t post_bytes = postdata_producer_reader->read_avail();
5869     transfered_bytes   = post_bytes;
5870     p = tunnel.add_producer(HTTP_TUNNEL_STATIC_PRODUCER, post_bytes, postdata_producer_reader, (HttpProducerHandler) nullptr,
5871                             HT_STATIC, "redirect static agent post");
5872   } else {
5873     int64_t alloc_index;
5874     // content length is undefined, use default buffer size
5875     if (t_state.hdr_info.request_content_length == HTTP_UNDEFINED_CL) {
5876       alloc_index = static_cast<int>(t_state.txn_conf->default_buffer_size_index);
5877       if (alloc_index < MIN_CONFIG_BUFFER_SIZE_INDEX || alloc_index > MAX_BUFFER_SIZE_INDEX) {
5878         alloc_index = DEFAULT_REQUEST_BUFFER_SIZE_INDEX;
5879       }
5880     } else {
5881       alloc_index =
5882         buffer_size_to_index(t_state.hdr_info.request_content_length, t_state.http_config_param->max_payload_iobuf_index);
5883     }
5884     MIOBuffer *post_buffer    = new_MIOBuffer(alloc_index);
5885     IOBufferReader *buf_start = post_buffer->alloc_reader();
5886     int64_t post_bytes        = chunked ? INT64_MAX : t_state.hdr_info.request_content_length;
5887 
5888     if (enable_redirection) {
5889       this->_postbuf.init(post_buffer->clone_reader(buf_start));
5890     }
5891 
5892     // Note: Many browsers, Netscape and IE included send two extra
5893     //  bytes (CRLF) at the end of the post.  We just ignore those
5894     //  bytes since the sending them is not spec
5895 
5896     // Next order of business if copy the remaining data from the
5897     //  header buffer into new buffer
5898     client_request_body_bytes = post_buffer->write(ua_buffer_reader, chunked ? ua_buffer_reader->read_avail() : post_bytes);
5899 
5900     ua_buffer_reader->consume(client_request_body_bytes);
5901     p = tunnel.add_producer(ua_entry->vc, post_bytes - transfered_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_HTTP_CLIENT,
5902                             "user agent post");
5903   }
5904   ua_entry->in_tunnel = true;
5905 
5906   switch (to_vc_type) {
5907   case HTTP_TRANSFORM_VC:
5908     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_request_wait_for_transform_read);
5909     ink_assert(post_transform_info.entry != nullptr);
5910     ink_assert(post_transform_info.entry->vc == post_transform_info.vc);
5911     tunnel.add_consumer(post_transform_info.entry->vc, ua_entry->vc, &HttpSM::tunnel_handler_transform_write, HT_TRANSFORM,
5912                         "post transform");
5913     post_transform_info.entry->in_tunnel = true;
5914     break;
5915   case HTTP_SERVER_VC:
5916     // YTS Team, yamsat Plugin
5917     // When redirect in process is true and redirection is enabled
5918     // add http server as the consumer
5919     if (post_redirect) {
5920       HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_for_partial_post);
5921       tunnel.add_consumer(server_entry->vc, HTTP_TUNNEL_STATIC_PRODUCER, &HttpSM::tunnel_handler_post_server, HT_HTTP_SERVER,
5922                           "redirect http server post");
5923     } else {
5924       HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_post);
5925       tunnel.add_consumer(server_entry->vc, ua_entry->vc, &HttpSM::tunnel_handler_post_server, HT_HTTP_SERVER, "http server post");
5926     }
5927     server_entry->in_tunnel = true;
5928     break;
5929   default:
5930     ink_release_assert(0);
5931     break;
5932   }
5933 
5934   // The user agent may support chunked (HTTP/1.1) or not (HTTP/2)
5935   // In either case, the server will support chunked (HTTP/1.1)
5936   if (chunked) {
5937     if (ua_txn->is_chunked_encoding_supported()) {
5938       tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT);
5939     } else {
5940       tunnel.set_producer_chunking_action(p, 0, TCA_CHUNK_CONTENT);
5941       tunnel.set_producer_chunking_size(p, 0);
5942     }
5943   }
5944 
5945   ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in));
5946   server_session->set_inactivity_timeout(get_server_inactivity_timeout());
5947 
5948   tunnel.tunnel_run(p);
5949 
5950   // If we're half closed, we got a FIN from the client. Forward it on to the origin server
5951   // now that we have the tunnel operational.
5952   // HttpTunnel could broken due to bad chunked data and close all vc by chain_abort_all().
5953   if (p->handler_state != HTTP_SM_POST_UA_FAIL && ua_txn->get_half_close_flag()) {
5954     p->vc->do_io_shutdown(IO_SHUTDOWN_READ);
5955   }
5956 }
5957 
5958 // void HttpSM::perform_transform_cache_write_action()
5959 //
5960 //   Called to do cache write from the transform
5961 //
5962 void
perform_transform_cache_write_action()5963 HttpSM::perform_transform_cache_write_action()
5964 {
5965   SMDebug("http", "[%" PRId64 "] perform_transform_cache_write_action %s", sm_id,
5966           HttpDebugNames::get_cache_action_name(t_state.cache_info.action));
5967 
5968   if (t_state.range_setup) {
5969     return;
5970   }
5971 
5972   switch (t_state.cache_info.transform_action) {
5973   case HttpTransact::CACHE_DO_NO_ACTION: {
5974     // Nothing to do
5975     transform_cache_sm.end_both();
5976     break;
5977   }
5978 
5979   case HttpTransact::CACHE_DO_WRITE: {
5980     transform_cache_sm.close_read();
5981     t_state.cache_info.transform_write_status = HttpTransact::CACHE_WRITE_IN_PROGRESS;
5982     setup_cache_write_transfer(&transform_cache_sm, transform_info.entry->vc, &t_state.cache_info.transform_store,
5983                                client_response_hdr_bytes, "cache write t");
5984     break;
5985   }
5986 
5987   default:
5988     ink_release_assert(0);
5989     break;
5990   }
5991 }
5992 
5993 // void HttpSM::perform_cache_write_action()
5994 //
5995 //   Called to do cache write, delete and updates based
5996 //    on s->cache_info.action.  Does not setup cache
5997 //    read tunnels
5998 //
5999 void
perform_cache_write_action()6000 HttpSM::perform_cache_write_action()
6001 {
6002   SMDebug("http", "[%" PRId64 "] perform_cache_write_action %s", sm_id,
6003           HttpDebugNames::get_cache_action_name(t_state.cache_info.action));
6004 
6005   switch (t_state.cache_info.action) {
6006   case HttpTransact::CACHE_DO_NO_ACTION:
6007 
6008   {
6009     // Nothing to do
6010     cache_sm.end_both();
6011     break;
6012   }
6013 
6014   case HttpTransact::CACHE_DO_SERVE: {
6015     cache_sm.abort_write();
6016     break;
6017   }
6018 
6019   case HttpTransact::CACHE_DO_DELETE: {
6020     // Write close deletes the old alternate
6021     cache_sm.close_write();
6022     cache_sm.close_read();
6023     break;
6024   }
6025 
6026   case HttpTransact::CACHE_DO_SERVE_AND_DELETE: {
6027     // FIX ME: need to set up delete for after cache write has
6028     //   completed
6029     break;
6030   }
6031 
6032   case HttpTransact::CACHE_DO_SERVE_AND_UPDATE: {
6033     issue_cache_update();
6034     break;
6035   }
6036 
6037   case HttpTransact::CACHE_DO_UPDATE: {
6038     cache_sm.close_read();
6039     issue_cache_update();
6040     break;
6041   }
6042 
6043   case HttpTransact::CACHE_DO_WRITE:
6044   case HttpTransact::CACHE_DO_REPLACE:
6045     // Fix need to set up delete for after cache write has
6046     //   completed
6047     if (transform_info.entry == nullptr || t_state.api_info.cache_untransformed == true) {
6048       cache_sm.close_read();
6049       t_state.cache_info.write_status = HttpTransact::CACHE_WRITE_IN_PROGRESS;
6050       setup_cache_write_transfer(&cache_sm, server_entry->vc, &t_state.cache_info.object_store, client_response_hdr_bytes,
6051                                  "cache write");
6052     } else {
6053       // We are not caching the untransformed.  We might want to
6054       //  use the cache writevc to cache the transformed copy
6055       ink_assert(transform_cache_sm.cache_write_vc == nullptr);
6056       transform_cache_sm.cache_write_vc = cache_sm.cache_write_vc;
6057       cache_sm.cache_write_vc           = nullptr;
6058     }
6059     break;
6060 
6061   default:
6062     ink_release_assert(0);
6063     break;
6064   }
6065 }
6066 
6067 void
issue_cache_update()6068 HttpSM::issue_cache_update()
6069 {
6070   ink_assert(cache_sm.cache_write_vc != nullptr);
6071   if (cache_sm.cache_write_vc) {
6072     t_state.cache_info.object_store.request_sent_time_set(t_state.request_sent_time);
6073     t_state.cache_info.object_store.response_received_time_set(t_state.response_received_time);
6074     ink_assert(t_state.cache_info.object_store.request_sent_time_get() > 0);
6075     ink_assert(t_state.cache_info.object_store.response_received_time_get() > 0);
6076     cache_sm.cache_write_vc->set_http_info(&t_state.cache_info.object_store);
6077     t_state.cache_info.object_store.clear();
6078   }
6079   // Now close the write which commits the update
6080   cache_sm.close_write();
6081 }
6082 
6083 int
write_header_into_buffer(HTTPHdr * h,MIOBuffer * b)6084 HttpSM::write_header_into_buffer(HTTPHdr *h, MIOBuffer *b)
6085 {
6086   int dumpoffset;
6087   int done;
6088 
6089   dumpoffset = 0;
6090   do {
6091     IOBufferBlock *block = b->get_current_block();
6092     int bufindex         = 0;
6093     int tmp              = dumpoffset;
6094 
6095     ink_assert(block->write_avail() > 0);
6096     done = h->print(block->start(), block->write_avail(), &bufindex, &tmp);
6097     dumpoffset += bufindex;
6098     ink_assert(bufindex > 0);
6099     b->fill(bufindex);
6100     if (!done) {
6101       b->add_block();
6102     }
6103   } while (!done);
6104 
6105   return dumpoffset;
6106 }
6107 
6108 void
attach_server_session(PoolableSession * s)6109 HttpSM::attach_server_session(PoolableSession *s)
6110 {
6111   hsm_release_assert(server_session == nullptr);
6112   hsm_release_assert(server_entry == nullptr);
6113   hsm_release_assert(s != nullptr);
6114   hsm_release_assert(s->is_active());
6115   server_session        = static_cast<Http1ServerSession *>(s);
6116   server_transact_count = server_session->transact_count++;
6117 
6118   // update the dst_addr when using an existing session
6119   // for e.g using Host based session pools may ignore the DNS IP
6120   if (!ats_ip_addr_eq(&t_state.current.server->dst_addr, &server_session->get_server_ip())) {
6121     ip_port_text_buffer ipb1, ipb2;
6122     Debug("http_ss", "updating ip when attaching server session from %s to %s",
6123           ats_ip_ntop(&t_state.current.server->dst_addr.sa, ipb1, sizeof(ipb1)),
6124           ats_ip_ntop(server_session->get_remote_addr(), ipb2, sizeof(ipb2)));
6125     ats_ip_copy(&t_state.current.server->dst_addr, server_session->get_remote_addr());
6126   }
6127 
6128   // Propagate the per client IP debugging
6129   if (ua_txn) {
6130     s->get_netvc()->control_flags.set_flags(get_cont_flags().get_flags());
6131   } else { // If there is no ua_txn no sense in continuing to attach the server session
6132     return;
6133   }
6134 
6135   // Set the mutex so that we have something to update
6136   //   stats with
6137   server_session->mutex = this->mutex;
6138 
6139   HTTP_INCREMENT_DYN_STAT(http_current_server_transactions_stat);
6140 
6141   // Record the VC in our table
6142   server_entry             = vc_table.new_entry();
6143   server_entry->vc         = server_session;
6144   server_entry->vc_type    = HTTP_SERVER_VC;
6145   server_entry->vc_handler = &HttpSM::state_send_server_request_header;
6146 
6147   // es - is this a concern here in HttpSM?  Does it belong somewhere else?
6148   // Get server and client connections
6149   UnixNetVConnection *server_vc = dynamic_cast<UnixNetVConnection *>(server_session->get_netvc());
6150   UnixNetVConnection *client_vc = (UnixNetVConnection *)(ua_txn->get_netvc());
6151 
6152   // Verifying that the user agent and server sessions/transactions are operating on the same thread.
6153   ink_release_assert(!server_vc || !client_vc || server_vc->thread == client_vc->thread);
6154 
6155   // set flag for server session is SSL
6156   SSLNetVConnection *server_ssl_vc = dynamic_cast<SSLNetVConnection *>(server_vc);
6157   if (server_ssl_vc) {
6158     server_connection_is_ssl = true;
6159   }
6160 
6161   server_protocol = server_session->get_protocol_string();
6162 
6163   // Initiate a read on the session so that the SM and not
6164   //  session manager will get called back if the timeout occurs
6165   //  or the server closes on us.  The IO Core now requires us to
6166   //  do the read with a buffer and a size so preallocate the
6167   //  buffer
6168   server_buffer_reader = server_session->get_reader();
6169   // ts-3189 We are only setting up an empty read at this point.  This
6170   // is sufficient to have the timeout errors directed to the appropriate
6171   // SM handler, but we don't want to read any data until the tunnel has
6172   // been set up.  This isn't such a big deal with GET results, since
6173   // if no tunnels are set up, there is no danger of data being delivered
6174   // to the wrong tunnel's consumer handler.  But for post and other
6175   // methods that send data after the request, two tunnels are created in
6176   // series, and with a full read set up at this point, the EOS from the
6177   // first tunnel was sometimes behind handled by the consumer of the
6178   // first tunnel instead of the producer of the second tunnel.
6179   // The real read is setup in setup_server_read_response_header()
6180   server_entry->read_vio = server_session->do_io_read(this, 0, server_session->read_buffer);
6181 
6182   // Transfer control of the write side as well
6183   server_entry->write_vio = server_session->do_io_write(this, 0, nullptr);
6184 
6185   // Setup the timeouts
6186   // Set the inactivity timeout to the connect timeout so that we
6187   //   we fail this server if it doesn't start sending the response
6188   //   header
6189   server_session->set_inactivity_timeout(get_server_connect_timeout());
6190   server_session->set_active_timeout(get_server_active_timeout());
6191 
6192   // Do we need Transfer_Encoding?
6193   if (ua_txn->has_request_body(t_state.hdr_info.request_content_length,
6194                                t_state.client_info.transfer_encoding == HttpTransact::CHUNKED_ENCODING)) {
6195     // See if we need to insert a chunked header
6196     if (!t_state.hdr_info.server_request.presence(MIME_PRESENCE_CONTENT_LENGTH)) {
6197       // Stuff in a TE setting so we treat this as chunked, sort of.
6198       t_state.server_info.transfer_encoding = HttpTransact::CHUNKED_ENCODING;
6199       t_state.hdr_info.server_request.value_append(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING, HTTP_VALUE_CHUNKED,
6200                                                    HTTP_LEN_CHUNKED, true);
6201     }
6202   }
6203 
6204   if (plugin_tunnel_type != HTTP_NO_PLUGIN_TUNNEL || will_be_private_ss) {
6205     SMDebug("http_ss", "Setting server session to private");
6206     server_session->set_private();
6207   }
6208 }
6209 
6210 void
setup_server_send_request_api()6211 HttpSM::setup_server_send_request_api()
6212 {
6213   // Make sure the VC is on the correct timeout
6214   server_session->set_inactivity_timeout(get_server_inactivity_timeout());
6215   t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR;
6216   do_api_callout();
6217 }
6218 
6219 void
setup_server_send_request()6220 HttpSM::setup_server_send_request()
6221 {
6222   int hdr_length;
6223   int64_t msg_len = 0; /* lv: just make gcc happy */
6224 
6225   hsm_release_assert(server_entry != nullptr);
6226   hsm_release_assert(server_session != nullptr);
6227   hsm_release_assert(server_entry->vc == server_session);
6228 
6229   // Send the request header
6230   server_entry->vc_handler   = &HttpSM::state_send_server_request_header;
6231   server_entry->write_buffer = new_MIOBuffer(HTTP_HEADER_BUFFER_SIZE_INDEX);
6232 
6233   if (t_state.api_server_request_body_set) {
6234     msg_len = t_state.internal_msg_buffer_size;
6235     t_state.hdr_info.server_request.value_set_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH, msg_len);
6236   }
6237 
6238   DUMP_HEADER("http_hdrs", &(t_state.hdr_info.server_request), t_state.state_machine_id, "Proxy's Request after hooks");
6239 
6240   // We need a reader so bytes don't fall off the end of
6241   //  the buffer
6242   IOBufferReader *buf_start = server_entry->write_buffer->alloc_reader();
6243   server_request_hdr_bytes = hdr_length = write_header_into_buffer(&t_state.hdr_info.server_request, server_entry->write_buffer);
6244 
6245   // the plugin decided to append a message to the request
6246   if (t_state.api_server_request_body_set) {
6247     SMDebug("http", "[%" PRId64 "] appending msg of %" PRId64 " bytes to request %s", sm_id, msg_len, t_state.internal_msg_buffer);
6248     hdr_length += server_entry->write_buffer->write(t_state.internal_msg_buffer, msg_len);
6249     server_request_body_bytes = msg_len;
6250   }
6251 
6252   milestones[TS_MILESTONE_SERVER_BEGIN_WRITE] = Thread::get_hrtime();
6253   server_entry->write_vio                     = server_entry->vc->do_io_write(this, hdr_length, buf_start);
6254 
6255   // Make sure the VC is using correct timeouts.  We may be reusing a previously used server session
6256   server_session->set_inactivity_timeout(get_server_inactivity_timeout());
6257 }
6258 
6259 void
setup_server_read_response_header()6260 HttpSM::setup_server_read_response_header()
6261 {
6262   ink_assert(server_session != nullptr);
6263   ink_assert(server_entry != nullptr);
6264   // REQ_FLAVOR_SCHEDULED_UPDATE can be transformed in REQ_FLAVOR_REVPROXY
6265   ink_assert(ua_txn != nullptr || t_state.req_flavor == HttpTransact::REQ_FLAVOR_SCHEDULED_UPDATE ||
6266              t_state.req_flavor == HttpTransact::REQ_FLAVOR_REVPROXY);
6267 
6268   // We should have set the server_buffer_reader
6269   //   we sent the request header
6270   ink_assert(server_buffer_reader != nullptr);
6271 
6272   // Now that we've got the ability to read from the
6273   //  server, setup to read the response header
6274   server_entry->vc_handler = &HttpSM::state_read_server_response_header;
6275 
6276   t_state.current.state         = HttpTransact::STATE_UNDEFINED;
6277   t_state.current.server->state = HttpTransact::STATE_UNDEFINED;
6278 
6279   // Note: we must use destroy() here since clear()
6280   //  does not free the memory from the header
6281   t_state.hdr_info.server_response.destroy();
6282   t_state.hdr_info.server_response.create(HTTP_TYPE_RESPONSE);
6283   http_parser_clear(&http_parser);
6284   server_response_hdr_bytes                        = 0;
6285   milestones[TS_MILESTONE_SERVER_READ_HEADER_DONE] = 0;
6286 
6287   // We already done the READ when we setup the connection to
6288   //   read the request header
6289   ink_assert(server_entry->read_vio);
6290 
6291   // The tunnel from OS to UA is now setup.  Ready to read the response
6292   server_entry->read_vio = server_session->do_io_read(this, INT64_MAX, server_buffer_reader->mbuf);
6293 
6294   // If there is anything in the buffer call the parsing routines
6295   //  since if the response is finished, we won't get any
6296   //  additional callbacks
6297 
6298   if (server_buffer_reader->read_avail() > 0) {
6299     state_read_server_response_header((server_entry->eos) ? VC_EVENT_EOS : VC_EVENT_READ_READY, server_entry->read_vio);
6300   }
6301 }
6302 
6303 HttpTunnelProducer *
setup_cache_read_transfer()6304 HttpSM::setup_cache_read_transfer()
6305 {
6306   int64_t alloc_index, hdr_size;
6307   int64_t doc_size;
6308 
6309   ink_assert(cache_sm.cache_read_vc != nullptr);
6310 
6311   doc_size    = t_state.cache_info.object_read->object_size_get();
6312   alloc_index = buffer_size_to_index(doc_size + index_to_buffer_size(HTTP_HEADER_BUFFER_SIZE_INDEX),
6313                                      t_state.http_config_param->max_payload_iobuf_index);
6314 
6315 #ifndef USE_NEW_EMPTY_MIOBUFFER
6316   MIOBuffer *buf = new_MIOBuffer(alloc_index);
6317 #else
6318   MIOBuffer *buf = new_empty_MIOBuffer(alloc_index);
6319   buf->append_block(HTTP_HEADER_BUFFER_SIZE_INDEX);
6320 #endif
6321 
6322   buf->water_mark = static_cast<int>(t_state.txn_conf->default_buffer_water_mark);
6323 
6324   IOBufferReader *buf_start = buf->alloc_reader();
6325 
6326   // Now dump the header into the buffer
6327   ink_assert(t_state.hdr_info.client_response.status_get() != HTTP_STATUS_NOT_MODIFIED);
6328   client_response_hdr_bytes = hdr_size = write_response_header_into_buffer(&t_state.hdr_info.client_response, buf);
6329   cache_response_hdr_bytes             = client_response_hdr_bytes;
6330 
6331   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6332 
6333   if (doc_size != INT64_MAX) {
6334     doc_size += hdr_size;
6335   }
6336 
6337   HttpTunnelProducer *p = tunnel.add_producer(cache_sm.cache_read_vc, doc_size, buf_start, &HttpSM::tunnel_handler_cache_read,
6338                                               HT_CACHE_READ, "cache read");
6339   tunnel.add_consumer(ua_entry->vc, cache_sm.cache_read_vc, &HttpSM::tunnel_handler_ua, HT_HTTP_CLIENT, "user agent");
6340   // if size of a cached item is not known, we'll do chunking for keep-alive HTTP/1.1 clients
6341   // this only applies to read-while-write cases where origin server sends a dynamically generated chunked content
6342   // w/o providing a Content-Length header
6343   if (t_state.client_info.receive_chunked_response) {
6344     tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT);
6345     tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size);
6346   }
6347   ua_entry->in_tunnel    = true;
6348   cache_sm.cache_read_vc = nullptr;
6349   return p;
6350 }
6351 
6352 HttpTunnelProducer *
setup_cache_transfer_to_transform()6353 HttpSM::setup_cache_transfer_to_transform()
6354 {
6355   int64_t alloc_index;
6356   int64_t doc_size;
6357 
6358   ink_assert(cache_sm.cache_read_vc != nullptr);
6359   ink_assert(transform_info.vc != nullptr);
6360   ink_assert(transform_info.entry->vc == transform_info.vc);
6361 
6362   // grab this here
6363   cache_response_hdr_bytes = t_state.hdr_info.cache_response.length_get();
6364 
6365   doc_size                  = t_state.cache_info.object_read->object_size_get();
6366   alloc_index               = buffer_size_to_index(doc_size, t_state.http_config_param->max_payload_iobuf_index);
6367   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6368   IOBufferReader *buf_start = buf->alloc_reader();
6369 
6370   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_response_wait_for_transform_read);
6371 
6372   HttpTunnelProducer *p = tunnel.add_producer(cache_sm.cache_read_vc, doc_size, buf_start, &HttpSM::tunnel_handler_cache_read,
6373                                               HT_CACHE_READ, "cache read");
6374 
6375   tunnel.add_consumer(transform_info.vc, cache_sm.cache_read_vc, &HttpSM::tunnel_handler_transform_write, HT_TRANSFORM,
6376                       "transform write");
6377   transform_info.entry->in_tunnel = true;
6378   cache_sm.cache_read_vc          = nullptr;
6379 
6380   return p;
6381 }
6382 
6383 void
setup_cache_write_transfer(HttpCacheSM * c_sm,VConnection * source_vc,HTTPInfo * store_info,int64_t skip_bytes,const char * name)6384 HttpSM::setup_cache_write_transfer(HttpCacheSM *c_sm, VConnection *source_vc, HTTPInfo *store_info, int64_t skip_bytes,
6385                                    const char *name)
6386 {
6387   ink_assert(c_sm->cache_write_vc != nullptr);
6388   ink_assert(t_state.request_sent_time > 0);
6389   ink_assert(t_state.response_received_time > 0);
6390 
6391   store_info->request_sent_time_set(t_state.request_sent_time);
6392   store_info->response_received_time_set(t_state.response_received_time);
6393 
6394   c_sm->cache_write_vc->set_http_info(store_info);
6395   store_info->clear();
6396 
6397   tunnel.add_consumer(c_sm->cache_write_vc, source_vc, &HttpSM::tunnel_handler_cache_write, HT_CACHE_WRITE, name, skip_bytes);
6398 
6399   c_sm->cache_write_vc = nullptr;
6400 }
6401 
6402 void
setup_100_continue_transfer()6403 HttpSM::setup_100_continue_transfer()
6404 {
6405   MIOBuffer *buf            = new_MIOBuffer(HTTP_HEADER_BUFFER_SIZE_INDEX);
6406   IOBufferReader *buf_start = buf->alloc_reader();
6407 
6408   // First write the client response header into the buffer
6409   ink_assert(t_state.client_info.http_version != HTTP_0_9);
6410   client_response_hdr_bytes = write_header_into_buffer(&t_state.hdr_info.client_response, buf);
6411   ink_assert(client_response_hdr_bytes > 0);
6412 
6413   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_100_continue);
6414 
6415   // Clear the decks before we set up new producers.  As things stand, we cannot have two static operators
6416   // at once
6417   tunnel.reset();
6418 
6419   // Setup the tunnel to the client
6420   HttpTunnelProducer *p = tunnel.add_producer(HTTP_TUNNEL_STATIC_PRODUCER, client_response_hdr_bytes, buf_start,
6421                                               (HttpProducerHandler) nullptr, HT_STATIC, "internal msg - 100 continue");
6422   tunnel.add_consumer(ua_entry->vc, HTTP_TUNNEL_STATIC_PRODUCER, &HttpSM::tunnel_handler_100_continue_ua, HT_HTTP_CLIENT,
6423                       "user agent");
6424 
6425   // Make sure the half_close is not set.
6426   ua_txn->set_half_close_flag(false);
6427   ua_entry->in_tunnel = true;
6428   tunnel.tunnel_run(p);
6429 }
6430 
6431 //////////////////////////////////////////////////////////////////////////
6432 //
6433 //  HttpSM::setup_error_transfer()
6434 //
6435 //  The proxy has generated an error message which it
6436 //  is sending to the client. For some cases, however,
6437 //  such as when the proxy is transparent, returning
6438 //  a proxy-generated error message exposes the proxy,
6439 //  destroying transparency. The HttpBodyFactory code,
6440 //  therefore, does not generate an error message body
6441 //  in such cases. This function checks for the presence
6442 //  of an error body. If its not present, it closes the
6443 //  connection to the user, else it simply calls
6444 //  setup_write_proxy_internal, which is the standard
6445 //  routine for setting up proxy-generated responses.
6446 //
6447 //////////////////////////////////////////////////////////////////////////
6448 void
setup_error_transfer()6449 HttpSM::setup_error_transfer()
6450 {
6451   if (t_state.internal_msg_buffer || is_response_body_precluded(t_state.http_return_code)) {
6452     // Since we need to send the error message, call the API
6453     //   function
6454     ink_assert(t_state.internal_msg_buffer_size > 0 || is_response_body_precluded(t_state.http_return_code));
6455     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
6456     do_api_callout();
6457   } else {
6458     SMDebug("http", "[setup_error_transfer] Now closing connection ...");
6459     vc_table.cleanup_entry(ua_entry);
6460     ua_entry = nullptr;
6461     // ua_txn     = NULL;
6462     terminate_sm   = true;
6463     t_state.source = HttpTransact::SOURCE_INTERNAL;
6464   }
6465 }
6466 
6467 void
setup_internal_transfer(HttpSMHandler handler_arg)6468 HttpSM::setup_internal_transfer(HttpSMHandler handler_arg)
6469 {
6470   bool is_msg_buf_present;
6471 
6472   if (t_state.internal_msg_buffer) {
6473     is_msg_buf_present = true;
6474     ink_assert(t_state.internal_msg_buffer_size > 0);
6475 
6476     // Set the content length here since a plugin
6477     //   may have changed the error body
6478     t_state.hdr_info.client_response.set_content_length(t_state.internal_msg_buffer_size);
6479     t_state.hdr_info.client_response.field_delete(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
6480 
6481     // set internal_msg_buffer_type if available
6482     if (t_state.internal_msg_buffer_type) {
6483       int len = strlen(t_state.internal_msg_buffer_type);
6484 
6485       if (len > 0) {
6486         t_state.hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, t_state.internal_msg_buffer_type,
6487                                                    len);
6488       }
6489       ats_free(t_state.internal_msg_buffer_type);
6490       t_state.internal_msg_buffer_type = nullptr;
6491     } else {
6492       t_state.hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, "text/html", 9);
6493     }
6494   } else {
6495     is_msg_buf_present = false;
6496 
6497     // If we are sending a response that can have a body
6498     //   but doesn't have a body add a content-length of zero.
6499     //   Needed for keep-alive on PURGE requests
6500     if (!is_response_body_precluded(t_state.hdr_info.client_response.status_get(), t_state.method)) {
6501       t_state.hdr_info.client_response.set_content_length(0);
6502       t_state.hdr_info.client_response.field_delete(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
6503     }
6504   }
6505 
6506   t_state.source = HttpTransact::SOURCE_INTERNAL;
6507 
6508   int64_t buf_size =
6509     index_to_buffer_size(HTTP_HEADER_BUFFER_SIZE_INDEX) + (is_msg_buf_present ? t_state.internal_msg_buffer_size : 0);
6510 
6511   MIOBuffer *buf            = new_MIOBuffer(buffer_size_to_index(buf_size, t_state.http_config_param->max_payload_iobuf_index));
6512   IOBufferReader *buf_start = buf->alloc_reader();
6513 
6514   // First write the client response header into the buffer
6515   client_response_hdr_bytes = write_response_header_into_buffer(&t_state.hdr_info.client_response, buf);
6516   int64_t nbytes            = client_response_hdr_bytes;
6517 
6518   // Next append the message onto the MIOBuffer
6519 
6520   // From HTTP/1.1 RFC:
6521   // "The HEAD method is identical to GET except that the server
6522   // MUST NOT return a message-body in the response. The metainformation
6523   // in the HTTP headers in response to a HEAD request SHOULD be
6524   // identical to the information sent in response to a GET request."
6525   // --> do not append the message onto the MIOBuffer and keep our pointer
6526   // to it so that it can be freed.
6527 
6528   if (is_msg_buf_present && t_state.method != HTTP_WKSIDX_HEAD) {
6529     nbytes += t_state.internal_msg_buffer_size;
6530 
6531     if (t_state.internal_msg_buffer_fast_allocator_size < 0) {
6532       buf->append_xmalloced(t_state.internal_msg_buffer, t_state.internal_msg_buffer_size);
6533     } else {
6534       buf->append_fast_allocated(t_state.internal_msg_buffer, t_state.internal_msg_buffer_size,
6535                                  t_state.internal_msg_buffer_fast_allocator_size);
6536     }
6537 
6538     // The IOBufferBlock will free the msg buffer when necessary so
6539     //  eliminate our pointer to it
6540     t_state.internal_msg_buffer      = nullptr;
6541     t_state.internal_msg_buffer_size = 0;
6542   }
6543 
6544   HTTP_SM_SET_DEFAULT_HANDLER(handler_arg);
6545 
6546   // Clear the decks before we setup the new producers
6547   // As things stand, we cannot have two static producers operating at
6548   // once
6549   tunnel.reset();
6550 
6551   // Setup the tunnel to the client
6552   HttpTunnelProducer *p =
6553     tunnel.add_producer(HTTP_TUNNEL_STATIC_PRODUCER, nbytes, buf_start, (HttpProducerHandler) nullptr, HT_STATIC, "internal msg");
6554   tunnel.add_consumer(ua_entry->vc, HTTP_TUNNEL_STATIC_PRODUCER, &HttpSM::tunnel_handler_ua, HT_HTTP_CLIENT, "user agent");
6555 
6556   ua_entry->in_tunnel = true;
6557   tunnel.tunnel_run(p);
6558 }
6559 
6560 // int HttpSM::find_http_resp_buffer_size(int cl)
6561 //
6562 //   Returns the allocation index for the buffer for
6563 //     a response based on the content length
6564 //
6565 int
find_http_resp_buffer_size(int64_t content_length)6566 HttpSM::find_http_resp_buffer_size(int64_t content_length)
6567 {
6568   int64_t alloc_index;
6569 
6570   if (content_length == HTTP_UNDEFINED_CL) {
6571     // Try use our configured default size.  Otherwise pick
6572     //   the default size
6573     alloc_index = static_cast<int>(t_state.txn_conf->default_buffer_size_index);
6574     if (alloc_index < MIN_CONFIG_BUFFER_SIZE_INDEX || alloc_index > DEFAULT_MAX_BUFFER_SIZE) {
6575       alloc_index = DEFAULT_RESPONSE_BUFFER_SIZE_INDEX;
6576     }
6577   } else {
6578     int64_t buf_size = index_to_buffer_size(HTTP_HEADER_BUFFER_SIZE_INDEX) + content_length;
6579     alloc_index      = buffer_size_to_index(buf_size, t_state.http_config_param->max_payload_iobuf_index);
6580   }
6581 
6582   return alloc_index;
6583 }
6584 
6585 // int HttpSM::server_transfer_init()
6586 //
6587 //    Moves data from the header buffer into the reply buffer
6588 //      and return the number of bytes we should use for initiating the
6589 //      tunnel
6590 //
6591 int64_t
server_transfer_init(MIOBuffer * buf,int hdr_size)6592 HttpSM::server_transfer_init(MIOBuffer *buf, int hdr_size)
6593 {
6594   int64_t nbytes;
6595   int64_t to_copy = INT64_MAX;
6596 
6597   ink_assert(t_state.current.server != nullptr); // should have been set up if we're doing a transfer.
6598 
6599   if (server_entry->eos == true) {
6600     // The server has shutdown on us already so the only data
6601     //  we'll get is already in the buffer
6602     nbytes = server_buffer_reader->read_avail() + hdr_size;
6603   } else if (t_state.hdr_info.response_content_length == HTTP_UNDEFINED_CL) {
6604     nbytes = -1;
6605   } else {
6606     //  Set to copy to the number of bytes we want to write as
6607     //  if the server is sending us a bogus response we have to
6608     //  truncate it as we've already decided to trust the content
6609     //  length
6610     to_copy = t_state.hdr_info.response_content_length;
6611     nbytes  = t_state.hdr_info.response_content_length + hdr_size;
6612   }
6613 
6614   // Next order of business if copy the remaining data from the header buffer into new buffer.
6615   int64_t server_response_pre_read_bytes = buf->write(server_buffer_reader, to_copy);
6616   server_buffer_reader->consume(server_response_pre_read_bytes);
6617 
6618   //  If we know the length & copied the entire body
6619   //   of the document out of the header buffer make
6620   //   sure the server isn't screwing us by having sent too
6621   //   much.  If it did, we want to close the server connection
6622   if (server_response_pre_read_bytes == to_copy && server_buffer_reader->read_avail() > 0) {
6623     t_state.current.server->keep_alive = HTTP_NO_KEEPALIVE;
6624   }
6625 
6626   return nbytes;
6627 }
6628 
6629 HttpTunnelProducer *
setup_server_transfer_to_transform()6630 HttpSM::setup_server_transfer_to_transform()
6631 {
6632   int64_t alloc_index;
6633   int64_t nbytes;
6634 
6635   alloc_index               = find_server_buffer_size();
6636   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6637   IOBufferReader *buf_start = buf->alloc_reader();
6638   nbytes                    = server_transfer_init(buf, 0);
6639 
6640   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_response_wait_for_transform_read);
6641 
6642   HttpTunnelProducer *p =
6643     tunnel.add_producer(server_entry->vc, nbytes, buf_start, &HttpSM::tunnel_handler_server, HT_HTTP_SERVER, "http server");
6644 
6645   tunnel.add_consumer(transform_info.vc, server_entry->vc, &HttpSM::tunnel_handler_transform_write, HT_TRANSFORM,
6646                       "transform write");
6647 
6648   server_entry->in_tunnel         = true;
6649   transform_info.entry->in_tunnel = true;
6650 
6651   if (t_state.current.server->transfer_encoding == HttpTransact::CHUNKED_ENCODING) {
6652     client_response_hdr_bytes = 0; // fixed by YTS Team, yamsat
6653     tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_DECHUNK_CONTENT);
6654   }
6655 
6656   return p;
6657 }
6658 
6659 HttpTunnelProducer *
setup_transfer_from_transform()6660 HttpSM::setup_transfer_from_transform()
6661 {
6662   int64_t alloc_index = find_server_buffer_size();
6663 
6664   // TODO change this call to new_empty_MIOBuffer()
6665   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6666   buf->water_mark           = static_cast<int>(t_state.txn_conf->default_buffer_water_mark);
6667   IOBufferReader *buf_start = buf->alloc_reader();
6668 
6669   HttpTunnelConsumer *c = tunnel.get_consumer(transform_info.vc);
6670   ink_assert(c != nullptr);
6671   ink_assert(c->vc == transform_info.vc);
6672   ink_assert(c->vc_type == HT_TRANSFORM);
6673 
6674   // Now dump the header into the buffer
6675   ink_assert(t_state.hdr_info.client_response.status_get() != HTTP_STATUS_NOT_MODIFIED);
6676   client_response_hdr_bytes = write_response_header_into_buffer(&t_state.hdr_info.client_response, buf);
6677 
6678   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6679 
6680   HttpTunnelProducer *p = tunnel.add_producer(transform_info.vc, INT64_MAX, buf_start, &HttpSM::tunnel_handler_transform_read,
6681                                               HT_TRANSFORM, "transform read");
6682   tunnel.chain(c, p);
6683 
6684   tunnel.add_consumer(ua_entry->vc, transform_info.vc, &HttpSM::tunnel_handler_ua, HT_HTTP_CLIENT, "user agent");
6685 
6686   transform_info.entry->in_tunnel = true;
6687   ua_entry->in_tunnel             = true;
6688 
6689   this->setup_plugin_agents(p);
6690 
6691   if (t_state.client_info.receive_chunked_response) {
6692     tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT);
6693     tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size);
6694   }
6695 
6696   return p;
6697 }
6698 
6699 HttpTunnelProducer *
setup_transfer_from_transform_to_cache_only()6700 HttpSM::setup_transfer_from_transform_to_cache_only()
6701 {
6702   int64_t alloc_index       = find_server_buffer_size();
6703   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6704   IOBufferReader *buf_start = buf->alloc_reader();
6705 
6706   HttpTunnelConsumer *c = tunnel.get_consumer(transform_info.vc);
6707   ink_assert(c != nullptr);
6708   ink_assert(c->vc == transform_info.vc);
6709   ink_assert(c->vc_type == HT_TRANSFORM);
6710 
6711   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6712 
6713   HttpTunnelProducer *p = tunnel.add_producer(transform_info.vc, INT64_MAX, buf_start, &HttpSM::tunnel_handler_transform_read,
6714                                               HT_TRANSFORM, "transform read");
6715   tunnel.chain(c, p);
6716 
6717   transform_info.entry->in_tunnel = true;
6718 
6719   ink_assert(t_state.cache_info.transform_action == HttpTransact::CACHE_DO_WRITE);
6720 
6721   perform_transform_cache_write_action();
6722 
6723   return p;
6724 }
6725 
6726 void
setup_server_transfer_to_cache_only()6727 HttpSM::setup_server_transfer_to_cache_only()
6728 {
6729   TunnelChunkingAction_t action;
6730   int64_t alloc_index;
6731   int64_t nbytes;
6732 
6733   alloc_index               = find_server_buffer_size();
6734   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6735   IOBufferReader *buf_start = buf->alloc_reader();
6736 
6737   action = (t_state.current.server && t_state.current.server->transfer_encoding == HttpTransact::CHUNKED_ENCODING) ?
6738              TCA_DECHUNK_CONTENT :
6739              TCA_PASSTHRU_DECHUNKED_CONTENT;
6740 
6741   nbytes = server_transfer_init(buf, 0);
6742 
6743   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6744 
6745   HttpTunnelProducer *p =
6746     tunnel.add_producer(server_entry->vc, nbytes, buf_start, &HttpSM::tunnel_handler_server, HT_HTTP_SERVER, "http server");
6747 
6748   tunnel.set_producer_chunking_action(p, 0, action);
6749   tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size);
6750 
6751   setup_cache_write_transfer(&cache_sm, server_entry->vc, &t_state.cache_info.object_store, 0, "cache write");
6752 
6753   server_entry->in_tunnel = true;
6754 }
6755 
6756 HttpTunnelProducer *
setup_server_transfer()6757 HttpSM::setup_server_transfer()
6758 {
6759   SMDebug("http", "Setup Server Transfer");
6760   int64_t alloc_index, hdr_size;
6761   int64_t nbytes;
6762 
6763   alloc_index = find_server_buffer_size();
6764 #ifndef USE_NEW_EMPTY_MIOBUFFER
6765   MIOBuffer *buf = new_MIOBuffer(alloc_index);
6766 #else
6767   MIOBuffer *buf = new_empty_MIOBuffer(alloc_index);
6768   buf->append_block(HTTP_HEADER_BUFFER_SIZE_INDEX);
6769 #endif
6770   buf->water_mark           = static_cast<int>(t_state.txn_conf->default_buffer_water_mark);
6771   IOBufferReader *buf_start = buf->alloc_reader();
6772 
6773   // we need to know if we are going to chunk the response or not
6774   // before we write the response header into buffer
6775   TunnelChunkingAction_t action;
6776   if (t_state.client_info.receive_chunked_response == false) {
6777     if (t_state.current.server->transfer_encoding == HttpTransact::CHUNKED_ENCODING) {
6778       action = TCA_DECHUNK_CONTENT;
6779     } else {
6780       action = TCA_PASSTHRU_DECHUNKED_CONTENT;
6781     }
6782   } else {
6783     if (t_state.current.server->transfer_encoding != HttpTransact::CHUNKED_ENCODING) {
6784       if (t_state.client_info.http_version == HTTP_0_9) {
6785         action = TCA_PASSTHRU_DECHUNKED_CONTENT; // send as-is
6786       } else {
6787         action = TCA_CHUNK_CONTENT;
6788       }
6789     } else {
6790       action = TCA_PASSTHRU_CHUNKED_CONTENT;
6791     }
6792   }
6793   if (action == TCA_CHUNK_CONTENT || action == TCA_PASSTHRU_CHUNKED_CONTENT) { // remove Content-Length
6794     t_state.hdr_info.client_response.field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
6795   }
6796   // Now dump the header into the buffer
6797   ink_assert(t_state.hdr_info.client_response.status_get() != HTTP_STATUS_NOT_MODIFIED);
6798   client_response_hdr_bytes = hdr_size = write_response_header_into_buffer(&t_state.hdr_info.client_response, buf);
6799 
6800   nbytes = server_transfer_init(buf, hdr_size);
6801 
6802   if (t_state.is_cacheable_due_to_negative_caching_configuration &&
6803       t_state.hdr_info.server_response.status_get() == HTTP_STATUS_NO_CONTENT) {
6804     int s = sizeof("No Content") - 1;
6805     buf->write("No Content", s);
6806     nbytes += s;
6807   }
6808 
6809   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6810 
6811   HttpTunnelProducer *p =
6812     tunnel.add_producer(server_entry->vc, nbytes, buf_start, &HttpSM::tunnel_handler_server, HT_HTTP_SERVER, "http server");
6813 
6814   tunnel.add_consumer(ua_entry->vc, server_entry->vc, &HttpSM::tunnel_handler_ua, HT_HTTP_CLIENT, "user agent");
6815 
6816   ua_entry->in_tunnel     = true;
6817   server_entry->in_tunnel = true;
6818 
6819   this->setup_plugin_agents(p);
6820 
6821   // If the incoming server response is chunked and the client does not
6822   // expect a chunked response, then dechunk it.  Otherwise, if the
6823   // incoming response is not chunked and the client expects a chunked
6824   // response, then chunk it.
6825   /*
6826      // this block is moved up so that we know if we need to remove
6827      // Content-Length field from response header before writing the
6828      // response header into buffer bz50730
6829      TunnelChunkingAction_t action;
6830      if (t_state.client_info.receive_chunked_response == false) {
6831      if (t_state.current.server->transfer_encoding ==
6832      HttpTransact::CHUNKED_ENCODING)
6833      action = TCA_DECHUNK_CONTENT;
6834      else action = TCA_PASSTHRU_DECHUNKED_CONTENT;
6835      }
6836      else {
6837      if (t_state.current.server->transfer_encoding !=
6838      HttpTransact::CHUNKED_ENCODING)
6839      action = TCA_CHUNK_CONTENT;
6840      else action = TCA_PASSTHRU_CHUNKED_CONTENT;
6841      }
6842    */
6843   tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, action);
6844   tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size);
6845   return p;
6846 }
6847 
6848 HttpTunnelProducer *
setup_push_transfer_to_cache()6849 HttpSM::setup_push_transfer_to_cache()
6850 {
6851   int64_t nbytes, alloc_index;
6852 
6853   alloc_index               = find_http_resp_buffer_size(t_state.hdr_info.request_content_length);
6854   MIOBuffer *buf            = new_MIOBuffer(alloc_index);
6855   IOBufferReader *buf_start = buf->alloc_reader();
6856 
6857   ink_release_assert(t_state.hdr_info.request_content_length != HTTP_UNDEFINED_CL);
6858   nbytes = t_state.hdr_info.request_content_length - pushed_response_hdr_bytes;
6859   ink_release_assert(nbytes >= 0);
6860 
6861   if (ua_entry->eos == true) {
6862     // The ua has shutdown on us already so the only data
6863     //  we'll get is already in the buffer.  Make sure it
6864     //  fulfills the stated length
6865     int64_t avail = ua_buffer_reader->read_avail();
6866 
6867     if (avail < nbytes) {
6868       // Client failed to send the body, it's gone.  Kill the
6869       // state machine
6870       terminate_sm = true;
6871       return nullptr;
6872     }
6873   }
6874   // Next order of business is copy the remaining data from the
6875   //  header buffer into new buffer.
6876   pushed_response_body_bytes = buf->write(ua_buffer_reader, nbytes);
6877   ua_buffer_reader->consume(pushed_response_body_bytes);
6878   client_request_body_bytes += pushed_response_body_bytes;
6879 
6880   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler_push);
6881 
6882   HttpTunnelProducer *p =
6883     tunnel.add_producer(ua_entry->vc, nbytes, buf_start, &HttpSM::tunnel_handler_ua_push, HT_HTTP_CLIENT, "user_agent");
6884   setup_cache_write_transfer(&cache_sm, ua_entry->vc, &t_state.cache_info.object_store, 0, "cache write");
6885 
6886   ua_entry->in_tunnel = true;
6887   return p;
6888 }
6889 
6890 void
setup_blind_tunnel(bool send_response_hdr,IOBufferReader * initial)6891 HttpSM::setup_blind_tunnel(bool send_response_hdr, IOBufferReader *initial)
6892 {
6893   HttpTunnelConsumer *c_ua;
6894   HttpTunnelConsumer *c_os;
6895   HttpTunnelProducer *p_ua;
6896   HttpTunnelProducer *p_os;
6897   MIOBuffer *from_ua_buf = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
6898   MIOBuffer *to_ua_buf   = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
6899   IOBufferReader *r_from = from_ua_buf->alloc_reader();
6900   IOBufferReader *r_to   = to_ua_buf->alloc_reader();
6901 
6902   milestones[TS_MILESTONE_SERVER_BEGIN_WRITE] = Thread::get_hrtime();
6903   if (send_response_hdr) {
6904     client_response_hdr_bytes = write_response_header_into_buffer(&t_state.hdr_info.client_response, to_ua_buf);
6905     if (initial && initial->read_avail()) {
6906       int64_t avail = initial->read_avail();
6907       to_ua_buf->write(initial, avail);
6908       initial->consume(avail);
6909     }
6910   } else {
6911     client_response_hdr_bytes = 0;
6912   }
6913 
6914   client_request_body_bytes = 0;
6915   if (ua_raw_buffer_reader != nullptr) {
6916     client_request_body_bytes += from_ua_buf->write(ua_raw_buffer_reader, client_request_hdr_bytes);
6917     ua_raw_buffer_reader->dealloc();
6918     ua_raw_buffer_reader = nullptr;
6919   }
6920 
6921   // Next order of business if copy the remaining data from the
6922   //  header buffer into new buffer
6923   client_request_body_bytes += from_ua_buf->write(ua_buffer_reader);
6924 
6925   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::tunnel_handler);
6926 
6927   p_os =
6928     tunnel.add_producer(server_entry->vc, -1, r_to, &HttpSM::tunnel_handler_ssl_producer, HT_HTTP_SERVER, "http server - tunnel");
6929 
6930   c_ua = tunnel.add_consumer(ua_entry->vc, server_entry->vc, &HttpSM::tunnel_handler_ssl_consumer, HT_HTTP_CLIENT,
6931                              "user agent - tunnel");
6932 
6933   p_ua = tunnel.add_producer(ua_entry->vc, -1, r_from, &HttpSM::tunnel_handler_ssl_producer, HT_HTTP_CLIENT, "user agent - tunnel");
6934 
6935   c_os = tunnel.add_consumer(server_entry->vc, ua_entry->vc, &HttpSM::tunnel_handler_ssl_consumer, HT_HTTP_SERVER,
6936                              "http server - tunnel");
6937 
6938   // Make the tunnel aware that the entries are bi-directional
6939   tunnel.chain(c_os, p_os);
6940   tunnel.chain(c_ua, p_ua);
6941 
6942   ua_entry->in_tunnel     = true;
6943   server_entry->in_tunnel = true;
6944 
6945   tunnel.tunnel_run();
6946 
6947   // If we're half closed, we got a FIN from the client. Forward it on to the origin server
6948   // now that we have the tunnel operational.
6949   if (ua_txn && ua_txn->get_half_close_flag()) {
6950     p_ua->vc->do_io_shutdown(IO_SHUTDOWN_READ);
6951   }
6952 }
6953 
6954 void
setup_plugin_agents(HttpTunnelProducer * p)6955 HttpSM::setup_plugin_agents(HttpTunnelProducer *p)
6956 {
6957   APIHook *agent           = txn_hook_get(TS_HTTP_RESPONSE_CLIENT_HOOK);
6958   has_active_plugin_agents = agent != nullptr;
6959   while (agent) {
6960     INKVConnInternal *contp = static_cast<INKVConnInternal *>(agent->m_cont);
6961     tunnel.add_consumer(contp, p->vc, &HttpSM::tunnel_handler_plugin_agent, HT_HTTP_CLIENT, "plugin agent");
6962     // We don't put these in the SM VC table because the tunnel
6963     // will clean them up in do_io_close().
6964     agent = agent->next();
6965   }
6966 }
6967 
6968 inline void
transform_cleanup(TSHttpHookID hook,HttpTransformInfo * info)6969 HttpSM::transform_cleanup(TSHttpHookID hook, HttpTransformInfo *info)
6970 {
6971   APIHook *t_hook = api_hooks.get(hook);
6972   if (t_hook && info->vc == nullptr) {
6973     do {
6974       VConnection *t_vcon = t_hook->m_cont;
6975       t_vcon->do_io_close();
6976       t_hook = t_hook->m_link.next;
6977     } while (t_hook != nullptr);
6978   }
6979 }
6980 
6981 void
plugin_agents_cleanup()6982 HttpSM::plugin_agents_cleanup()
6983 {
6984   // If this is set then all of the plugin agent VCs were put in
6985   // the VC table and cleaned up there. This handles the case where
6986   // something went wrong early.
6987   if (!has_active_plugin_agents) {
6988     APIHook *agent = txn_hook_get(TS_HTTP_RESPONSE_CLIENT_HOOK);
6989     while (agent) {
6990       INKVConnInternal *contp = static_cast<INKVConnInternal *>(agent->m_cont);
6991       contp->do_io_close();
6992       agent = agent->next();
6993     }
6994   }
6995 }
6996 
6997 //////////////////////////////////////////////////////////////////////////
6998 //
6999 //  HttpSM::kill_this()
7000 //
7001 //  This function has two phases.  One before we call the asynchronous
7002 //    clean up routines (api and list removal) and one after.
7003 //    The state about which phase we are in is kept in
7004 //    HttpSM::kill_this_async_done
7005 //
7006 //////////////////////////////////////////////////////////////////////////
7007 void
kill_this()7008 HttpSM::kill_this()
7009 {
7010   ink_release_assert(reentrancy_count == 1);
7011   this->postbuf_clear();
7012   enable_redirection = false;
7013 
7014   if (kill_this_async_done == false) {
7015     ////////////////////////////////
7016     // cancel uncompleted actions //
7017     ////////////////////////////////
7018     // The action should be cancelled only if
7019     // the state machine is in HTTP_API_NO_CALLOUT
7020     // state. This is because we are depending on the
7021     // callout to complete for the state machine to
7022     // get killed.
7023     if (callout_state == HTTP_API_NO_CALLOUT && !pending_action.is_empty()) {
7024       pending_action = nullptr;
7025     } else if (!pending_action.is_empty()) {
7026       ink_assert(pending_action.is_empty());
7027     }
7028 
7029     cache_sm.end_both();
7030     transform_cache_sm.end_both();
7031     vc_table.cleanup_all();
7032 
7033     // tunnel.deallocate_buffers();
7034     // Why don't we just kill the tunnel?  Might still be
7035     // active if the state machine is going down hard,
7036     // and we should clean it up.
7037     tunnel.kill_tunnel();
7038 
7039     // It possible that a plugin added transform hook
7040     //   but the hook never executed due to a client abort
7041     //   In that case, we need to manually close all the
7042     //   transforms to prevent memory leaks (INKqa06147)
7043     if (hooks_set) {
7044       transform_cleanup(TS_HTTP_RESPONSE_TRANSFORM_HOOK, &transform_info);
7045       transform_cleanup(TS_HTTP_REQUEST_TRANSFORM_HOOK, &post_transform_info);
7046       plugin_agents_cleanup();
7047     }
7048     // It's also possible that the plugin_tunnel vc was never
7049     //   executed due to not contacting the server
7050     if (plugin_tunnel) {
7051       plugin_tunnel->kill_no_connect();
7052       plugin_tunnel = nullptr;
7053     }
7054 
7055     server_session = nullptr;
7056 
7057     // So we don't try to nuke the state machine
7058     //  if the plugin receives event we must reset
7059     //  the terminate_flag
7060     terminate_sm            = false;
7061     t_state.api_next_action = HttpTransact::SM_ACTION_API_SM_SHUTDOWN;
7062     if (do_api_callout() < 0) { // Failed to get a continuation lock
7063       // Need to hang out until we can complete the TXN_CLOSE hook
7064       terminate_sm = false;
7065       reentrancy_count--;
7066       return;
7067     }
7068   }
7069   // The reentrancy_count is still valid up to this point since
7070   //   the api shutdown hook is asynchronous and double frees can
7071   //   happen if the reentrancy count is not still valid until
7072   //   after all asynch callouts have completed
7073   //
7074   // Once we get to this point, we could be waiting for async
7075   //   completion in which case we need to decrement the reentrancy
7076   //   count since the entry points can't do it for us since they
7077   //   don't know if the state machine has been destroyed.  In the
7078   //   case we really are done with asynch callouts, decrement the
7079   //   reentrancy count since it seems tacky to destruct a state
7080   //   machine with non-zero count
7081   reentrancy_count--;
7082   ink_release_assert(reentrancy_count == 0);
7083 
7084   // If the api shutdown & list removal was synchronous
7085   //   then the value of kill_this_async_done has changed so
7086   //   we must check it again
7087   if (kill_this_async_done == true) {
7088     pending_action = nullptr;
7089     if (t_state.http_config_param->enable_http_stats) {
7090       update_stats();
7091     }
7092 
7093     //////////////
7094     // Log Data //
7095     //////////////
7096     SMDebug("http_seq", "[HttpSM::update_stats] Logging transaction");
7097     if (Log::transaction_logging_enabled() && t_state.api_info.logging_enabled) {
7098       LogAccess accessor(this);
7099 
7100       int ret = Log::access(&accessor);
7101 
7102       if (ret & Log::FULL) {
7103         SMDebug("http", "[update_stats] Logging system indicates FULL.");
7104       }
7105       if (ret & Log::FAIL) {
7106         Log::error("failed to log transaction for at least one log object");
7107       }
7108     }
7109 
7110     if (ua_txn) {
7111       ua_txn->transaction_done();
7112     }
7113 
7114     // In the async state, the plugin could have been
7115     // called resulting in the creation of a plugin_tunnel.
7116     // So it needs to be deleted now.
7117     if (plugin_tunnel) {
7118       plugin_tunnel->kill_no_connect();
7119       plugin_tunnel = nullptr;
7120     }
7121 
7122     ink_assert(pending_action.is_empty());
7123     ink_release_assert(vc_table.is_table_clear() == true);
7124     ink_release_assert(tunnel.is_tunnel_active() == false);
7125 
7126     HTTP_SM_SET_DEFAULT_HANDLER(nullptr);
7127 
7128     if (redirect_url != nullptr) {
7129       ats_free((void *)redirect_url);
7130       redirect_url     = nullptr;
7131       redirect_url_len = 0;
7132     }
7133 
7134 #ifdef USE_HTTP_DEBUG_LISTS
7135     ink_mutex_acquire(&debug_sm_list_mutex);
7136     debug_sm_list.remove(this);
7137     ink_mutex_release(&debug_sm_list_mutex);
7138 #endif
7139 
7140     SMDebug("http", "[%" PRId64 "] deallocating sm", sm_id);
7141     destroy();
7142   }
7143 }
7144 
7145 void
update_stats()7146 HttpSM::update_stats()
7147 {
7148   milestones[TS_MILESTONE_SM_FINISH] = Thread::get_hrtime();
7149 
7150   if (is_action_tag_set("bad_length_state_dump")) {
7151     if (t_state.hdr_info.client_response.valid() && t_state.hdr_info.client_response.status_get() == HTTP_STATUS_OK) {
7152       int64_t p_resp_cl = t_state.hdr_info.client_response.get_content_length();
7153       int64_t resp_size = client_response_body_bytes;
7154       if (!((p_resp_cl == -1 || p_resp_cl == resp_size || resp_size == 0))) {
7155         Error("[%" PRId64 "] Truncated content detected", sm_id);
7156         dump_state_on_assert();
7157       }
7158     } else if (client_request_hdr_bytes == 0) {
7159       Error("[%" PRId64 "] Zero length request header received", sm_id);
7160       dump_state_on_assert();
7161     }
7162   }
7163 
7164   if (is_action_tag_set("assert_jtest_length")) {
7165     if (t_state.hdr_info.client_response.valid() && t_state.hdr_info.client_response.status_get() == HTTP_STATUS_OK) {
7166       int64_t p_resp_cl = t_state.hdr_info.client_response.get_content_length();
7167       int64_t resp_size = client_response_body_bytes;
7168       ink_release_assert(p_resp_cl == -1 || p_resp_cl == resp_size || resp_size == 0);
7169     }
7170   }
7171 
7172   ink_hrtime total_time = milestones.elapsed(TS_MILESTONE_SM_START, TS_MILESTONE_SM_FINISH);
7173 
7174   // ua_close will not be assigned properly in some exceptional situation.
7175   // TODO: Assign ua_close with suitable value when HttpTunnel terminates abnormally.
7176   if (milestones[TS_MILESTONE_UA_CLOSE] == 0 && milestones[TS_MILESTONE_UA_READ_HEADER_DONE] > 0) {
7177     milestones[TS_MILESTONE_UA_CLOSE] = Thread::get_hrtime();
7178   }
7179 
7180   // request_process_time  = The time after the header is parsed to the completion of the transaction
7181   ink_hrtime request_process_time = milestones[TS_MILESTONE_UA_CLOSE] - milestones[TS_MILESTONE_UA_READ_HEADER_DONE];
7182 
7183   HttpTransact::client_result_stat(&t_state, total_time, request_process_time);
7184 
7185   ink_hrtime ua_write_time;
7186   if (milestones[TS_MILESTONE_UA_BEGIN_WRITE] != 0 && milestones[TS_MILESTONE_UA_CLOSE] != 0) {
7187     ua_write_time = milestones.elapsed(TS_MILESTONE_UA_BEGIN_WRITE, TS_MILESTONE_UA_CLOSE);
7188   } else {
7189     ua_write_time = -1;
7190   }
7191 
7192   ink_hrtime os_read_time;
7193   if (milestones[TS_MILESTONE_SERVER_READ_HEADER_DONE] != 0 && milestones[TS_MILESTONE_SERVER_CLOSE] != 0) {
7194     os_read_time = milestones.elapsed(TS_MILESTONE_SERVER_READ_HEADER_DONE, TS_MILESTONE_SERVER_CLOSE);
7195   } else {
7196     os_read_time = -1;
7197   }
7198 
7199   HttpTransact::update_size_and_time_stats(
7200     &t_state, total_time, ua_write_time, os_read_time, client_request_hdr_bytes, client_request_body_bytes,
7201     client_response_hdr_bytes, client_response_body_bytes, server_request_hdr_bytes, server_request_body_bytes,
7202     server_response_hdr_bytes, server_response_body_bytes, pushed_response_hdr_bytes, pushed_response_body_bytes, milestones);
7203   /*
7204       if (is_action_tag_set("http_handler_times")) {
7205           print_all_http_handler_times();
7206       }
7207   */
7208 
7209   // print slow requests if the threshold is set (> 0) and if we are over the time threshold
7210   if (t_state.txn_conf->slow_log_threshold != 0 && ink_hrtime_from_msec(t_state.txn_conf->slow_log_threshold) < total_time) {
7211     char url_string[256] = "";
7212     int offset           = 0;
7213     int skip             = 0;
7214 
7215     t_state.hdr_info.client_request.url_print(url_string, sizeof(url_string) - 1, &offset, &skip);
7216     url_string[offset] = 0; // NULL terminate the string
7217 
7218     // unique id
7219     char unique_id_string[128] = "";
7220     int length                 = 0;
7221     const char *field          = t_state.hdr_info.client_request.value_get(MIME_FIELD_X_ID, MIME_LEN_X_ID, &length);
7222     if (field != nullptr && length > 0) {
7223       length = std::min(length, static_cast<int>(sizeof(unique_id_string)) - 1);
7224       memcpy(unique_id_string, field, length);
7225       unique_id_string[length] = 0; // NULL terminate the string
7226     }
7227 
7228     // set the fd for the request
7229     int fd             = 0;
7230     NetVConnection *vc = nullptr;
7231     if (ua_txn != nullptr) {
7232       vc = ua_txn->get_netvc();
7233       if (vc != nullptr) {
7234         fd = vc->get_socket();
7235       } else {
7236         fd = -1;
7237       }
7238     }
7239     // get the status code, lame that we have to check to see if it is valid or we will assert in the method call
7240     int status = 0;
7241     if (t_state.hdr_info.client_response.valid()) {
7242       status = t_state.hdr_info.client_response.status_get();
7243     }
7244     char client_ip[INET6_ADDRSTRLEN];
7245     ats_ip_ntop(&t_state.client_info.src_addr, client_ip, sizeof(client_ip));
7246     Error("[%" PRId64 "] Slow Request: "
7247           "client_ip: %s:%u "
7248           "protocol: %s "
7249           "url: %s "
7250           "status: %d "
7251           "unique id: %s "
7252           "redirection_tries: %d "
7253           "bytes: %" PRId64 " "
7254           "fd: %d "
7255           "client state: %d "
7256           "server state: %d "
7257           "tls_handshake: %.3f "
7258           "ua_begin: %.3f "
7259           "ua_first_read: %.3f "
7260           "ua_read_header_done: %.3f "
7261           "cache_open_read_begin: %.3f "
7262           "cache_open_read_end: %.3f "
7263           "cache_open_write_begin: %.3f "
7264           "cache_open_write_end: %.3f "
7265           "dns_lookup_begin: %.3f "
7266           "dns_lookup_end: %.3f "
7267           "server_connect: %.3f "
7268           "server_connect_end: %.3f "
7269           "server_first_read: %.3f "
7270           "server_read_header_done: %.3f "
7271           "server_close: %.3f "
7272           "ua_write: %.3f "
7273           "ua_close: %.3f "
7274           "sm_finish: %.3f "
7275           "plugin_active: %.3f "
7276           "plugin_total: %.3f",
7277           sm_id, client_ip, t_state.client_info.src_addr.host_order_port(), ua_txn ? ua_txn->get_protocol_string() : "-1",
7278           url_string, status, unique_id_string, redirection_tries, client_response_body_bytes, fd, t_state.client_info.state,
7279           t_state.server_info.state, milestones.difference_sec(TS_MILESTONE_TLS_HANDSHAKE_START, TS_MILESTONE_TLS_HANDSHAKE_END),
7280           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_UA_BEGIN),
7281           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_UA_FIRST_READ),
7282           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_UA_READ_HEADER_DONE),
7283           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_CACHE_OPEN_READ_BEGIN),
7284           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_CACHE_OPEN_READ_END),
7285           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_CACHE_OPEN_WRITE_BEGIN),
7286           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_CACHE_OPEN_WRITE_END),
7287           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_DNS_LOOKUP_BEGIN),
7288           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_DNS_LOOKUP_END),
7289           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SERVER_CONNECT),
7290           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SERVER_CONNECT_END),
7291           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SERVER_FIRST_READ),
7292           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SERVER_READ_HEADER_DONE),
7293           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SERVER_CLOSE),
7294           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_UA_BEGIN_WRITE),
7295           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_UA_CLOSE),
7296           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SM_FINISH),
7297           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_PLUGIN_ACTIVE),
7298           milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_PLUGIN_TOTAL));
7299   }
7300 }
7301 
7302 //
7303 // void HttpSM::dump_state_on_assert
7304 //    Debugging routine to dump the state machine's history
7305 //     and other state on an assertion failure
7306 //    We use Diags::Status instead of stderr since
7307 //     Diags works both on UNIX & NT
7308 //
7309 void
dump_state_on_assert()7310 HttpSM::dump_state_on_assert()
7311 {
7312   Error("[%" PRId64 "] ------- begin http state dump -------", sm_id);
7313 
7314   if (history.overflowed()) {
7315     Error("   History Wrap around. history size: %d", history.size());
7316   }
7317   // Loop through the history and dump it
7318   for (unsigned int i = 0; i < history.size(); i++) {
7319     char buf[256];
7320     int r = history[i].reentrancy;
7321     int e = history[i].event;
7322     Error("%d   %d   %s", e, r, history[i].location.str(buf, sizeof(buf)));
7323   }
7324 
7325   // Dump the via string
7326   Error("Via String: [%s]\n", t_state.via_string);
7327 
7328   // Dump header info
7329   dump_state_hdr(&t_state.hdr_info.client_request, "Client Request");
7330   dump_state_hdr(&t_state.hdr_info.server_request, "Server Request");
7331   dump_state_hdr(&t_state.hdr_info.server_response, "Server Response");
7332   dump_state_hdr(&t_state.hdr_info.transform_response, "Transform Response");
7333   dump_state_hdr(&t_state.hdr_info.client_response, "Client Response");
7334 
7335   Error("[%" PRId64 "] ------- end http state dump ---------", sm_id);
7336 }
7337 
7338 void
dump_state_hdr(HTTPHdr * h,const char * s)7339 HttpSM::dump_state_hdr(HTTPHdr *h, const char *s)
7340 {
7341   // Dump the client request if available
7342   if (h->valid()) {
7343     int l         = h->length_get();
7344     char *hdr_buf = static_cast<char *>(ats_malloc(l + 1));
7345     int index     = 0;
7346     int offset    = 0;
7347 
7348     h->print(hdr_buf, l, &index, &offset);
7349 
7350     hdr_buf[l] = '\0';
7351     Error("  ----  %s [%" PRId64 "] ----\n%s\n", s, sm_id, hdr_buf);
7352     ats_free(hdr_buf);
7353   }
7354 }
7355 
7356 /*****************************************************************************
7357  *****************************************************************************
7358  ****                                                                     ****
7359  ****                       HttpTransact Interface                        ****
7360  ****                                                                     ****
7361  *****************************************************************************
7362  *****************************************************************************/
7363 //////////////////////////////////////////////////////////////////////////
7364 //
7365 //      HttpSM::call_transact_and_set_next_state(f)
7366 //
7367 //      This routine takes an HttpTransact function <f>, calls the function
7368 //      to perform some actions on the current HttpTransact::State, and
7369 //      then uses the HttpTransact return action code to set the next
7370 //      handler (state) for the state machine.  HttpTransact could have
7371 //      returned the handler directly, but returns action codes in hopes of
7372 //      making a cleaner separation between the state machine and the
7373 //      HttpTransact logic.
7374 //
7375 //////////////////////////////////////////////////////////////////////////
7376 
7377 // Where is the goatherd?
7378 
7379 void
call_transact_and_set_next_state(TransactEntryFunc_t f)7380 HttpSM::call_transact_and_set_next_state(TransactEntryFunc_t f)
7381 {
7382   last_action = t_state.next_action; // remember where we were
7383 
7384   // The callee can either specify a method to call in to Transact,
7385   //   or call with NULL which indicates that Transact should use
7386   //   its stored entry point.
7387   if (f == nullptr) {
7388     ink_release_assert(t_state.transact_return_point != nullptr);
7389     t_state.transact_return_point(&t_state);
7390   } else {
7391     f(&t_state);
7392   }
7393 
7394   SMDebug("http", "[%" PRId64 "] State Transition: %s -> %s", sm_id, HttpDebugNames::get_action_name(last_action),
7395           HttpDebugNames::get_action_name(t_state.next_action));
7396 
7397   set_next_state();
7398 
7399   return;
7400 }
7401 
7402 //////////////////////////////////////////////////////////////////////////////
7403 //
7404 //  HttpSM::set_next_state()
7405 //
7406 //  call_transact_and_set_next_state() was broken into two parts, one
7407 //  which calls the HttpTransact method and the second which sets the
7408 //  next state. In a case which set_next_state() was not completed,
7409 //  the state function calls set_next_state() to retry setting the
7410 //  state.
7411 //
7412 //////////////////////////////////////////////////////////////////////////////
7413 void
set_next_state()7414 HttpSM::set_next_state()
7415 {
7416   ///////////////////////////////////////////////////////////////////////
7417   // Use the returned "next action" code to set the next state handler //
7418   ///////////////////////////////////////////////////////////////////////
7419   switch (t_state.next_action) {
7420   case HttpTransact::SM_ACTION_API_PRE_REMAP:
7421   case HttpTransact::SM_ACTION_API_POST_REMAP:
7422   case HttpTransact::SM_ACTION_API_READ_REQUEST_HDR:
7423   case HttpTransact::SM_ACTION_REQUEST_BUFFER_READ_COMPLETE:
7424   case HttpTransact::SM_ACTION_API_OS_DNS:
7425   case HttpTransact::SM_ACTION_API_SEND_REQUEST_HDR:
7426   case HttpTransact::SM_ACTION_API_READ_CACHE_HDR:
7427   case HttpTransact::SM_ACTION_API_READ_RESPONSE_HDR:
7428   case HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR:
7429   case HttpTransact::SM_ACTION_API_CACHE_LOOKUP_COMPLETE: {
7430     t_state.api_next_action = t_state.next_action;
7431     do_api_callout();
7432     break;
7433   }
7434 
7435   case HttpTransact::SM_ACTION_POST_REMAP_SKIP: {
7436     call_transact_and_set_next_state(nullptr);
7437     break;
7438   }
7439 
7440   case HttpTransact::SM_ACTION_REMAP_REQUEST: {
7441     do_remap_request(true); /* run inline */
7442     SMDebug("url_rewrite", "completed inline remapping request for [%" PRId64 "]", sm_id);
7443     t_state.url_remap_success = remapProcessor.finish_remap(&t_state, m_remap);
7444     if (t_state.next_action == HttpTransact::SM_ACTION_SEND_ERROR_CACHE_NOOP && t_state.transact_return_point == nullptr) {
7445       // It appears that we can now set the next_action to error and transact_return_point to nullptr when
7446       // going through do_remap_request presumably due to a plugin setting an error.  In that case, it seems
7447       // that the error message has already been setup, so we can just return and avoid the further
7448       // call_transact_and_set_next_state
7449     } else {
7450       call_transact_and_set_next_state(nullptr);
7451     }
7452     break;
7453   }
7454 
7455   case HttpTransact::SM_ACTION_DNS_LOOKUP: {
7456     sockaddr const *addr;
7457 
7458     if (t_state.api_server_addr_set) {
7459       /* If the API has set the server address before the OS DNS lookup
7460        * then we can skip the lookup
7461        */
7462       ip_text_buffer ipb;
7463       SMDebug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for API supplied target %s.",
7464               ats_ip_ntop(&t_state.server_info.dst_addr, ipb, sizeof(ipb)));
7465       // this seems wasteful as we will just copy it right back
7466       ats_ip_copy(t_state.host_db_info.ip(), &t_state.server_info.dst_addr);
7467       t_state.dns_info.lookup_success = true;
7468       call_transact_and_set_next_state(nullptr);
7469       break;
7470     } else if (0 == ats_ip_pton(t_state.dns_info.lookup_name, t_state.host_db_info.ip()) &&
7471                ats_is_ip_loopback(t_state.host_db_info.ip())) {
7472       // If it's 127.0.0.1 or ::1 don't bother with hostdb
7473       SMDebug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for %s because it's loopback",
7474               t_state.dns_info.lookup_name);
7475       t_state.dns_info.lookup_success = true;
7476       call_transact_and_set_next_state(nullptr);
7477       break;
7478     } else if (t_state.http_config_param->use_client_target_addr == 2 && !t_state.url_remap_success &&
7479                t_state.parent_result.result != PARENT_SPECIFIED && t_state.client_info.is_transparent &&
7480                t_state.dns_info.os_addr_style == HttpTransact::DNSLookupInfo::OS_Addr::OS_ADDR_TRY_DEFAULT &&
7481                ats_is_ip(addr = ua_txn->get_netvc()->get_local_addr())) {
7482       /* If the connection is client side transparent and the URL
7483        * was not remapped/directed to parent proxy, we can use the
7484        * client destination IP address instead of doing a DNS
7485        * lookup. This is controlled by the 'use_client_target_addr'
7486        * configuration parameter.
7487        */
7488       if (is_debug_tag_set("dns")) {
7489         ip_text_buffer ipb;
7490         SMDebug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for client supplied target %s.",
7491                 ats_ip_ntop(addr, ipb, sizeof(ipb)));
7492       }
7493       ats_ip_copy(t_state.host_db_info.ip(), addr);
7494       t_state.host_db_info.app.http_data.http_version = t_state.hdr_info.client_request.version_get();
7495 
7496       t_state.dns_info.lookup_success = true;
7497       // cache this result so we don't have to unreliably duplicate the
7498       // logic later if the connect fails.
7499       t_state.dns_info.os_addr_style = HttpTransact::DNSLookupInfo::OS_Addr::OS_ADDR_TRY_CLIENT;
7500       call_transact_and_set_next_state(nullptr);
7501       break;
7502     } else if (t_state.parent_result.result == PARENT_UNDEFINED && t_state.dns_info.lookup_success) {
7503       // Already set, and we don't have a parent proxy to lookup
7504       ink_assert(ats_is_ip(t_state.host_db_info.ip()));
7505       SMDebug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup, provided by plugin");
7506       call_transact_and_set_next_state(nullptr);
7507       break;
7508     } else if (t_state.dns_info.looking_up == HttpTransact::ORIGIN_SERVER && t_state.http_config_param->no_dns_forward_to_parent &&
7509                t_state.parent_result.result != PARENT_UNDEFINED) {
7510       t_state.dns_info.lookup_success = true;
7511       call_transact_and_set_next_state(nullptr);
7512       break;
7513     }
7514 
7515     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_hostdb_lookup);
7516 
7517     // We need to close the previous attempt
7518     // Because it could be a server side retry by DNS rr
7519     if (server_entry) {
7520       ink_assert(server_entry->vc_type == HTTP_SERVER_VC);
7521       vc_table.cleanup_entry(server_entry);
7522       server_entry   = nullptr;
7523       server_session = nullptr;
7524     } else {
7525       // Now that we have gotten the user agent request, we can cancel
7526       // the inactivity timeout associated with it.  Note, however, that
7527       // we must not cancel the inactivity timeout if the message
7528       // contains a body (as indicated by the non-zero request_content_length
7529       // field).  This indicates that a POST operation is taking place and
7530       // that the client is still sending data to the origin server.  The
7531       // origin server cannot reply until the entire request is received.  In
7532       // light of this dependency, TS must ensure that the client finishes
7533       // sending its request and for this reason, the inactivity timeout
7534       // cannot be cancelled.
7535       if (ua_txn && t_state.hdr_info.request_content_length <= 0) {
7536         ua_txn->cancel_inactivity_timeout();
7537       } else if (!ua_txn) {
7538         terminate_sm = true;
7539         return; // Give up if there is no session
7540       }
7541     }
7542 
7543     ink_assert(t_state.dns_info.looking_up != HttpTransact::UNDEFINED_LOOKUP);
7544     do_hostdb_lookup();
7545     break;
7546   }
7547 
7548   case HttpTransact::SM_ACTION_DNS_REVERSE_LOOKUP: {
7549     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_hostdb_reverse_lookup);
7550     do_hostdb_reverse_lookup();
7551     break;
7552   }
7553 
7554   case HttpTransact::SM_ACTION_CACHE_LOOKUP: {
7555     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_cache_open_read);
7556     do_cache_lookup_and_read();
7557     break;
7558   }
7559 
7560   case HttpTransact::SM_ACTION_ORIGIN_SERVER_OPEN: {
7561     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_http_server_open);
7562 
7563     // We need to close the previous attempt
7564     if (server_entry) {
7565       ink_assert(server_entry->vc_type == HTTP_SERVER_VC);
7566       vc_table.cleanup_entry(server_entry);
7567       server_entry   = nullptr;
7568       server_session = nullptr;
7569     } else {
7570       // Now that we have gotten the user agent request, we can cancel
7571       // the inactivity timeout associated with it.  Note, however, that
7572       // we must not cancel the inactivity timeout if the message
7573       // contains a body (as indicated by the non-zero request_content_length
7574       // field).  This indicates that a POST operation is taking place and
7575       // that the client is still sending data to the origin server.  The
7576       // origin server cannot reply until the entire request is received.  In
7577       // light of this dependency, TS must ensure that the client finishes
7578       // sending its request and for this reason, the inactivity timeout
7579       // cannot be cancelled.
7580       if (ua_txn && t_state.hdr_info.request_content_length <= 0) {
7581         ua_txn->cancel_inactivity_timeout();
7582       } else if (!ua_txn) {
7583         terminate_sm = true;
7584         return; // Give up if there is no session
7585       }
7586     }
7587 
7588     do_http_server_open();
7589     break;
7590   }
7591 
7592   case HttpTransact::SM_ACTION_SERVER_PARSE_NEXT_HDR: {
7593     setup_server_read_response_header();
7594     break;
7595   }
7596 
7597   case HttpTransact::SM_ACTION_INTERNAL_100_RESPONSE: {
7598     setup_100_continue_transfer();
7599     break;
7600   }
7601 
7602   case HttpTransact::SM_ACTION_SERVER_READ: {
7603     t_state.source = HttpTransact::SOURCE_HTTP_ORIGIN_SERVER;
7604 
7605     if (transform_info.vc) {
7606       ink_assert(t_state.hdr_info.client_response.valid() == 0);
7607       ink_assert((t_state.hdr_info.transform_response.valid() ? true : false) == true);
7608       HttpTunnelProducer *p = setup_server_transfer_to_transform();
7609       perform_cache_write_action();
7610       tunnel.tunnel_run(p);
7611     } else {
7612       ink_assert((t_state.hdr_info.client_response.valid() ? true : false) == true);
7613       t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7614 
7615       // check to see if we are going to handle the redirection from server response and if there is a plugin hook set
7616       if (hooks_set && is_redirect_required() == false) {
7617         do_api_callout_internal();
7618       } else {
7619         do_redirect();
7620         handle_api_return();
7621       }
7622     }
7623     break;
7624   }
7625 
7626   case HttpTransact::SM_ACTION_SERVE_FROM_CACHE: {
7627     ink_assert(t_state.cache_info.action == HttpTransact::CACHE_DO_SERVE ||
7628                t_state.cache_info.action == HttpTransact::CACHE_DO_SERVE_AND_DELETE ||
7629                t_state.cache_info.action == HttpTransact::CACHE_DO_SERVE_AND_UPDATE);
7630     release_server_session(true);
7631     t_state.source = HttpTransact::SOURCE_CACHE;
7632 
7633     if (transform_info.vc) {
7634       ink_assert(t_state.hdr_info.client_response.valid() == 0);
7635       ink_assert((t_state.hdr_info.transform_response.valid() ? true : false) == true);
7636       do_drain_request_body(t_state.hdr_info.transform_response);
7637       t_state.hdr_info.cache_response.create(HTTP_TYPE_RESPONSE);
7638       t_state.hdr_info.cache_response.copy(&t_state.hdr_info.transform_response);
7639 
7640       HttpTunnelProducer *p = setup_cache_transfer_to_transform();
7641       perform_cache_write_action();
7642       tunnel.tunnel_run(p);
7643     } else {
7644       ink_assert((t_state.hdr_info.client_response.valid() ? true : false) == true);
7645       do_drain_request_body(t_state.hdr_info.client_response);
7646       t_state.hdr_info.cache_response.create(HTTP_TYPE_RESPONSE);
7647       t_state.hdr_info.cache_response.copy(&t_state.hdr_info.client_response);
7648 
7649       perform_cache_write_action();
7650       t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7651 
7652       // check to see if there is a plugin hook set
7653       if (hooks_set) {
7654         do_api_callout_internal();
7655       } else {
7656         handle_api_return();
7657       }
7658     }
7659     break;
7660   }
7661 
7662   case HttpTransact::SM_ACTION_CACHE_ISSUE_WRITE: {
7663     ink_assert((cache_sm.cache_write_vc == nullptr) || t_state.redirect_info.redirect_in_process);
7664     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_cache_open_write);
7665 
7666     do_cache_prepare_write();
7667     break;
7668   }
7669 
7670   case HttpTransact::SM_ACTION_INTERNAL_CACHE_WRITE: {
7671     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7672     do_api_callout();
7673     break;
7674   }
7675 
7676   case HttpTransact::SM_ACTION_INTERNAL_CACHE_NOOP: {
7677     if (server_entry != nullptr && server_entry->in_tunnel == false) {
7678       release_server_session();
7679     }
7680     // If we're in state SEND_API_RESPONSE_HDR, it means functions
7681     // registered to hook SEND_RESPONSE_HDR have already been called. So we do not
7682     // need to call do_api_callout. Otherwise TS loops infinitely in this state !
7683     if (t_state.api_next_action == HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR) {
7684       handle_api_return();
7685     } else {
7686       t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7687       do_api_callout();
7688     }
7689     break;
7690   }
7691 
7692   case HttpTransact::SM_ACTION_INTERNAL_CACHE_DELETE: {
7693     // Nuke all the alternates since this is mostly likely
7694     //   the result of a delete method
7695     cache_sm.end_both();
7696     do_cache_delete_all_alts(nullptr);
7697 
7698     release_server_session();
7699     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7700     do_api_callout();
7701     break;
7702   }
7703 
7704   case HttpTransact::SM_ACTION_INTERNAL_CACHE_UPDATE_HEADERS: {
7705     issue_cache_update();
7706     cache_sm.close_read();
7707 
7708     release_server_session();
7709     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7710     do_api_callout();
7711     break;
7712   }
7713 
7714   case HttpTransact::SM_ACTION_SEND_ERROR_CACHE_NOOP: {
7715     setup_error_transfer();
7716     break;
7717   }
7718 
7719   case HttpTransact::SM_ACTION_INTERNAL_REQUEST:
7720     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_handle_stat_page);
7721     pending_action = statPagesManager.handle_http(this, &t_state.hdr_info.client_request);
7722     break;
7723 
7724   case HttpTransact::SM_ACTION_ORIGIN_SERVER_RR_MARK_DOWN: {
7725     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_mark_os_down);
7726 
7727     ink_assert(t_state.dns_info.looking_up == HttpTransact::ORIGIN_SERVER);
7728 
7729     // TODO: This might not be optimal (or perhaps even correct), but it will
7730     // effectively mark the host as down. What's odd is that state_mark_os_down
7731     // above isn't triggering.
7732     HttpSM::do_hostdb_update_if_necessary();
7733 
7734     do_hostdb_lookup();
7735     break;
7736   }
7737 
7738   case HttpTransact::SM_ACTION_SSL_TUNNEL: {
7739     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7740     do_api_callout();
7741     break;
7742   }
7743 
7744   case HttpTransact::SM_ACTION_ORIGIN_SERVER_RAW_OPEN: {
7745     // Pre-emptively set a server connect failure that will be cleared once a WRITE_READY is received from origin or
7746     // bytes are received back
7747     t_state.set_connect_fail(EIO);
7748     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_raw_http_server_open);
7749 
7750     ink_assert(server_entry == nullptr);
7751     do_http_server_open(true);
7752     break;
7753   }
7754 
7755   case HttpTransact::SM_ACTION_CACHE_ISSUE_WRITE_TRANSFORM: {
7756     ink_assert(t_state.cache_info.transform_action == HttpTransact::CACHE_PREPARE_TO_WRITE);
7757 
7758     if (transform_cache_sm.cache_write_vc) {
7759       // We've already got the write_vc that
7760       //  didn't use for the untransformed copy
7761       ink_assert(cache_sm.cache_write_vc == nullptr);
7762       ink_assert(t_state.api_info.cache_untransformed == false);
7763       t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_SUCCESS;
7764       call_transact_and_set_next_state(nullptr);
7765     } else {
7766       HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_cache_open_write);
7767 
7768       do_cache_prepare_write_transform();
7769     }
7770     break;
7771   }
7772 
7773   case HttpTransact::SM_ACTION_TRANSFORM_READ: {
7774     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
7775     do_api_callout();
7776     break;
7777   }
7778 
7779   case HttpTransact::SM_ACTION_READ_PUSH_HDR: {
7780     setup_push_read_response_header();
7781     break;
7782   }
7783 
7784   case HttpTransact::SM_ACTION_STORE_PUSH_BODY: {
7785     // This can return NULL - do we really want to run the tunnel in that case?
7786     // But that's how it was before this change.
7787     HttpTunnelProducer *p = setup_push_transfer_to_cache();
7788     tunnel.tunnel_run(p);
7789     break;
7790   }
7791 
7792   case HttpTransact::SM_ACTION_CACHE_PREPARE_UPDATE: {
7793     ink_assert(t_state.api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE);
7794     do_cache_prepare_update();
7795     break;
7796   }
7797   case HttpTransact::SM_ACTION_CACHE_ISSUE_UPDATE: {
7798     if (t_state.api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_ERROR) {
7799       t_state.cache_info.object_read = nullptr;
7800       cache_sm.close_read();
7801     }
7802     issue_cache_update();
7803     call_transact_and_set_next_state(nullptr);
7804     break;
7805   }
7806 
7807   case HttpTransact::SM_ACTION_WAIT_FOR_FULL_BODY: {
7808     wait_for_full_body();
7809     break;
7810   }
7811 
7812   case HttpTransact::SM_ACTION_CONTINUE: {
7813     ink_release_assert(!"Not implemented");
7814     break;
7815   }
7816 
7817   default: {
7818     ink_release_assert(!"Unknown next action");
7819   }
7820   }
7821 }
7822 
7823 void
do_redirect()7824 HttpSM::do_redirect()
7825 {
7826   SMDebug("http_redirect", "[HttpSM::do_redirect] enable_redirection %u", enable_redirection);
7827   if (!enable_redirection || redirection_tries >= t_state.txn_conf->number_of_redirections) {
7828     this->postbuf_clear();
7829 
7830     if (enable_redirection && redirection_tries >= t_state.txn_conf->number_of_redirections) {
7831       t_state.squid_codes.subcode = SQUID_SUBCODE_NUM_REDIRECTIONS_EXCEEDED;
7832     }
7833 
7834     return;
7835   }
7836 
7837   // if redirect_url is set by an user's plugin, yts will redirect to this url anyway.
7838   if (is_redirect_required()) {
7839     if (redirect_url != nullptr || t_state.hdr_info.client_response.field_find(MIME_FIELD_LOCATION, MIME_LEN_LOCATION)) {
7840       if (Log::transaction_logging_enabled() && t_state.api_info.logging_enabled) {
7841         LogAccess accessor(this);
7842         if (redirect_url == nullptr) {
7843           if (t_state.squid_codes.log_code == SQUID_LOG_TCP_HIT) {
7844             t_state.squid_codes.log_code = SQUID_LOG_TCP_HIT_REDIRECT;
7845           } else {
7846             t_state.squid_codes.log_code = SQUID_LOG_TCP_MISS_REDIRECT;
7847           }
7848         } else {
7849           if (t_state.squid_codes.log_code == SQUID_LOG_TCP_HIT) {
7850             t_state.squid_codes.log_code = SQUID_LOG_TCP_HIT_X_REDIRECT;
7851           } else {
7852             t_state.squid_codes.log_code = SQUID_LOG_TCP_MISS_X_REDIRECT;
7853           }
7854         }
7855 
7856         int ret = Log::access(&accessor);
7857 
7858         if (ret & Log::FULL) {
7859           SMDebug("http", "[update_stats] Logging system indicates FULL.");
7860         }
7861         if (ret & Log::FAIL) {
7862           Log::error("failed to log transaction for at least one log object");
7863         }
7864       }
7865 
7866       ++redirection_tries;
7867       if (redirect_url != nullptr) {
7868         redirect_request(redirect_url, redirect_url_len);
7869         ats_free((void *)redirect_url);
7870         redirect_url     = nullptr;
7871         redirect_url_len = 0;
7872         HTTP_INCREMENT_DYN_STAT(http_total_x_redirect_stat);
7873       } else {
7874         // get the location header and setup the redirect
7875         int redir_len = 0;
7876         char *redir_url =
7877           const_cast<char *>(t_state.hdr_info.client_response.value_get(MIME_FIELD_LOCATION, MIME_LEN_LOCATION, &redir_len));
7878         redirect_request(redir_url, redir_len);
7879       }
7880 
7881     } else {
7882       enable_redirection = false;
7883     }
7884   } else {
7885     enable_redirection = false;
7886   }
7887 }
7888 
7889 void
redirect_request(const char * arg_redirect_url,const int arg_redirect_len)7890 HttpSM::redirect_request(const char *arg_redirect_url, const int arg_redirect_len)
7891 {
7892   SMDebug("http_redirect", "[HttpSM::redirect_request]");
7893   // get a reference to the client request header and client url and check to see if the url is valid
7894   HTTPHdr &clientRequestHeader = t_state.hdr_info.client_request;
7895   URL &clientUrl               = *clientRequestHeader.url_get();
7896   if (!clientUrl.valid()) {
7897     return;
7898   }
7899 
7900   bool valid_origHost = true;
7901   int origHost_len, origMethod_len;
7902   char origHost[MAXDNAME];
7903   char origMethod[255];
7904   int origPort = 80;
7905 
7906   if (t_state.hdr_info.server_request.valid()) {
7907     char *tmpOrigHost;
7908 
7909     origPort    = t_state.hdr_info.server_request.port_get();
7910     tmpOrigHost = const_cast<char *>(t_state.hdr_info.server_request.value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &origHost_len));
7911 
7912     if (tmpOrigHost) {
7913       memcpy(origHost, tmpOrigHost, origHost_len);
7914       origHost[std::min(origHost_len, MAXDNAME - 1)] = '\0';
7915     } else {
7916       valid_origHost = false;
7917     }
7918 
7919     char *tmpOrigMethod = const_cast<char *>(t_state.hdr_info.server_request.method_get(&origMethod_len));
7920     if (tmpOrigMethod) {
7921       memcpy(origMethod, tmpOrigMethod, std::min(origMethod_len, static_cast<int>(sizeof(origMethod))));
7922     } else {
7923       valid_origHost = false;
7924     }
7925   } else {
7926     SMDebug("http_redir_error", "t_state.hdr_info.server_request not valid");
7927     valid_origHost = false;
7928   }
7929 
7930   t_state.redirect_info.redirect_in_process = true;
7931 
7932   // set the passed in location url and parse it
7933   URL redirectUrl;
7934   redirectUrl.create(nullptr);
7935 
7936   redirectUrl.parse(arg_redirect_url, arg_redirect_len);
7937   {
7938     int _scheme_len = -1;
7939     int _host_len   = -1;
7940     if (redirectUrl.scheme_get(&_scheme_len) == nullptr && redirectUrl.host_get(&_host_len) != nullptr &&
7941         arg_redirect_url[0] != '/') {
7942       // RFC7230 § 5.5
7943       // The redirect URL lacked a scheme and so it is a relative URL.
7944       // The redirect URL did not begin with a slash, so we parsed some or all
7945       // of the the relative URI path as the host.
7946       // Prepend a slash and parse again.
7947       char redirect_url_leading_slash[arg_redirect_len + 1];
7948       redirect_url_leading_slash[0] = '/';
7949       if (arg_redirect_len > 0) {
7950         memcpy(redirect_url_leading_slash + 1, arg_redirect_url, arg_redirect_len);
7951       }
7952       url_nuke_proxy_stuff(redirectUrl.m_url_impl);
7953       redirectUrl.parse(redirect_url_leading_slash, arg_redirect_len + 1);
7954     }
7955   }
7956 
7957   // copy the client url to the original url
7958   URL &origUrl = t_state.redirect_info.original_url;
7959   if (!origUrl.valid()) {
7960     origUrl.create(nullptr);
7961     origUrl.copy(&clientUrl);
7962   }
7963   // copy the redirect url to the client url
7964   clientUrl.copy(&redirectUrl);
7965 
7966   redirectUrl.destroy();
7967 
7968   //(bug 2540703) Clear the previous response if we will attempt the redirect
7969   if (t_state.hdr_info.client_response.valid()) {
7970     // XXX - doing a destroy() for now, we can do a fileds_clear() if we have performance issue
7971     t_state.hdr_info.client_response.destroy();
7972   }
7973 
7974   int scheme                  = t_state.next_hop_scheme;
7975   int scheme_len              = hdrtoken_index_to_length(scheme);
7976   const char *next_hop_scheme = hdrtoken_index_to_wks(scheme);
7977   char scheme_str[scheme_len + 1];
7978 
7979   if (next_hop_scheme) {
7980     memcpy(scheme_str, next_hop_scheme, scheme_len);
7981   } else {
7982     valid_origHost = false;
7983   }
7984 
7985   t_state.hdr_info.server_request.destroy();
7986 
7987   // we want to close the server session
7988   // will do that in handle_api_return under the
7989   // HttpTransact::SM_ACTION_REDIRECT_READ state
7990   t_state.parent_result.reset();
7991   t_state.request_sent_time      = 0;
7992   t_state.response_received_time = 0;
7993   t_state.next_action            = HttpTransact::SM_ACTION_REDIRECT_READ;
7994   // we have a new OS and need to have DNS lookup the new OS
7995   t_state.dns_info.lookup_success = false;
7996   t_state.force_dns               = false;
7997   t_state.server_info.clear();
7998   t_state.parent_info.clear();
7999 
8000   // Must reset whether the InkAPI has set the destination address
8001   t_state.api_server_addr_set = false;
8002 
8003   if (t_state.txn_conf->cache_http) {
8004     t_state.cache_info.object_read = nullptr;
8005   }
8006 
8007   bool noPortInHost = HttpConfig::m_master.redirection_host_no_port;
8008 
8009   bool isRedirectUrlOriginForm = !clientUrl.m_url_impl->m_len_scheme && !clientUrl.m_url_impl->m_len_user &&
8010                                  !clientUrl.m_url_impl->m_len_password && !clientUrl.m_url_impl->m_len_host &&
8011                                  !clientUrl.m_url_impl->m_len_port;
8012 
8013   // check to see if the client request passed a host header, if so copy the host and port from the redirect url and
8014   // make a new host header
8015   if (t_state.hdr_info.client_request.presence(MIME_PRESENCE_HOST)) {
8016     int host_len;
8017     const char *host = clientUrl.host_get(&host_len);
8018 
8019     if (host != nullptr) {
8020       int port = clientUrl.port_get();
8021       int redirectSchemeLen;
8022       const char *redirectScheme = clientUrl.scheme_get(&redirectSchemeLen);
8023 
8024       if (redirectScheme == nullptr) {
8025         clientUrl.scheme_set(scheme_str, scheme_len);
8026         SMDebug("http_redirect", "[HttpSM::redirect_request] URL without scheme");
8027       }
8028 
8029       if (noPortInHost) {
8030         int redirectSchemeIdx = clientUrl.scheme_get_wksidx();
8031         bool defaultPort =
8032           (((redirectSchemeIdx == URL_WKSIDX_HTTP) && (port == 80)) || ((redirectSchemeIdx == URL_WKSIDX_HTTPS) && (port == 443)));
8033 
8034         if (!defaultPort) {
8035           noPortInHost = false;
8036         }
8037       }
8038 
8039       if (!noPortInHost) {
8040         char buf[host_len + 7]; // 5 + 1 + 1 ("12345" + ':' + '\0')
8041 
8042         host_len = snprintf(buf, host_len + 7, "%.*s:%d", host_len, host, port);
8043         t_state.hdr_info.client_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, buf, host_len);
8044       } else {
8045         t_state.hdr_info.client_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, host, host_len);
8046       }
8047       t_state.hdr_info.client_request.m_target_cached = false;
8048       t_state.hdr_info.server_request.m_target_cached = false;
8049     } else {
8050       // the client request didn't have a host, so use the current origin host
8051       if (valid_origHost) {
8052         char *saveptr = nullptr;
8053 
8054         // the client request didn't have a host, so use the current origin host
8055         SMDebug("http_redirect", "[HttpSM::redirect_request] keeping client request host %s://%s", next_hop_scheme, origHost);
8056         char *origHostNoPort = strtok_r(origHost, ":", &saveptr);
8057 
8058         if (origHostNoPort == nullptr) {
8059           goto LhostError;
8060         }
8061 
8062         host_len = strlen(origHostNoPort);
8063         if (noPortInHost) {
8064           int redirectSchemeIdx = t_state.next_hop_scheme;
8065           bool defaultPort      = (((redirectSchemeIdx == URL_WKSIDX_HTTP) && (origPort == 80)) ||
8066                               ((redirectSchemeIdx == URL_WKSIDX_HTTPS) && (origPort == 443)));
8067 
8068           if (!defaultPort) {
8069             noPortInHost = false;
8070           }
8071         }
8072 
8073         if (!noPortInHost) {
8074           char buf[host_len + 7]; // 5 + 1 + 1 ("12345" + ':' + '\0')
8075 
8076           host_len = snprintf(buf, host_len + 7, "%s:%d", origHostNoPort, origPort);
8077           t_state.hdr_info.client_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, buf, host_len);
8078         } else {
8079           t_state.hdr_info.client_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, origHostNoPort, host_len);
8080         }
8081 
8082         // Cleanup of state etc.
8083         url_nuke_proxy_stuff(clientUrl.m_url_impl);
8084         url_nuke_proxy_stuff(t_state.hdr_info.client_request.m_url_cached.m_url_impl);
8085         t_state.hdr_info.client_request.method_set(origMethod, std::min(origMethod_len, static_cast<int>(sizeof(origMethod))));
8086         t_state.hdr_info.client_request.m_target_cached = false;
8087         t_state.hdr_info.server_request.m_target_cached = false;
8088         clientUrl.scheme_set(scheme_str, scheme_len);
8089         if (isRedirectUrlOriginForm) {
8090           // build the rest of the effictive URL: the authority part
8091           clientUrl.user_set(origUrl.m_url_impl->m_ptr_user, origUrl.m_url_impl->m_len_user);
8092           clientUrl.password_set(origUrl.m_url_impl->m_ptr_password, origUrl.m_url_impl->m_len_password);
8093           clientUrl.host_set(origUrl.m_url_impl->m_ptr_host, origUrl.m_url_impl->m_len_host);
8094           clientUrl.port_set(origUrl.port_get());
8095         }
8096       } else {
8097       LhostError:
8098         // the server request didn't have a host, so remove it from the headers
8099         t_state.hdr_info.client_request.field_delete(MIME_FIELD_HOST, MIME_LEN_HOST);
8100       }
8101     }
8102   }
8103 
8104   DUMP_HEADER("http_hdrs", &t_state.hdr_info.client_request, sm_id, "Framed Client Request..checking");
8105 }
8106 
8107 void
set_http_schedule(Continuation * contp)8108 HttpSM::set_http_schedule(Continuation *contp)
8109 {
8110   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::get_http_schedule);
8111   schedule_cont = contp;
8112 }
8113 
8114 int
get_http_schedule(int event,void *)8115 HttpSM::get_http_schedule(int event, void * /* data ATS_UNUSED */)
8116 {
8117   bool plugin_lock;
8118   Ptr<ProxyMutex> plugin_mutex;
8119   if (schedule_cont->mutex) {
8120     plugin_mutex = schedule_cont->mutex;
8121     plugin_lock  = MUTEX_TAKE_TRY_LOCK(schedule_cont->mutex, mutex->thread_holding);
8122 
8123     if (!plugin_lock) {
8124       HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::get_http_schedule);
8125       ink_assert(pending_action.is_empty());
8126       pending_action = mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(10));
8127       return 0;
8128     } else {
8129       pending_action = nullptr; // if there was a pending action, it'll get freed after this returns so clear it.
8130     }
8131   } else {
8132     plugin_lock = false;
8133   }
8134 
8135   // handle Mutex;
8136   schedule_cont->handleEvent(event, this);
8137   if (plugin_lock) {
8138     Mutex_unlock(plugin_mutex, mutex->thread_holding);
8139   }
8140 
8141   return 0;
8142 }
8143 
8144 bool
set_server_session_private(bool private_session)8145 HttpSM::set_server_session_private(bool private_session)
8146 {
8147   if (server_session != nullptr) {
8148     server_session->set_private(private_session);
8149     return true;
8150   }
8151   return false;
8152 }
8153 
8154 inline bool
is_private()8155 HttpSM::is_private()
8156 {
8157   bool res = false;
8158   if (server_session) {
8159     res = server_session->is_private();
8160   } else if (ua_txn) {
8161     Http1ServerSession *ss = dynamic_cast<Http1ServerSession *>(ua_txn->get_server_session());
8162     if (ss) {
8163       res = ss->is_private();
8164     } else if (will_be_private_ss) {
8165       res = will_be_private_ss;
8166     }
8167   }
8168   return res;
8169 }
8170 
8171 // check to see if redirection is enabled and less than max redirections tries or if a plugin enabled redirection
8172 inline bool
is_redirect_required()8173 HttpSM::is_redirect_required()
8174 {
8175   bool redirect_required = (enable_redirection && (redirection_tries < t_state.txn_conf->number_of_redirections) &&
8176                             !HttpTransact::is_fresh_cache_hit(t_state.cache_lookup_result));
8177 
8178   SMDebug("http_redirect", "is_redirect_required %u", redirect_required);
8179 
8180   if (redirect_required == true) {
8181     HTTPStatus status = t_state.hdr_info.client_response.status_get();
8182     // check to see if the response from the origin was a 301, 302, or 303
8183     switch (status) {
8184     case HTTP_STATUS_MULTIPLE_CHOICES:   // 300
8185     case HTTP_STATUS_MOVED_PERMANENTLY:  // 301
8186     case HTTP_STATUS_MOVED_TEMPORARILY:  // 302
8187     case HTTP_STATUS_SEE_OTHER:          // 303
8188     case HTTP_STATUS_USE_PROXY:          // 305
8189     case HTTP_STATUS_TEMPORARY_REDIRECT: // 307
8190     case HTTP_STATUS_PERMANENT_REDIRECT: // 308
8191       redirect_required = true;
8192       break;
8193     default:
8194       redirect_required = false;
8195       break;
8196     }
8197 
8198     // if redirect_url is set by an user's plugin, ats will redirect to this url anyway.
8199     if (redirect_url != nullptr) {
8200       redirect_required = true;
8201     }
8202   }
8203   return redirect_required;
8204 }
8205 
8206 // Fill in the client protocols used.  Return the number of entries populated.
8207 int
populate_client_protocol(std::string_view * result,int n) const8208 HttpSM::populate_client_protocol(std::string_view *result, int n) const
8209 {
8210   int retval = 0;
8211   if (n > 0) {
8212     std::string_view proto = HttpSM::find_proto_string(t_state.hdr_info.client_request.version_get());
8213     if (!proto.empty()) {
8214       result[retval++] = proto;
8215       if (n > retval && ua_txn) {
8216         retval += ua_txn->populate_protocol(result + retval, n - retval);
8217       }
8218     }
8219   }
8220   return retval;
8221 }
8222 
8223 // Look for a specific client protocol
8224 const char *
client_protocol_contains(std::string_view tag_prefix) const8225 HttpSM::client_protocol_contains(std::string_view tag_prefix) const
8226 {
8227   const char *retval     = nullptr;
8228   std::string_view proto = HttpSM::find_proto_string(t_state.hdr_info.client_request.version_get());
8229   if (!proto.empty()) {
8230     std::string_view prefix(tag_prefix);
8231     if (prefix.size() <= proto.size() && 0 == strncmp(proto.data(), prefix.data(), prefix.size())) {
8232       retval = proto.data();
8233     } else if (ua_txn) {
8234       retval = ua_txn->protocol_contains(prefix);
8235     }
8236   }
8237   return retval;
8238 }
8239 
8240 // Fill in the server protocols used.  Return the number of entries populated.
8241 int
populate_server_protocol(std::string_view * result,int n) const8242 HttpSM::populate_server_protocol(std::string_view *result, int n) const
8243 {
8244   int retval = 0;
8245   if (!t_state.hdr_info.server_request.valid()) {
8246     return retval;
8247   }
8248   if (n > 0) {
8249     std::string_view proto = HttpSM::find_proto_string(t_state.hdr_info.server_request.version_get());
8250     if (!proto.empty()) {
8251       result[retval++] = proto;
8252       if (n > retval && server_session) {
8253         retval += server_session->populate_protocol(result + retval, n - retval);
8254       }
8255     }
8256   }
8257   return retval;
8258 }
8259 
8260 // Look for a specific server protocol
8261 const char *
server_protocol_contains(std::string_view tag_prefix) const8262 HttpSM::server_protocol_contains(std::string_view tag_prefix) const
8263 {
8264   const char *retval     = nullptr;
8265   std::string_view proto = HttpSM::find_proto_string(t_state.hdr_info.server_request.version_get());
8266   if (!proto.empty()) {
8267     std::string_view prefix(tag_prefix);
8268     if (prefix.size() <= proto.size() && 0 == strncmp(proto.data(), prefix.data(), prefix.size())) {
8269       retval = proto.data();
8270     } else {
8271       if (server_session) {
8272         retval = server_session->protocol_contains(prefix);
8273       }
8274     }
8275   }
8276   return retval;
8277 }
8278 
8279 std::string_view
find_proto_string(HTTPVersion version) const8280 HttpSM::find_proto_string(HTTPVersion version) const
8281 {
8282   if (version == HTTP_2_0) {
8283     return IP_PROTO_TAG_HTTP_2_0;
8284   } else if (version == HTTP_1_1) {
8285     return IP_PROTO_TAG_HTTP_1_1;
8286   } else if (version == HTTP_1_0) {
8287     return IP_PROTO_TAG_HTTP_1_0;
8288   } else if (version == HTTP_0_9) {
8289     return IP_PROTO_TAG_HTTP_0_9;
8290   }
8291   return {};
8292 }
8293 
8294 void
rewind_state_machine()8295 HttpSM::rewind_state_machine()
8296 {
8297   callout_state = HTTP_API_REWIND_STATE_MACHINE;
8298 }
8299 
8300 // YTS Team, yamsat Plugin
8301 // Function to copy the partial Post data while tunnelling
8302 void
copy_partial_post_data()8303 PostDataBuffers::copy_partial_post_data()
8304 {
8305   if (post_data_buffer_done) {
8306     return;
8307   }
8308   Debug("http_redirect", "[PostDataBuffers::copy_partial_post_data] wrote %" PRId64 " bytes to buffers %" PRId64 "",
8309         this->ua_buffer_reader->read_avail(), this->postdata_copy_buffer_start->read_avail());
8310   this->postdata_copy_buffer->write(this->ua_buffer_reader);
8311   this->ua_buffer_reader->consume(this->ua_buffer_reader->read_avail());
8312 }
8313 
8314 IOBufferReader *
get_post_data_buffer_clone_reader()8315 PostDataBuffers::get_post_data_buffer_clone_reader()
8316 {
8317   return this->postdata_copy_buffer->clone_reader(this->postdata_copy_buffer_start);
8318 }
8319 
8320 // YTS Team, yamsat Plugin
8321 // Allocating the post data buffers
8322 void
init(IOBufferReader * ua_reader)8323 PostDataBuffers::init(IOBufferReader *ua_reader)
8324 {
8325   Debug("http_redirect", "[PostDataBuffers::init]");
8326 
8327   this->ua_buffer_reader = ua_reader;
8328 
8329   if (this->postdata_copy_buffer == nullptr) {
8330     this->post_data_buffer_done = false;
8331     ink_assert(this->postdata_copy_buffer_start == nullptr);
8332     this->postdata_copy_buffer       = new_empty_MIOBuffer(BUFFER_SIZE_INDEX_4K);
8333     this->postdata_copy_buffer_start = this->postdata_copy_buffer->alloc_reader();
8334   }
8335 
8336   ink_assert(this->ua_buffer_reader != nullptr);
8337 }
8338 
8339 // YTS Team, yamsat Plugin
8340 // Deallocating the post data buffers
8341 void
clear()8342 PostDataBuffers::clear()
8343 {
8344   Debug("http_redirect", "[PostDataBuffers::clear]");
8345 
8346   if (this->postdata_copy_buffer != nullptr) {
8347     free_MIOBuffer(this->postdata_copy_buffer);
8348     this->postdata_copy_buffer       = nullptr;
8349     this->postdata_copy_buffer_start = nullptr; // deallocated by the buffer
8350   }
8351   this->post_data_buffer_done = false;
8352 }
8353 
~PostDataBuffers()8354 PostDataBuffers::~PostDataBuffers()
8355 {
8356   this->clear();
8357 }
8358 
8359 PoolableSession *
get_server_session() const8360 HttpSM::get_server_session() const
8361 {
8362   return server_session;
8363 }
8364