1 /** @file
2 
3   A brief file description
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 #pragma once
25 
26 #include "tscore/ink_assert.h"
27 #include "tscore/ink_platform.h"
28 #include "P_HostDB.h"
29 #include "P_Net.h"
30 #include "HttpConfig.h"
31 #include "HTTP.h"
32 #include "HttpTransactCache.h"
33 #include "ControlMatcher.h"
34 #include "CacheControl.h"
35 #include "ParentSelection.h"
36 #include "ProxyConfig.h"
37 #include "Transform.h"
38 #include "Milestones.h"
39 #include "ts/remap.h"
40 #include "RemapPluginInfo.h"
41 #include "UrlMapping.h"
42 #include "records/I_RecHttp.h"
43 #include "ProxySession.h"
44 #include "MgmtDefs.h"
45 
46 #define HTTP_RELEASE_ASSERT(X) ink_release_assert(X)
47 
48 #define DUMP_HEADER(T, H, I, S)                                 \
49   {                                                             \
50     if (diags->on(T)) {                                         \
51       fprintf(stderr, "+++++++++ %s +++++++++\n", S);           \
52       fprintf(stderr, "-- State Machine Id: %" PRId64 "\n", I); \
53       char b[4096];                                             \
54       int used, tmp, offset;                                    \
55       int done;                                                 \
56       offset = 0;                                               \
57       if ((H)->valid()) {                                       \
58         do {                                                    \
59           used = 0;                                             \
60           tmp  = offset;                                        \
61           done = (H)->print(b, 4095, &used, &tmp);              \
62           offset += used;                                       \
63           b[used] = '\0';                                       \
64           fprintf(stderr, "%s", b);                             \
65         } while (!done);                                        \
66       }                                                         \
67     }                                                           \
68   }
69 
70 typedef time_t ink_time_t;
71 
72 struct HttpConfigParams;
73 class HttpSM;
74 
75 #include "tscore/InkErrno.h"
76 #include "HttpConnectionCount.h"
77 
78 #define UNKNOWN_INTERNAL_ERROR (INK_START_ERRNO - 1)
79 
80 enum ViaStringIndex_t {
81   //
82   // General information
83   VIA_CLIENT = 0,
84   VIA_CLIENT_REQUEST,
85   VIA_CACHE,
86   VIA_CACHE_RESULT,
87   VIA_SERVER,
88   VIA_SERVER_RESULT,
89   VIA_CACHE_FILL,
90   VIA_CACHE_FILL_ACTION,
91   VIA_PROXY,
92   VIA_PROXY_RESULT,
93   VIA_ERROR,
94   VIA_ERROR_TYPE,
95   //
96   // State Machine specific details
97   VIA_DETAIL_SEPARATOR,
98   VIA_DETAIL_TUNNEL_DESCRIPTOR,
99   VIA_DETAIL_TUNNEL,
100   VIA_DETAIL_CACHE_DESCRIPTOR,
101   VIA_DETAIL_CACHE_TYPE,
102   VIA_DETAIL_CACHE_LOOKUP,
103   VIA_DETAIL_PP_DESCRIPTOR,
104   VIA_DETAIL_PP_CONNECT,
105   VIA_DETAIL_SERVER_DESCRIPTOR,
106   VIA_DETAIL_SERVER_CONNECT,
107   //
108   // Total
109   MAX_VIA_INDICES
110 };
111 
112 enum ViaString_t {
113   // client stuff
114   VIA_CLIENT_STRING   = 'u',
115   VIA_CLIENT_ERROR    = 'E',
116   VIA_CLIENT_IMS      = 'I',
117   VIA_CLIENT_NO_CACHE = 'N',
118   VIA_CLIENT_COOKIE   = 'C',
119   VIA_CLIENT_SIMPLE   = 'S',
120   // cache lookup stuff
121   VIA_CACHE_STRING            = 'c',
122   VIA_CACHE_MISS              = 'M',
123   VIA_IN_CACHE_NOT_ACCEPTABLE = 'A',
124   VIA_IN_CACHE_STALE          = 'S',
125   VIA_IN_CACHE_FRESH          = 'H',
126   VIA_IN_RAM_CACHE_FRESH      = 'R',
127   // server stuff
128   VIA_SERVER_STRING       = 's',
129   VIA_SERVER_ERROR        = 'E',
130   VIA_SERVER_NOT_MODIFIED = 'N',
131   VIA_SERVER_SERVED       = 'S',
132   // cache fill stuff
133   VIA_CACHE_FILL_STRING = 'f',
134   VIA_CACHE_DELETED     = 'D',
135   VIA_CACHE_WRITTEN     = 'W',
136   VIA_CACHE_UPDATED     = 'U',
137   // proxy stuff
138   VIA_PROXY_STRING             = 'p',
139   VIA_PROXY_NOT_MODIFIED       = 'N',
140   VIA_PROXY_SERVED             = 'S',
141   VIA_PROXY_SERVER_REVALIDATED = 'R',
142   // errors
143   VIA_ERROR_STRING            = 'e',
144   VIA_ERROR_NO_ERROR          = 'N',
145   VIA_ERROR_AUTHORIZATION     = 'A',
146   VIA_ERROR_CONNECTION        = 'C',
147   VIA_ERROR_DNS_FAILURE       = 'D',
148   VIA_ERROR_FORBIDDEN         = 'F',
149   VIA_ERROR_HEADER_SYNTAX     = 'H',
150   VIA_ERROR_SERVER            = 'S',
151   VIA_ERROR_TIMEOUT           = 'T',
152   VIA_ERROR_CACHE_READ        = 'R',
153   VIA_ERROR_MOVED_TEMPORARILY = 'M',
154   VIA_ERROR_LOOP_DETECTED     = 'L',
155   //
156   // Now the detailed stuff
157   //
158   VIA_DETAIL_SEPARATOR_STRING = ':',
159   // tunnelling
160   VIA_DETAIL_TUNNEL_DESCRIPTOR_STRING = 't',
161   VIA_DETAIL_TUNNEL_HEADER_FIELD      = 'F',
162   VIA_DETAIL_TUNNEL_METHOD            = 'M',
163   VIA_DETAIL_TUNNEL_CACHE_OFF         = 'O',
164   VIA_DETAIL_TUNNEL_URL               = 'U',
165   VIA_DETAIL_TUNNEL_NO_FORWARD        = 'N',
166   VIA_DETAIL_TUNNEL_AUTHORIZATION     = 'A',
167   // cache type
168   VIA_DETAIL_CACHE_DESCRIPTOR_STRING = 'c',
169   VIA_DETAIL_CACHE                   = 'C',
170   VIA_DETAIL_PARENT                  = 'P',
171   VIA_DETAIL_SERVER                  = 'S',
172   // result of cache lookup
173   VIA_DETAIL_HIT_CONDITIONAL  = 'N',
174   VIA_DETAIL_HIT_SERVED       = 'H',
175   VIA_DETAIL_MISS_CONDITIONAL = 'I',
176   VIA_DETAIL_MISS_NOT_CACHED  = 'M',
177   VIA_DETAIL_MISS_EXPIRED     = 'S',
178   VIA_DETAIL_MISS_CONFIG      = 'C',
179   VIA_DETAIL_MISS_CLIENT      = 'U',
180   VIA_DETAIL_MISS_METHOD      = 'D',
181   VIA_DETAIL_MISS_COOKIE      = 'K',
182   // result of pp suggested host lookup
183   VIA_DETAIL_PP_DESCRIPTOR_STRING = 'p',
184   VIA_DETAIL_PP_SUCCESS           = 'S',
185   VIA_DETAIL_PP_FAILURE           = 'F',
186   // result of server suggested host lookup
187   VIA_DETAIL_SERVER_DESCRIPTOR_STRING = 's',
188   VIA_DETAIL_SERVER_SUCCESS           = 'S',
189   VIA_DETAIL_SERVER_FAILURE           = 'F'
190 };
191 
192 struct HttpApiInfo {
193   char *parent_proxy_name       = nullptr;
194   int parent_proxy_port         = -1;
195   bool cache_untransformed      = false;
196   bool cache_transformed        = true;
197   bool logging_enabled          = true;
198   bool retry_intercept_failures = false;
199 
HttpApiInfoHttpApiInfo200   HttpApiInfo() {}
201 };
202 
203 const int32_t HTTP_UNDEFINED_CL = -1;
204 
205 //////////////////////////////////////////////////////////////////////////////
206 //
207 //  HttpTransact
208 //
209 //  The HttpTransact class is purely used for scoping and should
210 //  not be instantiated.
211 //
212 //////////////////////////////////////////////////////////////////////////////
213 #define SET_VIA_STRING(I, S) s->via_string[I] = S;
214 #define GET_VIA_STRING(I) (s->via_string[I])
215 
216 class HttpTransact
217 {
218 public:
219   enum AbortState_t {
220     ABORT_UNDEFINED = 0,
221     DIDNOT_ABORT,
222     ABORTED,
223   };
224 
225   enum Authentication_t {
226     AUTHENTICATION_SUCCESS = 0,
227     AUTHENTICATION_MUST_REVALIDATE,
228     AUTHENTICATION_MUST_PROXY,
229     AUTHENTICATION_CACHE_AUTH
230   };
231 
232   enum CacheAction_t {
233     CACHE_DO_UNDEFINED = 0,
234     CACHE_DO_NO_ACTION,
235     CACHE_DO_DELETE,
236     CACHE_DO_LOOKUP,
237     CACHE_DO_REPLACE,
238     CACHE_DO_SERVE,
239     CACHE_DO_SERVE_AND_DELETE,
240     CACHE_DO_SERVE_AND_UPDATE,
241     CACHE_DO_UPDATE,
242     CACHE_DO_WRITE,
243     CACHE_PREPARE_TO_DELETE,
244     CACHE_PREPARE_TO_UPDATE,
245     CACHE_PREPARE_TO_WRITE,
246     TOTAL_CACHE_ACTION_TYPES
247   };
248 
249   enum CacheWriteLock_t {
250     CACHE_WL_INIT,
251     CACHE_WL_SUCCESS,
252     CACHE_WL_FAIL,
253     CACHE_WL_READ_RETRY,
254   };
255 
256   enum ClientTransactionResult_t {
257     CLIENT_TRANSACTION_RESULT_UNDEFINED,
258     CLIENT_TRANSACTION_RESULT_HIT_FRESH,
259     CLIENT_TRANSACTION_RESULT_HIT_REVALIDATED,
260     CLIENT_TRANSACTION_RESULT_MISS_COLD,
261     CLIENT_TRANSACTION_RESULT_MISS_CHANGED,
262     CLIENT_TRANSACTION_RESULT_MISS_CLIENT_NO_CACHE,
263     CLIENT_TRANSACTION_RESULT_MISS_UNCACHABLE,
264     CLIENT_TRANSACTION_RESULT_ERROR_ABORT,
265     CLIENT_TRANSACTION_RESULT_ERROR_POSSIBLE_ABORT,
266     CLIENT_TRANSACTION_RESULT_ERROR_CONNECT_FAIL,
267     CLIENT_TRANSACTION_RESULT_ERROR_OTHER
268   };
269 
270   enum Freshness_t {
271     FRESHNESS_FRESH = 0, // Fresh enough, serve it
272     FRESHNESS_WARNING,   // Stale, but client says OK
273     FRESHNESS_STALE      // Stale, don't use
274   };
275 
276   enum HttpTransactMagic_t {
277     HTTP_TRANSACT_MAGIC_ALIVE     = 0x00001234,
278     HTTP_TRANSACT_MAGIC_DEAD      = 0xDEAD1234,
279     HTTP_TRANSACT_MAGIC_SEPARATOR = 0x12345678
280   };
281 
282   enum LookingUp_t {
283     ORIGIN_SERVER,
284     UNDEFINED_LOOKUP,
285     PARENT_PROXY,
286     INCOMING_ROUTER,
287     HOST_NONE,
288   };
289 
290   enum ProxyMode_t {
291     UNDEFINED_MODE,
292     GENERIC_PROXY,
293     TUNNELLING_PROXY,
294   };
295 
296   enum RequestError_t {
297     NO_REQUEST_HEADER_ERROR,
298     BAD_HTTP_HEADER_SYNTAX,
299     BAD_CONNECT_PORT,
300     FAILED_PROXY_AUTHORIZATION,
301     METHOD_NOT_SUPPORTED,
302     MISSING_HOST_FIELD,
303     NO_POST_CONTENT_LENGTH,
304     NO_REQUEST_SCHEME,
305     NON_EXISTANT_REQUEST_HEADER,
306     SCHEME_NOT_SUPPORTED,
307     UNACCEPTABLE_TE_REQUIRED,
308     INVALID_POST_CONTENT_LENGTH,
309     TOTAL_REQUEST_ERROR_TYPES
310   };
311 
312   enum ResponseError_t {
313     NO_RESPONSE_HEADER_ERROR,
314     BOGUS_OR_NO_DATE_IN_RESPONSE,
315     CONNECTION_OPEN_FAILED,
316     MISSING_REASON_PHRASE,
317     MISSING_STATUS_CODE,
318     NON_EXISTANT_RESPONSE_HEADER,
319     NOT_A_RESPONSE_HEADER,
320     STATUS_CODE_SERVER_ERROR,
321     TOTAL_RESPONSE_ERROR_TYPES
322   };
323 
324   // Please do not forget to fix TSServerState (ts/apidefs.h.in)
325   // in case of any modifications in ServerState_t
326   enum ServerState_t {
327     STATE_UNDEFINED = 0,
328     ACTIVE_TIMEOUT,
329     BAD_INCOMING_RESPONSE,
330     CONNECTION_ALIVE,
331     CONNECTION_CLOSED,
332     CONNECTION_ERROR,
333     INACTIVE_TIMEOUT,
334     OPEN_RAW_ERROR,
335     PARSE_ERROR,
336     TRANSACTION_COMPLETE,
337     PARENT_RETRY,
338     OUTBOUND_CONGESTION
339   };
340 
341   enum CacheWriteStatus_t {
342     NO_CACHE_WRITE = 0,
343     CACHE_WRITE_LOCK_MISS,
344     CACHE_WRITE_IN_PROGRESS,
345     CACHE_WRITE_ERROR,
346     CACHE_WRITE_COMPLETE
347   };
348 
349   enum HttpRequestFlavor_t {
350     REQ_FLAVOR_INTERCEPTED      = 0,
351     REQ_FLAVOR_REVPROXY         = 1,
352     REQ_FLAVOR_FWDPROXY         = 2,
353     REQ_FLAVOR_SCHEDULED_UPDATE = 3
354   };
355 
356   ////////////
357   // source //
358   ////////////
359   enum Source_t {
360     SOURCE_NONE = 0,
361     SOURCE_HTTP_ORIGIN_SERVER,
362     SOURCE_RAW_ORIGIN_SERVER,
363     SOURCE_CACHE,
364     SOURCE_TRANSFORM,
365     SOURCE_INTERNAL // generated from text buffer
366   };
367 
368   ////////////////////////////////////////////////
369   // HttpTransact fills a StateMachineAction_t  //
370   // to tell the state machine what to do next. //
371   ////////////////////////////////////////////////
372   enum StateMachineAction_t {
373     SM_ACTION_UNDEFINED = 0,
374 
375     // SM_ACTION_AUTH_LOOKUP,
376     SM_ACTION_DNS_LOOKUP,
377     SM_ACTION_DNS_REVERSE_LOOKUP,
378 
379     SM_ACTION_CACHE_LOOKUP,
380     SM_ACTION_CACHE_ISSUE_WRITE,
381     SM_ACTION_CACHE_ISSUE_WRITE_TRANSFORM,
382     SM_ACTION_CACHE_PREPARE_UPDATE,
383     SM_ACTION_CACHE_ISSUE_UPDATE,
384 
385     SM_ACTION_ORIGIN_SERVER_OPEN,
386     SM_ACTION_ORIGIN_SERVER_RAW_OPEN,
387     SM_ACTION_ORIGIN_SERVER_RR_MARK_DOWN,
388 
389     SM_ACTION_READ_PUSH_HDR,
390     SM_ACTION_STORE_PUSH_BODY,
391 
392     SM_ACTION_INTERNAL_CACHE_DELETE,
393     SM_ACTION_INTERNAL_CACHE_NOOP,
394     SM_ACTION_INTERNAL_CACHE_UPDATE_HEADERS,
395     SM_ACTION_INTERNAL_CACHE_WRITE,
396     SM_ACTION_INTERNAL_100_RESPONSE,
397     SM_ACTION_INTERNAL_REQUEST,
398     SM_ACTION_SEND_ERROR_CACHE_NOOP,
399 
400     SM_ACTION_WAIT_FOR_FULL_BODY,
401     SM_ACTION_REQUEST_BUFFER_READ_COMPLETE,
402     SM_ACTION_SERVE_FROM_CACHE,
403     SM_ACTION_SERVER_READ,
404     SM_ACTION_SERVER_PARSE_NEXT_HDR,
405     SM_ACTION_TRANSFORM_READ,
406     SM_ACTION_SSL_TUNNEL,
407     SM_ACTION_CONTINUE,
408 
409     SM_ACTION_API_SM_START,
410     SM_ACTION_API_READ_REQUEST_HDR,
411     SM_ACTION_API_PRE_REMAP,
412     SM_ACTION_API_POST_REMAP,
413     SM_ACTION_API_OS_DNS,
414     SM_ACTION_API_SEND_REQUEST_HDR,
415     SM_ACTION_API_READ_CACHE_HDR,
416     SM_ACTION_API_CACHE_LOOKUP_COMPLETE,
417     SM_ACTION_API_READ_RESPONSE_HDR,
418     SM_ACTION_API_SEND_RESPONSE_HDR,
419     SM_ACTION_API_SM_SHUTDOWN,
420 
421     SM_ACTION_REMAP_REQUEST,
422     SM_ACTION_POST_REMAP_SKIP,
423     SM_ACTION_REDIRECT_READ
424   };
425 
426   enum TransferEncoding_t {
427     NO_TRANSFER_ENCODING = 0,
428     CHUNKED_ENCODING,
429     DEFLATE_ENCODING,
430   };
431 
432   enum Variability_t {
433     VARIABILITY_NONE = 0,
434     VARIABILITY_SOME,
435     VARIABILITY_ALL,
436   };
437 
438   enum CacheLookupResult_t {
439     CACHE_LOOKUP_NONE,
440     CACHE_LOOKUP_MISS,
441     CACHE_LOOKUP_DOC_BUSY,
442     CACHE_LOOKUP_HIT_STALE,
443     CACHE_LOOKUP_HIT_WARNING,
444     CACHE_LOOKUP_HIT_FRESH,
445     CACHE_LOOKUP_SKIPPED
446   };
447 
448   enum UpdateCachedObject_t {
449     UPDATE_CACHED_OBJECT_NONE,
450     UPDATE_CACHED_OBJECT_PREPARE,
451     UPDATE_CACHED_OBJECT_CONTINUE,
452     UPDATE_CACHED_OBJECT_ERROR,
453     UPDATE_CACHED_OBJECT_SUCCEED,
454     UPDATE_CACHED_OBJECT_FAIL
455   };
456 
457   enum RangeSetup_t {
458     RANGE_NONE = 0,
459     RANGE_REQUESTED,
460     RANGE_NOT_SATISFIABLE,
461     RANGE_NOT_HANDLED,
462     RANGE_NOT_TRANSFORM_REQUESTED,
463   };
464 
465   enum CacheAuth_t {
466     CACHE_AUTH_NONE = 0,
467     // CACHE_AUTH_TRUE,
468     CACHE_AUTH_FRESH,
469     CACHE_AUTH_STALE,
470     CACHE_AUTH_SERVE
471   };
472 
473   struct State;
474   typedef void (*TransactFunc_t)(HttpTransact::State *);
475 
476   typedef struct _CacheDirectives {
477     bool does_client_permit_lookup      = true;
478     bool does_client_permit_storing     = true;
479     bool does_client_permit_dns_storing = true;
480     bool does_config_permit_lookup      = true;
481     bool does_config_permit_storing     = true;
482     bool does_server_permit_lookup      = true;
483     bool does_server_permit_storing     = true;
484 
_CacheDirectives_CacheDirectives485     _CacheDirectives() {}
486   } CacheDirectives;
487 
488   typedef struct _CacheLookupInfo {
489     HttpTransact::CacheAction_t action           = CACHE_DO_UNDEFINED;
490     HttpTransact::CacheAction_t transform_action = CACHE_DO_UNDEFINED;
491 
492     HttpTransact::CacheWriteStatus_t write_status           = NO_CACHE_WRITE;
493     HttpTransact::CacheWriteStatus_t transform_write_status = NO_CACHE_WRITE;
494 
495     URL *lookup_url = nullptr;
496     URL lookup_url_storage;
497     URL original_url;
498     HTTPInfo object_store;
499     HTTPInfo transform_store;
500     CacheDirectives directives;
501     HTTPInfo *object_read             = nullptr;
502     int open_read_retries             = 0;
503     int open_write_retries            = 0;
504     CacheWriteLock_t write_lock_state = CACHE_WL_INIT;
505     int lookup_count                  = 0;
506     SquidHitMissCode hit_miss_code    = SQUID_MISS_NONE;
507     URL *parent_selection_url         = nullptr;
508     URL parent_selection_url_storage;
509 
_CacheLookupInfo_CacheLookupInfo510     _CacheLookupInfo() {}
511   } CacheLookupInfo;
512 
513   typedef struct _RedirectInfo {
514     bool redirect_in_process = false;
515     URL original_url;
516 
_RedirectInfo_RedirectInfo517     _RedirectInfo() {}
518   } RedirectInfo;
519 
520   struct ConnectionAttributes {
521     HTTPVersion http_version;
522     HTTPKeepAlive keep_alive = HTTP_KEEPALIVE_UNDEFINED;
523 
524     // The following variable is true if the client expects to
525     // received a chunked response.
526     bool receive_chunked_response = false;
527     bool proxy_connect_hdr        = false;
528     /// @c errno from the most recent attempt to connect.
529     /// zero means no failure (not attempted, succeeded).
530     int connect_result                   = 0;
531     char *name                           = nullptr;
532     TransferEncoding_t transfer_encoding = NO_TRANSFER_ENCODING;
533 
534     /** This is the source address of the connection from the point of view of the transaction.
535         It is the address of the source of the request.
536     */
537     IpEndpoint src_addr;
538     /** This is the destination address of the connection from the point of view of the transaction.
539         It is the address of the target of the request.
540     */
541     IpEndpoint dst_addr;
542 
543     ServerState_t state                         = STATE_UNDEFINED;
544     AbortState_t abort                          = ABORT_UNDEFINED;
545     HttpProxyPort::TransportType port_attribute = HttpProxyPort::TRANSPORT_DEFAULT;
546 
547     /// @c true if the connection is transparent.
548     bool is_transparent = false;
549     ProxyError rx_error_code;
550     ProxyError tx_error_code;
551 
552     bool
had_connect_failConnectionAttributes553     had_connect_fail() const
554     {
555       return 0 != connect_result;
556     }
557     void
clear_connect_failConnectionAttributes558     clear_connect_fail()
559     {
560       connect_result = 0;
561     }
ConnectionAttributesConnectionAttributes562     ConnectionAttributes() { clear(); }
563 
564     void
clearConnectionAttributes565     clear()
566     {
567       ink_zero(src_addr);
568       ink_zero(dst_addr);
569       connect_result = 0;
570     }
571   };
572 
573   typedef struct _CurrentInfo {
574     ProxyMode_t mode                           = UNDEFINED_MODE;
575     LookingUp_t request_to                     = UNDEFINED_LOOKUP;
576     ConnectionAttributes *server               = nullptr;
577     ink_time_t now                             = 0;
578     ServerState_t state                        = STATE_UNDEFINED;
579     unsigned attempts                          = 0;
580     unsigned simple_retry_attempts             = 0;
581     unsigned unavailable_server_retry_attempts = 0;
582     ParentRetry_t retry_type                   = PARENT_RETRY_NONE;
583 
_CurrentInfo_CurrentInfo584     _CurrentInfo() {}
585   } CurrentInfo;
586 
587   typedef struct _DNSLookupInfo {
588     /** Origin server address source selection.
589 
590         If config says to use CTA (client target addr) state is
591         OS_ADDR_TRY_CLIENT, otherwise it remains the default. If the
592         connect fails then we switch to a USE. We go to USE_HOSTDB if
593         (1) the HostDB lookup is successful and (2) some address other
594         than the CTA is available to try. Otherwise we keep retrying
595         on the CTA (USE_CLIENT) up to the max retry value.  In essence
596         we try to treat the CTA as if it were another RR value in the
597         HostDB record.
598      */
599     enum class OS_Addr {
600       OS_ADDR_TRY_DEFAULT, ///< Initial state, use what config says.
601       OS_ADDR_TRY_HOSTDB,  ///< Try HostDB data.
602       OS_ADDR_TRY_CLIENT,  ///< Try client target addr.
603       OS_ADDR_USE_HOSTDB,  ///< Force use of HostDB target address.
604       OS_ADDR_USE_CLIENT   ///< Use client target addr, no fallback.
605     };
606 
607     OS_Addr os_addr_style = OS_Addr::OS_ADDR_TRY_DEFAULT;
608 
609     bool lookup_success         = false;
610     char *lookup_name           = nullptr;
611     char srv_hostname[MAXDNAME] = {0};
612     LookingUp_t looking_up      = UNDEFINED_LOOKUP;
613     bool srv_lookup_success     = false;
614     short srv_port              = 0;
615     HostDBApplicationInfo srv_app;
616 
617     /*** Set to true by default.  If use_client_target_address is set
618      * to 1, this value will be set to false if the client address is
619      * not in the DNS pool */
620     bool lookup_validated = true;
621 
_DNSLookupInfo_DNSLookupInfo622     _DNSLookupInfo() {}
623   } DNSLookupInfo;
624 
625   // Conversion handling for DNS host resolution type.
626   static const MgmtConverter HOST_RES_CONV;
627 
628   typedef struct _HeaderInfo {
629     HTTPHdr client_request;
630     HTTPHdr client_response;
631     HTTPHdr server_request;
632     HTTPHdr server_response;
633     HTTPHdr transform_response;
634     HTTPHdr cache_response;
635     int64_t request_content_length  = HTTP_UNDEFINED_CL;
636     int64_t response_content_length = HTTP_UNDEFINED_CL;
637     int64_t transform_request_cl    = HTTP_UNDEFINED_CL;
638     int64_t transform_response_cl   = HTTP_UNDEFINED_CL;
639     bool client_req_is_server_style = false;
640     bool trust_response_cl          = false;
641     ResponseError_t response_error  = NO_RESPONSE_HEADER_ERROR;
642     bool extension_method           = false;
643 
_HeaderInfo_HeaderInfo644     _HeaderInfo() {}
645   } HeaderInfo;
646 
647   typedef struct _SquidLogInfo {
648     SquidLogCode log_code          = SQUID_LOG_ERR_UNKNOWN;
649     SquidSubcode subcode           = SQUID_SUBCODE_EMPTY;
650     SquidHierarchyCode hier_code   = SQUID_HIER_EMPTY;
651     SquidHitMissCode hit_miss_code = SQUID_MISS_NONE;
652 
_SquidLogInfo_SquidLogInfo653     _SquidLogInfo() {}
654   } SquidLogInfo;
655 
656   struct State {
657     HttpTransactMagic_t m_magic = HTTP_TRANSACT_MAGIC_ALIVE;
658 
659     HttpSM *state_machine = nullptr;
660 
661     Arena arena;
662 
663     HttpConfigParams *http_config_param = nullptr;
664     CacheLookupInfo cache_info;
665     DNSLookupInfo dns_info;
666     RedirectInfo redirect_info;
667     OutboundConnTrack::TxnState outbound_conn_track_state;
668     HTTPVersion updated_server_version    = HTTP_INVALID;
669     bool force_dns                        = false;
670     MgmtByte cache_open_write_fail_action = 0;
671     ConnectionAttributes client_info;
672     ConnectionAttributes parent_info;
673     ConnectionAttributes server_info;
674 
675     Source_t source                = SOURCE_NONE;
676     Source_t pre_transform_source  = SOURCE_NONE;
677     HttpRequestFlavor_t req_flavor = REQ_FLAVOR_FWDPROXY;
678 
679     CurrentInfo current;
680     HeaderInfo hdr_info;
681     SquidLogInfo squid_codes;
682     HttpApiInfo api_info;
683     // To handle parent proxy case, we need to be
684     //  able to defer some work in building the request
685     TransactFunc_t pending_work = nullptr;
686 
687     HttpRequestData request_data;
688     ParentConfigParams *parent_params                           = nullptr;
689     std::shared_ptr<NextHopSelectionStrategy> next_hop_strategy = nullptr;
690     ParentResult parent_result;
691     CacheControlResult cache_control;
692     CacheLookupResult_t cache_lookup_result = CACHE_LOOKUP_NONE;
693 
694     StateMachineAction_t next_action                      = SM_ACTION_UNDEFINED; // out
695     StateMachineAction_t api_next_action                  = SM_ACTION_UNDEFINED; // out
696     void (*transact_return_point)(HttpTransact::State *s) = nullptr;             // out
697 
698     // We keep this so we can jump back to the upgrade handler after remap is complete
699     void (*post_remap_upgrade_return_point)(HttpTransact::State *s) = nullptr; // out
700     const char *upgrade_token_wks                                   = nullptr;
701     bool is_upgrade_request                                         = false;
702 
703     // Some WebSocket state
704     bool is_websocket        = false;
705     bool did_upgrade_succeed = false;
706 
707     char *internal_msg_buffer                       = nullptr; // out
708     char *internal_msg_buffer_type                  = nullptr; // out
709     int64_t internal_msg_buffer_size                = 0;       // out
710     int64_t internal_msg_buffer_fast_allocator_size = -1;
711 
712     int scheme               = -1;     // out
713     int next_hop_scheme      = scheme; // out
714     int orig_scheme          = scheme; // pre-mapped scheme
715     int method               = 0;
716     int cause_of_death_errno = -UNKNOWN_INTERNAL_ERROR; // in
717     Ptr<HostDBInfo> hostdb_entry;                       // Pointer to the entry we are referencing in hostdb-- to keep our ref
718     HostDBInfo host_db_info;                            // in
719 
720     ink_time_t client_request_time    = UNDEFINED_TIME; // internal
721     ink_time_t request_sent_time      = UNDEFINED_TIME; // internal
722     ink_time_t response_received_time = UNDEFINED_TIME; // internal
723     ink_time_t plugin_set_expire_time = UNDEFINED_TIME;
724 
725     char via_string[MAX_VIA_INDICES + 1];
726 
727     int64_t state_machine_id = 0;
728 
729     // new ACL filtering result (calculated immediately after remap)
730     bool client_connection_enabled = true;
731     bool acl_filtering_performed   = false;
732 
733     /// True if the response is cacheable because of negative caching configuration.
734     ///
735     /// This being true implies the following:
736     ///
737     /// * The response code was negative.
738     /// * Negative caching is enabled.
739     /// * The response is considered cacheable because of negative caching
740     ///   configuration.
741     bool is_cacheable_due_to_negative_caching_configuration = false;
742     // for authenticated content caching
743     CacheAuth_t www_auth_content = CACHE_AUTH_NONE;
744 
745     RemapPluginInst *os_response_plugin_inst = nullptr;
746     HTTPStatus http_return_code              = HTTP_STATUS_NONE;
747 
748     int api_txn_active_timeout_value      = -1;
749     int api_txn_connect_timeout_value     = -1;
750     int api_txn_dns_timeout_value         = -1;
751     int api_txn_no_activity_timeout_value = -1;
752 
753     // Used by INKHttpTxnCachedReqGet and INKHttpTxnCachedRespGet SDK functions
754     // to copy part of HdrHeap (only the writable portion) for cached response headers
755     // and request headers
756     // These ptrs are deallocate when transaction is over.
757     HdrHeapSDKHandle *cache_req_hdr_heap_handle   = nullptr;
758     HdrHeapSDKHandle *cache_resp_hdr_heap_handle  = nullptr;
759     bool api_cleanup_cache_read                   = false;
760     bool api_server_response_no_store             = false;
761     bool api_server_response_ignore               = false;
762     bool api_http_sm_shutdown                     = false;
763     bool api_modifiable_cached_resp               = false;
764     bool api_server_request_body_set              = false;
765     bool api_req_cacheable                        = false;
766     bool api_resp_cacheable                       = false;
767     bool api_server_addr_set                      = false;
768     UpdateCachedObject_t api_update_cached_object = UPDATE_CACHED_OBJECT_NONE;
769     StateMachineAction_t saved_update_next_action = SM_ACTION_UNDEFINED;
770     CacheAction_t saved_update_cache_action       = CACHE_DO_UNDEFINED;
771 
772     // Remap plugin processor support
773     UrlMappingContainer url_map;
774     host_hdr_info hh_info = {nullptr, 0, 0};
775 
776     int congestion_control_crat = 0; // Client retry after
777 
778     unsigned int filter_mask = 0;
779     char *remap_redirect     = nullptr;
780     bool reverse_proxy       = false;
781     bool url_remap_success   = false;
782 
783     bool api_skip_all_remapping = false;
784 
785     bool already_downgraded = false;
786     URL unmapped_url; // unmapped url is the effective url before remap
787 
788     // Http Range: related variables
789     RangeSetup_t range_setup = RANGE_NONE;
790     int64_t num_range_fields = 0;
791     int64_t range_output_cl  = 0;
792     RangeRecord *ranges      = nullptr;
793 
794     OverridableHttpConfigParams const *txn_conf = nullptr;
795     OverridableHttpConfigParams &
my_txn_confState796     my_txn_conf() // Storage for plugins, to avoid malloc
797     {
798       auto p = reinterpret_cast<OverridableHttpConfigParams *>(_my_txn_conf);
799 
800       ink_assert(p == txn_conf);
801 
802       return *p;
803     }
804 
805     bool transparent_passthrough = false;
806     bool range_in_cache          = false;
807 
808     // Methods
809     void
initState810     init()
811     {
812       parent_params = ParentConfig::acquire();
813     }
814 
815     // Constructor
StateState816     State()
817     {
818       int i;
819       char *via_ptr = via_string;
820 
821       for (i = 0; i < MAX_VIA_INDICES; i++) {
822         *via_ptr++ = ' ';
823       }
824 
825       via_string[VIA_CLIENT]                   = VIA_CLIENT_STRING;
826       via_string[VIA_CACHE]                    = VIA_CACHE_STRING;
827       via_string[VIA_SERVER]                   = VIA_SERVER_STRING;
828       via_string[VIA_CACHE_FILL]               = VIA_CACHE_FILL_STRING;
829       via_string[VIA_PROXY]                    = VIA_PROXY_STRING;
830       via_string[VIA_ERROR]                    = VIA_ERROR_STRING;
831       via_string[VIA_ERROR_TYPE]               = VIA_ERROR_NO_ERROR;
832       via_string[VIA_DETAIL_SEPARATOR]         = VIA_DETAIL_SEPARATOR_STRING;
833       via_string[VIA_DETAIL_TUNNEL_DESCRIPTOR] = VIA_DETAIL_TUNNEL_DESCRIPTOR_STRING;
834       via_string[VIA_DETAIL_CACHE_DESCRIPTOR]  = VIA_DETAIL_CACHE_DESCRIPTOR_STRING;
835       via_string[VIA_DETAIL_PP_DESCRIPTOR]     = VIA_DETAIL_PP_DESCRIPTOR_STRING;
836       via_string[VIA_DETAIL_SERVER_DESCRIPTOR] = VIA_DETAIL_SERVER_DESCRIPTOR_STRING;
837       via_string[MAX_VIA_INDICES]              = '\0';
838 
839       memset((void *)&host_db_info, 0, sizeof(host_db_info));
840     }
841 
842     void
destroyState843     destroy()
844     {
845       m_magic = HTTP_TRANSACT_MAGIC_DEAD;
846 
847       free_internal_msg_buffer();
848       ats_free(internal_msg_buffer_type);
849 
850       ParentConfig::release(parent_params);
851       parent_params = nullptr;
852 
853       hdr_info.client_request.destroy();
854       hdr_info.client_response.destroy();
855       hdr_info.server_request.destroy();
856       hdr_info.server_response.destroy();
857       hdr_info.transform_response.destroy();
858       hdr_info.cache_response.destroy();
859       cache_info.lookup_url_storage.destroy();
860       cache_info.parent_selection_url_storage.destroy();
861       cache_info.original_url.destroy();
862       cache_info.object_store.destroy();
863       cache_info.transform_store.destroy();
864       redirect_info.original_url.destroy();
865 
866       url_map.clear();
867       arena.reset();
868       unmapped_url.clear();
869       hostdb_entry.clear();
870       outbound_conn_track_state.clear();
871 
872       delete[] ranges;
873       ranges      = nullptr;
874       range_setup = RANGE_NONE;
875       return;
876     }
877 
878     // Little helper function to setup the per-transaction configuration copy
879     void
setup_per_txn_configsState880     setup_per_txn_configs()
881     {
882       if (txn_conf != reinterpret_cast<OverridableHttpConfigParams *>(_my_txn_conf)) {
883         txn_conf = reinterpret_cast<OverridableHttpConfigParams *>(_my_txn_conf);
884         memcpy(_my_txn_conf, &http_config_param->oride, sizeof(_my_txn_conf));
885       }
886     }
887 
888     void
free_internal_msg_bufferState889     free_internal_msg_buffer()
890     {
891       if (internal_msg_buffer) {
892         if (internal_msg_buffer_fast_allocator_size >= 0) {
893           ioBufAllocator[internal_msg_buffer_fast_allocator_size].free_void(internal_msg_buffer);
894         } else {
895           ats_free(internal_msg_buffer);
896         }
897         internal_msg_buffer = nullptr;
898       }
899       internal_msg_buffer_size = 0;
900     }
901 
902     ProxyProtocol pp_info;
903 
904     void
set_connect_failState905     set_connect_fail(int e)
906     {
907       if (e == EIO || this->current.server->connect_result == EIO) {
908         this->current.server->connect_result = e;
909       }
910       if (e != EIO) {
911         this->cause_of_death_errno = e;
912       }
913     }
914 
915   private:
916     // Make this a raw byte array, so it will be accessed through the my_txn_conf() member function.
917     alignas(OverridableHttpConfigParams) char _my_txn_conf[sizeof(OverridableHttpConfigParams)];
918 
919   }; // End of State struct.
920 
921   static void HandleBlindTunnel(State *s);
922   static void StartRemapRequest(State *s);
923   static void EndRemapRequest(State *s);
924   static void PerformRemap(State *s);
925   static void ModifyRequest(State *s);
926   static void HandleRequest(State *s);
927   static void HandleRequestBufferDone(State *s);
928   static bool handleIfRedirect(State *s);
929 
930   static void StartAccessControl(State *s);
931   static void HandleRequestAuthorized(State *s);
932   static void BadRequest(State *s);
933   static void Forbidden(State *s);
934   static void SelfLoop(State *s);
935   static void TooEarly(State *s);
936   static void OriginDead(State *s);
937   static void PostActiveTimeoutResponse(State *s);
938   static void PostInactiveTimeoutResponse(State *s);
939   static void DecideCacheLookup(State *s);
940   static void LookupSkipOpenServer(State *s);
941 
942   static void CallOSDNSLookup(State *s);
943   static void OSDNSLookup(State *s);
944   static void ReDNSRoundRobin(State *s);
945   static void PPDNSLookup(State *s);
946   static void OriginServerRawOpen(State *s);
947   static void HandleCacheOpenRead(State *s);
948   static void HandleCacheOpenReadHitFreshness(State *s);
949   static void HandleCacheOpenReadHit(State *s);
950   static void HandleCacheOpenReadMiss(State *s);
951   static void build_response_from_cache(State *s, HTTPWarningCode warning_code);
952   static void handle_cache_write_lock(State *s);
953   static void HandleResponse(State *s);
954   static void HandleUpdateCachedObject(State *s);
955   static void HandleUpdateCachedObjectContinue(State *s);
956   static void HandleStatPage(State *s);
957   static void handle_100_continue_response(State *s);
958   static void handle_transform_ready(State *s);
959   static void handle_transform_cache_write(State *s);
960   static void handle_response_from_parent(State *s);
961   static void handle_response_from_server(State *s);
962   static void delete_server_rr_entry(State *s, int max_retries);
963   static void retry_server_connection_not_open(State *s, ServerState_t conn_state, unsigned max_retries);
964   static void error_log_connection_failure(State *s, ServerState_t conn_state);
965   static void handle_server_connection_not_open(State *s);
966   static void handle_forward_server_connection_open(State *s);
967   static void handle_cache_operation_on_forward_server_response(State *s);
968   static void handle_no_cache_operation_on_forward_server_response(State *s);
969   static void merge_and_update_headers_for_cache_update(State *s);
970   static void set_headers_for_cache_write(State *s, HTTPInfo *cache_info, HTTPHdr *request, HTTPHdr *response);
971   static void set_header_for_transform(State *s, HTTPHdr *base_header);
972   static void merge_response_header_with_cached_header(HTTPHdr *cached_header, HTTPHdr *response_header);
973   static void merge_warning_header(HTTPHdr *cached_header, HTTPHdr *response_header);
974   static void SetCacheFreshnessLimit(State *s);
975   static void HandleApiErrorJump(State *);
976   static void handle_websocket_upgrade_pre_remap(State *s);
977   static void handle_websocket_upgrade_post_remap(State *s);
978   static bool handle_upgrade_request(State *s);
979   static void handle_websocket_connection(State *s);
980 
981   static void HandleCacheOpenReadPush(State *s, bool read_successful);
982   static void HandlePushResponseHdr(State *s);
983   static void HandlePushCacheWrite(State *s);
984   static void HandlePushTunnelSuccess(State *s);
985   static void HandlePushTunnelFailure(State *s);
986   static void HandlePushError(State *s, const char *reason);
987   static void HandleBadPushRespHdr(State *s);
988 
989   // Utility Methods
990   static void issue_revalidate(State *s);
991   static bool get_ka_info_from_config(State *s, ConnectionAttributes *server_info);
992   static void get_ka_info_from_host_db(State *s, ConnectionAttributes *server_info, ConnectionAttributes *client_info,
993                                        HostDBInfo *host_db_info);
994   static void setup_plugin_request_intercept(State *s);
995   static void add_client_ip_to_outgoing_request(State *s, HTTPHdr *request);
996   static RequestError_t check_request_validity(State *s, HTTPHdr *incoming_hdr);
997   static ResponseError_t check_response_validity(State *s, HTTPHdr *incoming_hdr);
998   static void set_client_request_state(State *s, HTTPHdr *incoming_hdr);
999   static bool delete_all_document_alternates_and_return(State *s, bool cache_hit);
1000   static bool does_client_request_permit_cached_response(const OverridableHttpConfigParams *p, CacheControlResult *c, HTTPHdr *h,
1001                                                          char *via_string);
1002   static bool does_client_request_permit_dns_caching(CacheControlResult *c, HTTPHdr *h);
1003   static bool does_client_request_permit_storing(CacheControlResult *c, HTTPHdr *h);
1004   static bool handle_internal_request(State *s, HTTPHdr *incoming_hdr);
1005   static bool handle_trace_and_options_requests(State *s, HTTPHdr *incoming_hdr);
1006   static void bootstrap_state_variables_from_request(State *s, HTTPHdr *incoming_request);
1007   static void initialize_state_variables_from_request(State *s, HTTPHdr *obsolete_incoming_request);
1008   static void initialize_state_variables_from_response(State *s, HTTPHdr *incoming_response);
1009   static bool is_server_negative_cached(State *s);
1010   static bool is_cache_response_returnable(State *s);
1011   static bool is_stale_cache_response_returnable(State *s);
1012   static bool need_to_revalidate(State *s);
1013   static bool url_looks_dynamic(URL *url);
1014   static bool is_request_cache_lookupable(State *s);
1015   static bool is_request_valid(State *s, HTTPHdr *incoming_request);
1016   static bool is_request_retryable(State *s);
1017 
1018   static bool is_response_cacheable(State *s, HTTPHdr *request, HTTPHdr *response);
1019   static bool is_response_valid(State *s, HTTPHdr *incoming_response);
1020 
1021   static void process_quick_http_filter(State *s, int method);
1022   static bool will_this_request_self_loop(State *s);
1023   static bool is_request_likely_cacheable(State *s, HTTPHdr *request);
1024   static bool is_cache_hit(CacheLookupResult_t r);
1025   static bool is_fresh_cache_hit(CacheLookupResult_t r);
1026 
1027   static void build_request(State *s, HTTPHdr *base_request, HTTPHdr *outgoing_request, HTTPVersion outgoing_version);
1028   static void build_response(State *s, HTTPHdr *base_response, HTTPHdr *outgoing_response, HTTPVersion outgoing_version,
1029                              HTTPStatus status_code, const char *reason_phrase = nullptr);
1030   static void build_response(State *s, HTTPHdr *base_response, HTTPHdr *outgoing_response, HTTPVersion outgoing_version);
1031   static void build_response(State *s, HTTPHdr *outgoing_response, HTTPVersion outgoing_version, HTTPStatus status_code,
1032                              const char *reason_phrase = nullptr);
1033 
1034   static void build_response_copy(State *s, HTTPHdr *base_response, HTTPHdr *outgoing_response, HTTPVersion outgoing_version);
1035   static void handle_content_length_header(State *s, HTTPHdr *header, HTTPHdr *base);
1036   static void change_response_header_because_of_range_request(State *s, HTTPHdr *header);
1037 
1038   static void handle_request_keep_alive_headers(State *s, HTTPVersion ver, HTTPHdr *heads);
1039   static void handle_response_keep_alive_headers(State *s, HTTPVersion ver, HTTPHdr *heads);
1040   static int get_max_age(HTTPHdr *response);
1041   static int calculate_document_freshness_limit(State *s, HTTPHdr *response, time_t response_date, bool *heuristic);
1042   static Freshness_t what_is_document_freshness(State *s, HTTPHdr *client_request, HTTPHdr *cached_obj_response);
1043   static Authentication_t AuthenticationNeeded(const OverridableHttpConfigParams *p, HTTPHdr *client_request,
1044                                                HTTPHdr *obj_response);
1045   static void handle_parent_died(State *s);
1046   static void handle_server_died(State *s);
1047   static void build_error_response(State *s, HTTPStatus status_code, const char *reason_phrase_or_null,
1048                                    const char *error_body_type);
1049   static void build_redirect_response(State *s);
1050   static const char *get_error_string(int erno);
1051 
1052   // the stat functions
1053   static void update_size_and_time_stats(State *s, ink_hrtime total_time, ink_hrtime user_agent_write_time,
1054                                          ink_hrtime origin_server_read_time, int user_agent_request_header_size,
1055                                          int64_t user_agent_request_body_size, int user_agent_response_header_size,
1056                                          int64_t user_agent_response_body_size, int origin_server_request_header_size,
1057                                          int64_t origin_server_request_body_size, int origin_server_response_header_size,
1058                                          int64_t origin_server_response_body_size, int pushed_response_header_size,
1059                                          int64_t pushed_response_body_size, const TransactionMilestones &milestones);
1060   static void histogram_request_document_size(State *s, int64_t size);
1061   static void histogram_response_document_size(State *s, int64_t size);
1062   static void user_agent_connection_speed(State *s, ink_hrtime transfer_time, int64_t nbytes);
1063   static void origin_server_connection_speed(State *s, ink_hrtime transfer_time, int64_t nbytes);
1064   static void client_result_stat(State *s, ink_hrtime total_time, ink_hrtime request_process_time);
1065   static void delete_warning_value(HTTPHdr *to_warn, HTTPWarningCode warning_code);
1066   static bool is_connection_collapse_checks_success(State *s); // YTS Team, yamsat
1067 };
1068 
1069 typedef void (*TransactEntryFunc_t)(HttpTransact::State *s);
1070 
1071 /* The spec says about message body the following:
1072  *
1073  * All responses to the HEAD and CONNECT request method
1074  * MUST NOT include a message-body, even though the presence
1075  * of entity-header fields might lead one to believe they do.
1076  *
1077  * All 1xx (informational), 204 (no content), and 304 (not modified)
1078  * responses MUST NOT include a message-body.
1079  *
1080  * Refer : [https://tools.ietf.org/html/rfc7231#section-4.3.6]
1081  */
1082 inline bool
is_response_body_precluded(HTTPStatus status_code)1083 is_response_body_precluded(HTTPStatus status_code)
1084 {
1085   if (((status_code != HTTP_STATUS_OK) &&
1086        ((status_code == HTTP_STATUS_NOT_MODIFIED) || ((status_code < HTTP_STATUS_OK) && (status_code >= HTTP_STATUS_CONTINUE)) ||
1087         (status_code == HTTP_STATUS_NO_CONTENT)))) {
1088     return true;
1089   } else {
1090     return false;
1091   }
1092 }
1093 
1094 inline bool
is_response_body_precluded(HTTPStatus status_code,int method)1095 is_response_body_precluded(HTTPStatus status_code, int method)
1096 {
1097   if ((method == HTTP_WKSIDX_HEAD) || (method == HTTP_WKSIDX_CONNECT) || is_response_body_precluded(status_code)) {
1098     return true;
1099   } else {
1100     return false;
1101   }
1102 }
1103 
1104 inkcoreapi extern ink_time_t ink_local_time();
1105