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