00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "libts.h"
00025 
00026 #include <strings.h>
00027 #include <math.h>
00028 
00029 #include "HttpTransact.h"
00030 #include "HttpTransactHeaders.h"
00031 #include "HttpSM.h"
00032 #include "HttpCacheSM.h"        
00033 #include "HttpDebugNames.h"
00034 #include "time.h"
00035 #include "ParseRules.h"
00036 #include "HTTP.h"
00037 #include "HdrUtils.h"
00038 #include "MimeTable.h"
00039 #include "logging/Log.h"
00040 #include "logging/LogUtils.h"
00041 #include "Error.h"
00042 #include "CacheControl.h"
00043 #include "ControlMatcher.h"
00044 #include "ReverseProxy.h"
00045 #include "HttpBodyFactory.h"
00046 #include "StatPages.h"
00047 #include "HttpClientSession.h"
00048 #include "I_Machine.h"
00049 
00050 static char range_type[] = "multipart/byteranges; boundary=RANGE_SEPARATOR";
00051 #define RANGE_NUMBERS_LENGTH 60
00052 
00053 #define HTTP_INCREMENT_TRANS_STAT(X) update_stat(s, X, 1);
00054 #define HTTP_SUM_TRANS_STAT(X,S) update_stat(s, X, (ink_statval_t) S);
00055 
00056 #define TRANSACT_REMEMBER(_s,_e,_d) \
00057 { \
00058     HttpSM *sm = (_s)->state_machine; \
00059     sm->history[sm->history_pos % HISTORY_SIZE].file  = __FILE__; \
00060     sm->history[sm->history_pos % HISTORY_SIZE].line  = __LINE__; \
00061     sm->history[sm->history_pos % HISTORY_SIZE].event = _e; \
00062     sm->history[sm->history_pos % HISTORY_SIZE].data = (void *)_d; \
00063     sm->history_pos += 1; \
00064 }
00065 
00066 #define DebugTxn(tag, ...) DebugSpecific((s->state_machine->debug_on), tag, __VA_ARGS__)
00067 
00068 extern HttpBodyFactory *body_factory;
00069 extern int cache_config_vary_on_user_agent;
00070 
00071 static const char local_host_ip_str[] = "127.0.0.1";
00072 
00073 
00074 
00075 
00076 inline static HTTPKeepAlive
00077 is_header_keep_alive(const HTTPVersion & http_version, const HTTPVersion & request_http_version, MIMEField* con_hdr    )
00078 {
00079   enum
00080   {
00081     CON_TOKEN_NONE = 0,
00082     CON_TOKEN_KEEP_ALIVE,
00083     CON_TOKEN_CLOSE
00084   };
00085 
00086   int con_token = CON_TOKEN_NONE;
00087   HTTPKeepAlive keep_alive = HTTP_NO_KEEPALIVE;
00088   
00089 
00090   if (con_hdr) {
00091     int val_len;
00092     const char *val;
00093 
00094     if (!con_hdr->has_dups()) { 
00095       val = con_hdr->value_get(&val_len);
00096       if (ptr_len_casecmp(val, val_len, "keep-alive", 10) == 0) {
00097         con_token = CON_TOKEN_KEEP_ALIVE;
00098       } else if (ptr_len_casecmp(val, val_len, "close", 5) == 0) {
00099         con_token = CON_TOKEN_CLOSE;
00100       }
00101     }
00102 
00103     if (con_token == CON_TOKEN_NONE) {
00104       HdrCsvIter iter;
00105 
00106       val = iter.get_first(con_hdr, &val_len);
00107 
00108       while (val) {
00109         if (ptr_len_casecmp(val, val_len, "keep-alive", 10) == 0) {
00110           con_token = CON_TOKEN_KEEP_ALIVE;
00111           
00112 
00113 
00114 
00115           break;
00116         } else if (ptr_len_casecmp(val, val_len, "close", 5) == 0) {
00117           con_token = CON_TOKEN_CLOSE;
00118           
00119 
00120 
00121 
00122           break;
00123         } else {
00124           
00125         }
00126         val = iter.get_next(&val_len);
00127       }
00128     }
00129   }
00130 
00131   if (HTTPVersion(1, 0) == http_version) {
00132     keep_alive = (con_token == CON_TOKEN_KEEP_ALIVE) ? (HTTP_KEEPALIVE) : (HTTP_NO_KEEPALIVE);
00133   } else if (HTTPVersion(1, 1) == http_version) {
00134     
00135     
00136     
00137     
00138     keep_alive = ((con_token == CON_TOKEN_KEEP_ALIVE) ||
00139                   (con_token == CON_TOKEN_NONE && HTTPVersion(1, 1) == request_http_version)) ? (HTTP_KEEPALIVE)
00140       : (HTTP_NO_KEEPALIVE);
00141   } else {
00142     keep_alive = HTTP_NO_KEEPALIVE;
00143   }
00144 
00145   return (keep_alive);
00146 }
00147 
00148 inline static bool
00149 is_request_conditional(HTTPHdr* header)
00150 {
00151   uint64_t mask = (MIME_PRESENCE_IF_UNMODIFIED_SINCE |
00152                  MIME_PRESENCE_IF_MODIFIED_SINCE | MIME_PRESENCE_IF_RANGE |
00153                  MIME_PRESENCE_IF_MATCH | MIME_PRESENCE_IF_NONE_MATCH);
00154   return (header->presence(mask) && (header->method_get_wksidx() == HTTP_WKSIDX_GET ||
00155                           header->method_get_wksidx() == HTTP_WKSIDX_HEAD));
00156 }
00157 
00158 static inline bool
00159 is_port_in_range(int port, HttpConfigPortRange *pr)
00160 {
00161   while (pr) {
00162     if (pr->low == -1) {
00163       return true;
00164     } else if ((pr->low <= port) && (pr->high >= port)) {
00165       return true;
00166     }
00167 
00168     pr = pr->next;
00169   }
00170 
00171   return false;
00172 }
00173 
00174 inline static void
00175 update_cache_control_information_from_config(HttpTransact::State* s)
00176 {
00177   getCacheControl(&s->cache_control, &s->request_data, s->txn_conf);
00178 
00179   s->cache_info.directives.does_config_permit_lookup &= (s->cache_control.never_cache == false);
00180   s->cache_info.directives.does_config_permit_storing &= (s->cache_control.never_cache == false);
00181 
00182   s->cache_info.directives.does_client_permit_storing =
00183     HttpTransact::does_client_request_permit_storing(&s->cache_control, &s->hdr_info.client_request);
00184 
00185   s->cache_info.directives.does_client_permit_lookup =
00186     HttpTransact::does_client_request_permit_cached_response(s->txn_conf, &s->cache_control,
00187                                                              &s->hdr_info.client_request, s->via_string);
00188 
00189   s->cache_info.directives.does_client_permit_dns_storing =
00190     HttpTransact::does_client_request_permit_dns_caching(&s->cache_control, &s->hdr_info.client_request);
00191 
00192   if (s->client_info.http_version == HTTPVersion(0, 9)) {
00193     s->cache_info.directives.does_client_permit_lookup = false;
00194     s->cache_info.directives.does_client_permit_storing = false;
00195   }
00196 
00197   
00198   if (s->cache_control.cache_responses_to_cookies >= 0)
00199     s->txn_conf->cache_responses_to_cookies = s->cache_control.cache_responses_to_cookies;
00200 }
00201 
00202 inline bool
00203 HttpTransact::is_server_negative_cached(State* s)
00204 {
00205   if (s->host_db_info.app.http_data.last_failure != 0 &&
00206       s->host_db_info.app.http_data.last_failure + s->txn_conf->down_server_timeout > s->client_request_time) {
00207     return true;
00208   } else {
00209     
00210     
00211     
00212     
00213     
00214     if (s->client_request_time + s->txn_conf->down_server_timeout < s->host_db_info.app.http_data.last_failure) {
00215       s->host_db_info.app.http_data.last_failure = 0;
00216       ink_assert(!"extreme clock skew");
00217       return true;
00218     }
00219     return false;
00220   }
00221 }
00222 
00223 inline static void
00224 update_current_info(HttpTransact::CurrentInfo* into, HttpTransact::ConnectionAttributes* from,
00225                     HttpTransact::LookingUp_t who, int attempts)
00226 {
00227   into->request_to = who;
00228   into->server = from;
00229   into->attempts = attempts;
00230 }
00231 
00232 inline static void
00233 update_dns_info(HttpTransact::DNSLookupInfo* dns, HttpTransact::CurrentInfo* from, int attempts,
00234                 Arena* )
00235 {
00236   dns->looking_up = from->request_to;
00237   dns->lookup_name = from->server->name;
00238   dns->attempts = attempts;
00239 }
00240 
00241 inline static HTTPHdr *
00242 find_appropriate_cached_resp(HttpTransact::State* s)
00243 {
00244   HTTPHdr *c_resp = NULL;
00245 
00246   if (s->cache_info.object_store.valid()) {
00247     c_resp = s->cache_info.object_store.response_get();
00248     if (c_resp != NULL && c_resp->valid())
00249       return c_resp;
00250   }
00251 
00252   ink_assert(s->cache_info.object_read != NULL);
00253   return s->cache_info.object_read->response_get();
00254 }
00255 
00256 inline static bool
00257 is_negative_caching_appropriate(HttpTransact::State* s)
00258 {
00259   if (!s->txn_conf->negative_caching_enabled || !s->hdr_info.server_response.valid())
00260     return false;
00261 
00262   switch (s->hdr_info.server_response.status_get()) {
00263   case HTTP_STATUS_NO_CONTENT:
00264   case HTTP_STATUS_USE_PROXY:
00265   case HTTP_STATUS_BAD_REQUEST:
00266   case HTTP_STATUS_FORBIDDEN:
00267   case HTTP_STATUS_NOT_FOUND:
00268   case HTTP_STATUS_METHOD_NOT_ALLOWED:
00269   case HTTP_STATUS_REQUEST_URI_TOO_LONG:
00270   case HTTP_STATUS_INTERNAL_SERVER_ERROR:
00271   case HTTP_STATUS_NOT_IMPLEMENTED:
00272   case HTTP_STATUS_BAD_GATEWAY:
00273   case HTTP_STATUS_SERVICE_UNAVAILABLE:
00274   case HTTP_STATUS_GATEWAY_TIMEOUT:
00275     return true;
00276   default:
00277     break;
00278   }
00279 
00280   return false;
00281 }
00282 
00283 inline static HttpTransact::LookingUp_t
00284 find_server_and_update_current_info(HttpTransact::State* s)
00285 {
00286   URL *url = s->hdr_info.client_request.url_get();
00287   int host_len;
00288   const char *host = s->hdr_info.client_request.host_get(&host_len);
00289 
00290   if (ptr_len_cmp(host, host_len, local_host_ip_str, sizeof(local_host_ip_str) - 1) == 0) {
00291     
00292     
00293     
00294     s->parent_result.r = PARENT_DIRECT;
00295   } else if (url->scheme_get_wksidx() == URL_WKSIDX_HTTPS) {
00296     
00297     s->parent_result.r = PARENT_DIRECT;
00298   } else if (s->method == HTTP_WKSIDX_CONNECT && s->http_config_param->disable_ssl_parenting) {
00299     s->parent_result.r = PARENT_DIRECT;
00300   } else if (s->http_config_param->uncacheable_requests_bypass_parent &&
00301              s->http_config_param->no_dns_forward_to_parent == 0 &&
00302              !HttpTransact::is_request_cache_lookupable(s)) {
00303     
00304     
00305     
00306     
00307     
00308     
00309     DebugTxn("http_trans", "request not cacheable, so bypass parent");
00310     s->parent_result.r = PARENT_DIRECT;
00311   } else {
00312     switch (s->parent_result.r) {
00313     case PARENT_UNDEFINED:
00314       s->parent_params->findParent(&s->request_data, &s->parent_result);
00315       break;
00316     case PARENT_SPECIFIED:
00317       s->parent_params->nextParent(&s->request_data, &s->parent_result);
00318 
00319       
00320       
00321       
00322       
00323       if (s->parent_result.r == PARENT_DIRECT && s->http_config_param->no_dns_forward_to_parent != 0) {
00324         ink_assert(!ats_is_ip(&s->server_info.addr));
00325         s->parent_result.r = PARENT_FAIL;
00326       }
00327       break;
00328     case PARENT_FAIL:
00329       
00330       
00331       
00332       
00333       
00334       if (!s->parent_params->apiParentExists(&s->request_data) && s->parent_result.rec->bypass_ok() &&
00335           s->http_config_param->no_dns_forward_to_parent == 0) {
00336         s->parent_result.r = PARENT_DIRECT;
00337       }
00338       break;
00339     default:
00340       ink_assert(0);
00341       
00342     case PARENT_DIRECT:
00343       
00344       
00345       
00346       break;
00347     }
00348   }
00349 
00350   switch (s->parent_result.r) {
00351   case PARENT_SPECIFIED:
00352     s->parent_info.name = s->arena.str_store(s->parent_result.hostname, strlen(s->parent_result.hostname));
00353     s->parent_info.port = s->parent_result.port;
00354     update_current_info(&s->current, &s->parent_info, HttpTransact::PARENT_PROXY, (s->current.attempts)++);
00355     update_dns_info(&s->dns_info, &s->current, 0, &s->arena);
00356     ink_assert(s->dns_info.looking_up == HttpTransact::PARENT_PROXY);
00357     s->next_hop_scheme = URL_WKSIDX_HTTP;
00358 
00359     return HttpTransact::PARENT_PROXY;
00360   case PARENT_FAIL:
00361     
00362     s->current.request_to = HttpTransact::HOST_NONE;
00363     return HttpTransact::HOST_NONE;
00364 
00365   case PARENT_DIRECT:
00366     
00367   default:
00368     update_current_info(&s->current, &s->server_info, HttpTransact::ORIGIN_SERVER, (s->current.attempts)++);
00369     update_dns_info(&s->dns_info, &s->current, 0, &s->arena);
00370     ink_assert(s->dns_info.looking_up == HttpTransact::ORIGIN_SERVER);
00371     s->next_hop_scheme = s->scheme;
00372     return HttpTransact::ORIGIN_SERVER;
00373   }
00374 }
00375 
00376 inline static bool
00377 do_cookies_prevent_caching(int cookies_conf, HTTPHdr* request, HTTPHdr* response, HTTPHdr* cached_request = NULL)
00378 {
00379   enum CookiesConfig
00380   {
00381     COOKIES_CACHE_NONE = 0,     
00382     COOKIES_CACHE_ALL = 1,      
00383     COOKIES_CACHE_IMAGES = 2,   
00384     COOKIES_CACHE_ALL_BUT_TEXT = 3,     
00385     COOKIES_CACHE_ALL_BUT_TEXT_EXT = 4  
00386       
00387   };
00388 
00389   const char *content_type = NULL;
00390   int str_len;
00391 
00392 #ifdef DEBUG
00393   ink_assert(request->type_get() == HTTP_TYPE_REQUEST);
00394   ink_assert(response->type_get() == HTTP_TYPE_RESPONSE);
00395   if (cached_request) {
00396     ink_assert(cached_request->type_get() == HTTP_TYPE_REQUEST);
00397   }
00398 #endif
00399 
00400   
00401   if ((CookiesConfig) cookies_conf == COOKIES_CACHE_ALL) {
00402     return false;
00403   }
00404 
00405   
00406   
00407   
00408   
00409   
00410   
00411   
00412 
00413   
00414   
00415   
00416   
00417   if (!response->presence(MIME_PRESENCE_SET_COOKIE) &&
00418       !request->presence(MIME_PRESENCE_COOKIE) && (cached_request == NULL
00419                                                    || !cached_request->presence(MIME_PRESENCE_COOKIE))) {
00420     return false;
00421   }
00422 
00423   
00424   
00425   if ((CookiesConfig) cookies_conf == COOKIES_CACHE_NONE) {
00426     return true;
00427   }
00428   
00429   content_type = response->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &str_len);
00430 
00431   if ((CookiesConfig) cookies_conf == COOKIES_CACHE_IMAGES) {
00432     if (content_type && str_len >= 5 && memcmp(content_type, "image", 5) == 0) {
00433       
00434       return false;
00435     }
00436     return true;                
00437   }
00438   
00439   
00440   
00441 
00442   if (content_type && str_len >= 4 && memcmp(content_type, "text", 4) == 0) {   
00443     
00444     
00445     
00446     
00447     if ((CookiesConfig) cookies_conf == COOKIES_CACHE_ALL_BUT_TEXT_EXT &&
00448         ((!response->presence(MIME_PRESENCE_SET_COOKIE)) || response->is_cache_control_set(HTTP_VALUE_PUBLIC))) {
00449       return false;
00450     }
00451     return true;
00452   }
00453   return false;                 
00454 }
00455 
00456 
00457 inline static bool
00458 does_method_require_cache_copy_deletion(const HttpConfigParams *http_config_param, const int method)
00459 {
00460   return ((method != HTTP_WKSIDX_GET) &&
00461           (method == HTTP_WKSIDX_DELETE || method == HTTP_WKSIDX_PURGE ||
00462            method == HTTP_WKSIDX_PUT ||
00463            (http_config_param->cache_post_method != 1 && method == HTTP_WKSIDX_POST)));
00464 }
00465 
00466 
00467 inline static
00468 HttpTransact::StateMachineAction_t
00469 how_to_open_connection(HttpTransact::State* s)
00470 {
00471   ink_assert(s->pending_work == NULL);
00472 
00473   
00474   
00475   
00476   
00477   
00478   
00479   
00480   
00481   
00482   switch (s->cache_info.action) {
00483   case HttpTransact::CACHE_PREPARE_TO_DELETE:
00484   case HttpTransact::CACHE_PREPARE_TO_UPDATE:
00485   case HttpTransact::CACHE_PREPARE_TO_WRITE:
00486     s->transact_return_point = HttpTransact::handle_cache_write_lock;
00487     return HttpTransact::SM_ACTION_CACHE_ISSUE_WRITE;
00488   default:
00489     
00490     
00491     
00492     
00493     
00494     break;
00495   }
00496 
00497   if (s->method == HTTP_WKSIDX_CONNECT && s->parent_result.r != PARENT_SPECIFIED) {
00498     s->cdn_saved_next_action = HttpTransact::SM_ACTION_ORIGIN_SERVER_RAW_OPEN;
00499   } else {
00500     s->cdn_saved_next_action = HttpTransact::SM_ACTION_ORIGIN_SERVER_OPEN;
00501   }
00502 
00503   
00504   
00505   
00506   
00507 
00508   if ((url_remap_mode == HttpTransact::URL_REMAP_FOR_OS) &&
00509       (s->current.request_to == HttpTransact::ORIGIN_SERVER) && !s->cdn_remap_complete) {
00510     DebugTxn("cdn", "*** START CDN Remapping *** CDN mode = %d", url_remap_mode);
00511 
00512     char *remap_redirect = NULL;
00513     int host_len;
00514     const char *host;
00515 
00516     
00517     s->hdr_info.server_request.url_set(s->hdr_info.client_request.url_get());
00518 
00519     
00520     
00521     if (request_url_remap(s, &s->hdr_info.server_request, &remap_redirect)) {
00522       ink_assert(!remap_redirect);      
00523       HttpTransact::initialize_state_variables_for_origin_server(s, &s->hdr_info.server_request, true);
00524       DebugTxn("cdn", "Converting proxy request to server request");
00525       
00526       if (                      
00527            !s->hdr_info.server_request.presence(MIME_PRESENCE_HOST)) {
00528         URL *url = s->hdr_info.server_request.url_get();
00529         host = url->host_get(&host_len);
00530         
00531         
00532         int port = url->port_get();
00533         if (port != url_canonicalize_port(URL_TYPE_HTTP, 0)) {
00534           char *buf = (char *)alloca(host_len + 15);
00535           memcpy(buf, host, host_len); 
00536           host_len += snprintf(buf + host_len, 15, ":%d", port);
00537           s->hdr_info.server_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, buf, host_len);
00538         } else {
00539           s->hdr_info.server_request.value_set(MIME_FIELD_HOST, MIME_LEN_HOST, host, host_len);
00540         }
00541         ats_free(remap_redirect);  
00542       }
00543       
00544       if (s->current.server == &s->server_info && s->next_hop_scheme == URL_WKSIDX_HTTP) {
00545         DebugTxn("cdn", "Removing host name from URL");
00546         HttpTransactHeaders::remove_host_name_from_url(&s->hdr_info.server_request);
00547       }
00548     }                           
00549     if (is_debug_tag_set("cdn")) {
00550       char *d_url = s->hdr_info.server_request.url_get()->string_get(NULL);
00551       if (d_url)
00552         DebugTxn("cdn", "URL: %s", d_url);
00553       char *d_hst = (char *) s->hdr_info.server_request.value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_len);
00554       if (d_hst)
00555         DebugTxn("cdn", "Host Hdr: %s", d_hst);
00556       ats_free(d_url);
00557     }
00558     s->cdn_remap_complete = true;       
00559     s->transact_return_point = HttpTransact::OSDNSLookup;
00560     ink_assert(s->next_action);
00561     ink_assert(s->cdn_saved_next_action);
00562     return HttpTransact::SM_ACTION_DNS_LOOKUP;
00563   }
00564 
00565   if (!s->already_downgraded) { 
00566     (&s->hdr_info.server_request)->version_set(HTTPVersion(1, 1));
00567     HttpTransactHeaders::convert_request(s->current.server->http_version, &s->hdr_info.server_request);
00568   }
00569 
00570   ink_assert(s->cdn_saved_next_action == HttpTransact::SM_ACTION_ORIGIN_SERVER_OPEN ||
00571                     s->cdn_saved_next_action == HttpTransact::SM_ACTION_ORIGIN_SERVER_RAW_OPEN);
00572   return s->cdn_saved_next_action;
00573 }
00574 
00575 
00576 
00577 
00578 
00579 
00580 
00581 
00582 
00583 
00584 
00585 
00586 
00587 void
00588 HttpTransact::BadRequest(State* s)
00589 {
00590   DebugTxn("http_trans", "[BadRequest]" "parser marked request bad");
00591   bootstrap_state_variables_from_request(s, &s->hdr_info.client_request);
00592   build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid HTTP Request", "request#syntax_error", NULL);
00593   TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
00594 }
00595 
00596 void
00597 HttpTransact::HandleBlindTunnel(State* s)
00598 {
00599   DebugTxn("http_trans", "[HttpTransact::HandleBlindTunnel]");
00600 
00601   
00602   
00603   s->hdr_info.client_request.create(HTTP_TYPE_REQUEST);
00604   s->hdr_info.client_request.method_set(HTTP_METHOD_CONNECT, HTTP_LEN_CONNECT);
00605   URL u;
00606   s->hdr_info.client_request.url_create(&u);
00607   u.scheme_set(URL_SCHEME_TUNNEL, URL_LEN_TUNNEL);
00608   s->hdr_info.client_request.url_set(&u);
00609 
00610   
00611   
00612   
00613   HTTPVersion ver(0, 9);
00614   s->hdr_info.client_request.version_set(ver);
00615 
00616   char new_host[INET6_ADDRSTRLEN];
00617   ats_ip_ntop(s->state_machine->ua_session->get_netvc()->get_local_addr(), new_host, sizeof(new_host));
00618 
00619   s->hdr_info.client_request.url_get()->host_set(new_host, strlen(new_host));
00620   s->hdr_info.client_request.url_get()->port_set(s->state_machine->ua_session->get_netvc()->get_local_port());
00621 
00622   
00623   bootstrap_state_variables_from_request(s, &s->hdr_info.client_request);
00624 
00625   if (is_debug_tag_set("http_trans")) {
00626     int host_len;
00627     const char *host = s->hdr_info.client_request.url_get()->host_get(&host_len);
00628     DebugTxn("http_trans", "[HandleBlindTunnel] destination set to %.*s:%d", host_len, host,
00629           s->hdr_info.client_request.url_get()->port_get());
00630   }
00631   
00632   
00633   
00634 
00635   
00636   bool url_remap_success = false;
00637   char *remap_redirect = NULL;
00638 
00639   if (s->transparent_passthrough) {
00640     url_remap_success = true;
00641   } else if (url_remap_mode == URL_REMAP_DEFAULT || url_remap_mode == URL_REMAP_ALL) {
00642     
00643     
00644     url_remap_success = request_url_remap(s, &s->hdr_info.client_request, &remap_redirect);
00645   }
00646   
00647   
00648   
00649   
00650   if (url_remap_success == false || remap_redirect != NULL) {
00651     
00652     
00653     
00654     build_error_response(s, HTTP_STATUS_INTERNAL_SERVER_ERROR, "Port Forwarding Error", "default", NULL);
00655 
00656     int host_len;
00657     const char *host = s->hdr_info.client_request.url_get()->host_get(&host_len);
00658 
00659     Log::error("Forwarded port error: request with destination %.*s:%d "
00660                "does not have a mapping", host_len, host, s->hdr_info.client_request.url_get()->port_get());
00661 
00662     TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
00663   }
00664   
00665   s->current.mode = TUNNELLING_PROXY;
00666 
00667   
00668   
00669   HandleRequest(s);
00670 }
00671 
00672 bool
00673 HttpTransact::perform_accept_encoding_filtering(State* s)
00674 {
00675   HttpUserAgent_RegxEntry *uae;
00676   HTTPHdr *client_request;
00677   MIMEField *accept_field;
00678   MIMEField *usragent_field;
00679   char tmp_ua_buf[1024], *c;
00680   char const *u_agent = NULL;
00681   int u_agent_len = 0;
00682   bool retcode = false;
00683   bool ua_match = false;
00684 
00685   client_request = &s->hdr_info.client_request;
00686 
00687   
00688   if ((usragent_field = client_request->field_find(MIME_FIELD_USER_AGENT, MIME_LEN_USER_AGENT)) != 0 &&
00689       (u_agent = usragent_field->value_get(&u_agent_len)) != 0 && u_agent_len > 0) {
00690     if (u_agent_len >= (int) sizeof(tmp_ua_buf))
00691       u_agent_len = (int) (sizeof(tmp_ua_buf) - 1);
00692     memcpy(tmp_ua_buf, u_agent, u_agent_len);
00693     tmp_ua_buf[u_agent_len] = '\0';
00694 
00695     
00696     
00697     if ((c = strstr(tmp_ua_buf, "MSIE")) != NULL) {
00698       if (c[5] >= '7' && c[5] <= '9')
00699         return false;           
00700       ua_match = true;
00701     } else if (!strncasecmp(tmp_ua_buf, "mozilla", 7)) {
00702       if (tmp_ua_buf[8] >= '5' && tmp_ua_buf[8] <= '9')
00703         return false;           
00704       ua_match = true;
00705     }
00706 
00707     
00708     if (!ua_match && HttpConfig::user_agent_list) {
00709       for (uae = HttpConfig::user_agent_list; uae && !ua_match; uae = uae->next) {
00710         switch (uae->stype) {
00711         case HttpUserAgent_RegxEntry::STRTYPE_SUBSTR_CASE:     
00712           if (u_agent_len >= uae->user_agent_str_size &&
00713               !memcmp(tmp_ua_buf, uae->user_agent_str, uae->user_agent_str_size))
00714             ua_match = true;
00715           break;
00716         case HttpUserAgent_RegxEntry::STRTYPE_SUBSTR_NCASE:    
00717           if (u_agent_len >= uae->user_agent_str_size &&
00718               !strncasecmp(uae->user_agent_str, tmp_ua_buf, uae->user_agent_str_size))
00719             ua_match = true;
00720           break;
00721         case HttpUserAgent_RegxEntry::STRTYPE_REGEXP:  
00722           if (uae->regx_valid && !pcre_exec(uae->regx, NULL, tmp_ua_buf, u_agent_len, 0, 0, NULL, 0))
00723             ua_match = true;
00724           break;
00725         default:               
00726           
00727           ink_error
00728             ("[HttpTransact::perform_accept_encoding_filtering] - get unknown User-Agent string type - bad initialization");
00729         };
00730       }
00731     }
00732 
00733     
00734 
00735 
00736 
00737 
00738 
00739     if (ua_match) {
00740       DebugTxn("http_trans", "HttpTransact::ModifyRequest, insert identity Accept-Encoding");
00741       accept_field = client_request->field_find(MIME_FIELD_ACCEPT_ENCODING, MIME_LEN_ACCEPT_ENCODING);
00742       if (!accept_field) {
00743         accept_field = client_request->field_create(MIME_FIELD_ACCEPT_ENCODING, MIME_LEN_ACCEPT_ENCODING);
00744         if (accept_field)
00745           client_request->field_attach(accept_field);
00746       }
00747       if (accept_field) {
00748         client_request->field_value_set(accept_field, HTTP_VALUE_IDENTITY, HTTP_LEN_IDENTITY);
00749       }
00750     }
00751     retcode = true;
00752   }                             
00753   return retcode;
00754 }
00755 
00756 void
00757 HttpTransact::StartRemapRequest(State* s)
00758 {
00759   
00760   if (s->api_skip_all_remapping) {
00761     Debug ("http_trans", "API request to skip remapping");
00762 
00763     if (s->is_upgrade_request && s->post_remap_upgrade_return_point) {
00764       TRANSACT_RETURN(SM_ACTION_POST_REMAP_SKIP, s->post_remap_upgrade_return_point);
00765     }
00766 
00767     TRANSACT_RETURN(SM_ACTION_POST_REMAP_SKIP, HttpTransact::HandleRequest);
00768   }
00769   
00770   DebugTxn("http_trans", "START HttpTransact::StartRemapRequest");
00771 
00772 
00773 
00774 
00775 
00776 
00777 
00778 
00779   HTTPHdr *incoming_request = &s->hdr_info.client_request;
00780   URL *url = incoming_request->url_get();
00781   int host_len, path_len;
00782   const char *host = url->host_get(&host_len);
00783   const char *path = url->path_get(&path_len);
00784   const int port = url->port_get();
00785 
00786   const char syntxt[] = "synthetic.txt";
00787 
00788   s->cop_test_page = (ptr_len_cmp(host, host_len, local_host_ip_str, sizeof(local_host_ip_str) - 1) == 0) &&
00789     (ptr_len_cmp(path, path_len, syntxt, sizeof(syntxt) - 1) == 0) &&
00790     port == s->http_config_param->autoconf_port &&
00791     s->method == HTTP_WKSIDX_GET &&
00792     s->orig_scheme == URL_WKSIDX_HTTP &&
00793     (!s->http_config_param->autoconf_localhost_only || ats_ip4_addr_cast(&s->client_info.addr.sa) == htonl(INADDR_LOOPBACK));
00794 
00795 
00796   
00797   
00798   
00799 
00800 
00801 
00802   
00803   
00804   
00805   
00806   
00807   
00808   
00809   
00810 
00811 
00812   if (is_debug_tag_set("http_chdr_describe") || is_debug_tag_set("http_trans")) {
00813     DebugTxn("http_trans", "Before Remapping:");
00814     obj_describe(s->hdr_info.client_request.m_http, 1);
00815   }
00816 
00817   if (url_remap_mode == URL_REMAP_DEFAULT || url_remap_mode == URL_REMAP_ALL) {
00818     if (s->http_config_param->referer_filter_enabled) {
00819       s->filter_mask = URL_REMAP_FILTER_REFERER;
00820       if (s->http_config_param->referer_format_redirect)
00821         s->filter_mask |= URL_REMAP_FILTER_REDIRECT_FMT;
00822     }
00823   }
00824 
00825   DebugTxn("http_trans", "END HttpTransact::StartRemapRequest");
00826   TRANSACT_RETURN(SM_ACTION_API_PRE_REMAP, HttpTransact::PerformRemap);
00827 }
00828 
00829 void HttpTransact::PerformRemap(State *s)
00830 {
00831   DebugTxn("http_trans","Inside PerformRemap");
00832   TRANSACT_RETURN(SM_ACTION_REMAP_REQUEST, HttpTransact::EndRemapRequest);
00833 }
00834 
00835 void
00836 HttpTransact::EndRemapRequest(State* s)
00837 {
00838   DebugTxn("http_trans", "START HttpTransact::EndRemapRequest");
00839 
00840   HTTPHdr *incoming_request = &s->hdr_info.client_request;
00841   int method = incoming_request->method_get_wksidx();
00842   int host_len;
00843   const char *host = incoming_request->host_get(&host_len);
00844   DebugTxn("http_trans","EndRemapRequest host is %.*s", host_len,host);
00845   
00846 
00847   
00848 
00849   if (s->remap_redirect != NULL) {
00850     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
00851     if (s->http_return_code == HTTP_STATUS_MOVED_PERMANENTLY) {
00852       build_error_response(s, HTTP_STATUS_MOVED_PERMANENTLY, "Redirect", "redirect#moved_permanently", NULL);
00853     } else {
00854       build_error_response(s, HTTP_STATUS_MOVED_TEMPORARILY, "Redirect", "redirect#moved_temporarily", NULL);
00855     }
00856     ats_free(s->remap_redirect);
00857     s->reverse_proxy = false;
00858     goto done;
00859   }
00860 
00861   
00862 
00863   process_quick_http_filter(s, method);
00864 
00865   
00866 
00867   if (!s->client_connection_enabled) {
00868     build_error_response(s, HTTP_STATUS_FORBIDDEN, "Access Denied", "access#denied", NULL);
00869     s->reverse_proxy = false;
00870     goto done;
00871   }
00872 
00873   
00874 
00875   if (s->http_return_code != HTTP_STATUS_NONE) {
00876     build_error_response(s, s->http_return_code, NULL, NULL,
00877                          s->internal_msg_buffer_size ? s->internal_msg_buffer : NULL);
00878     s->reverse_proxy = false;
00879     goto done;
00880   }
00881 
00882 
00883   
00884   
00885   
00886   
00887 
00888 
00889   if (!s->url_remap_success) {
00890 
00891 
00892 
00893 
00894     if (handleIfRedirect(s)) {
00895       DebugTxn("http_trans", "END HttpTransact::RemapRequest");
00896       TRANSACT_RETURN(SM_ACTION_INTERNAL_CACHE_NOOP, NULL);
00897     }
00898 
00899 
00900     
00901 
00902     if (s->http_config_param->reverse_proxy_enabled
00903         && !s->client_info.is_transparent
00904         && !incoming_request->is_target_in_url()) {
00905 
00906       
00907       
00908       
00909       
00910       
00911       
00912 
00913 
00914       char *redirect_url = s->http_config_param->reverse_proxy_no_host_redirect;
00915       int redirect_url_len = s->http_config_param->reverse_proxy_no_host_redirect_len;
00916 
00917       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
00918       if (redirect_url) {       
00919         build_error_response(s, HTTP_STATUS_MOVED_TEMPORARILY, "Redirect For Explanation", "request#no_host", NULL);
00920         s->hdr_info.client_response.value_set(MIME_FIELD_LOCATION, MIME_LEN_LOCATION, redirect_url, redirect_url_len);
00921       
00922       } else if (host == NULL) {    
00923         build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Host Header Required", "request#no_host", NULL);
00924       } else {
00925         build_error_response(s, HTTP_STATUS_NOT_FOUND, "Not Found on Accelerator", "urlrouting#no_mapping", NULL);
00926       }
00927       s->reverse_proxy = false;
00928       goto done;
00929     } else if (s->http_config_param->url_remap_required && !s->cop_test_page) {
00930 
00931       
00932       
00933       
00934 
00935 
00936       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
00937       build_error_response(s, HTTP_STATUS_NOT_FOUND, "Not Found", "urlrouting#no_mapping", NULL);
00938 
00939       s->reverse_proxy = false;
00940       goto done;
00941     }
00942   } else {
00943     if (s->http_config_param->reverse_proxy_enabled) {
00944       s->req_flavor = REQ_FLAVOR_REVPROXY;
00945     }
00946   }
00947   s->reverse_proxy = true;
00948   s->server_info.is_transparent = s->state_machine->ua_session ? s->state_machine->ua_session->f_outbound_transparent : false;
00949 
00950 done:
00951   if (is_debug_tag_set("http_chdr_describe") || is_debug_tag_set("http_trans") || is_debug_tag_set("url_rewrite")) {
00952     DebugTxn("http_trans", "After Remapping:");
00953     obj_describe(s->hdr_info.client_request.m_http, 1);
00954   }
00955 
00956   
00957 
00958 
00959 
00960 
00961 
00962 
00963 
00964   if (!s->reverse_proxy && s->state_machine->plugin_tunnel_type == HTTP_NO_PLUGIN_TUNNEL) {
00965     
00966     initialize_state_variables_from_request(s, &s->hdr_info.client_request);
00967     DebugTxn("http_trans", "END HttpTransact::EndRemapRequest");
00968     HTTP_INCREMENT_TRANS_STAT(http_invalid_client_requests_stat);
00969     TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
00970   } else {
00971     s->hdr_info.client_response.clear(); 
00972     DebugTxn("http_trans", "END HttpTransact::EndRemapRequest");
00973 
00974     if (s->is_upgrade_request && s->post_remap_upgrade_return_point) {
00975       TRANSACT_RETURN(SM_ACTION_API_POST_REMAP, s->post_remap_upgrade_return_point);
00976     }
00977 
00978     TRANSACT_RETURN(SM_ACTION_API_POST_REMAP, HttpTransact::HandleRequest);
00979   }
00980 
00981   ink_assert(!"not reached");
00982 }
00983 
00984 bool HttpTransact::handle_upgrade_request(State *s) {
00985   
00986   
00987 
00988   if (!s->hdr_info.client_request.presence(MIME_PRESENCE_UPGRADE) ||
00989       !s->hdr_info.client_request.presence(MIME_PRESENCE_CONNECTION) ||
00990       s->method != HTTP_WKSIDX_GET ||
00991       s->hdr_info.client_request.version_get() < HTTPVersion(1, 1)) {
00992     return false;
00993   }
00994 
00995   MIMEField *upgrade_hdr = s->hdr_info.client_request.field_find(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE);
00996   MIMEField *connection_hdr = s->hdr_info.client_request.field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
00997 
00998   StrList connection_hdr_vals;
00999   const char *upgrade_hdr_val = NULL;
01000   int upgrade_hdr_val_len = 0;
01001 
01002   if ( !upgrade_hdr ||
01003        !connection_hdr ||
01004        connection_hdr->value_get_comma_list(&connection_hdr_vals) == 0 ||
01005        (upgrade_hdr_val = upgrade_hdr->value_get(&upgrade_hdr_val_len)) == NULL) {
01006       DebugTxn("http_trans_upgrade", "Transaction wasn't a valid upgrade request, proceeding as a normal HTTP request.");
01007       return false;
01008   }
01009 
01010   
01011 
01012 
01013 
01014 
01015   bool connection_contains_upgrade = false;
01016   
01017   for(int i = 0; i < connection_hdr_vals.count; ++i) {
01018     Str *val = connection_hdr_vals.get_idx(i);
01019     if (ptr_len_casecmp(val->str, val->len, MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE) == 0) {
01020       connection_contains_upgrade = true;
01021       break;
01022     }
01023   }
01024 
01025   if (!connection_contains_upgrade) {
01026     DebugTxn("http_trans_upgrade", "Transaction wasn't a valid upgrade request, proceeding as a normal HTTP request, missing Connection upgrade header.");
01027     return false;
01028   }
01029 
01030 
01031   
01032   s->is_upgrade_request = true;
01033 
01034   
01035 
01036 
01037 
01038 
01039 
01040 
01041 
01042 
01043 
01044 
01045 
01046   if (hdrtoken_tokenize(upgrade_hdr_val, upgrade_hdr_val_len, &s->upgrade_token_wks) >= 0) {
01047     if (s->upgrade_token_wks == MIME_VALUE_WEBSOCKET) {
01048       MIMEField *sec_websocket_key = s->hdr_info.client_request.field_find(MIME_FIELD_SEC_WEBSOCKET_KEY, MIME_LEN_SEC_WEBSOCKET_KEY);
01049       MIMEField *sec_websocket_ver = s->hdr_info.client_request.field_find(MIME_FIELD_SEC_WEBSOCKET_VERSION, MIME_LEN_SEC_WEBSOCKET_VERSION);
01050 
01051       if (sec_websocket_key &&
01052           sec_websocket_ver &&
01053           sec_websocket_ver->value_get_int() == 13) {
01054         DebugTxn("http_trans_upgrade", "Transaction wants upgrade to websockets");
01055         handle_websocket_upgrade_pre_remap(s);
01056         return true;
01057       } else {
01058         DebugTxn("http_trans_upgrade", "Unable to upgrade connection to websockets, invalid headers (RFC 6455).");
01059       }
01060     }
01061   } else {
01062     DebugTxn("http_trans_upgrade", "Transaction requested upgrade for unknown protocol: %s", upgrade_hdr_val);
01063   }
01064 
01065   build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid Upgrade Request", "request#syntax_error", NULL);
01066 
01067   
01068   
01069   TRANSACT_RETURN_VAL(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL, true);
01070 }
01071 
01072 void
01073 HttpTransact::handle_websocket_upgrade_pre_remap(State *s) {
01074   DebugTxn("http_trans_websocket_upgrade_pre_remap", "Prepping transaction before remap.");
01075 
01076   
01077 
01078 
01079 
01080   s->is_websocket = true;
01081   s->post_remap_upgrade_return_point = HttpTransact::handle_websocket_upgrade_post_remap;
01082 
01083   
01084   URL *url = s->hdr_info.client_request.url_get();
01085   if (url->scheme_get_wksidx() == URL_WKSIDX_HTTP) {
01086     DebugTxn("http_trans_websocket_upgrade_pre_remap", "Changing scheme to WS for remapping.");
01087     url->scheme_set(URL_SCHEME_WS, URL_LEN_WS);
01088   } else if (url->scheme_get_wksidx() == URL_WKSIDX_HTTPS) {
01089     DebugTxn("http_trans_websocket_upgrade_pre_remap", "Changing scheme to WSS for remapping.");
01090     url->scheme_set(URL_SCHEME_WSS, URL_LEN_WSS);
01091   } else {
01092     DebugTxn("http_trans_websocket_upgrade_pre_remap", "Invalid scheme for websocket upgrade");
01093     build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid Upgrade Request", "request#syntax_error", NULL);
01094     TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01095   }
01096 
01097   TRANSACT_RETURN(SM_ACTION_API_READ_REQUEST_HDR, HttpTransact::StartRemapRequest);
01098 }
01099 
01100 void
01101 HttpTransact::handle_websocket_upgrade_post_remap(State *s) {
01102   DebugTxn("http_trans_websocket_upgrade_post_remap", "Remap is complete, start websocket upgrade");
01103 
01104   TRANSACT_RETURN(SM_ACTION_API_POST_REMAP, HttpTransact::handle_websocket_connection);
01105 }
01106 
01107 void
01108 HttpTransact::handle_websocket_connection(State *s) {
01109   DebugTxn("http_trans_websocket", "START handle_websocket_connection");
01110 
01111   HandleRequest(s);
01112 }
01113 
01114 
01115 static bool mimefield_value_equal(MIMEField *field, const char *value, const int value_len)
01116 {
01117   if (field != NULL) {
01118     int field_value_len = 0;
01119     const char *field_value = field->value_get(&field_value_len);
01120     if (field_value != NULL) {
01121       if (field_value_len == value_len) {
01122         return !strncasecmp(field_value, value, value_len);
01123       }
01124     }
01125   }
01126   return false;
01127 }
01128 
01129 void
01130 HttpTransact::ModifyRequest(State* s)
01131 {
01132   int scheme, hostname_len;
01133   const char *hostname;
01134   HTTPHdr& request = s->hdr_info.client_request;
01135 
01136   DebugTxn("http_trans", "START HttpTransact::ModifyRequest");
01137 
01138   
01139   bootstrap_state_variables_from_request(s, &request);
01140 
01141 
01142   
01143 
01144   URL *url = request.url_get();
01145 
01146   s->orig_scheme = (scheme = url->scheme_get_wksidx());
01147 
01148   s->method = request.method_get_wksidx();
01149   if (scheme < 0 && s->method != HTTP_WKSIDX_CONNECT) {
01150     if (s->client_info.port_attribute == HttpProxyPort::TRANSPORT_SSL) {
01151       url->scheme_set(URL_SCHEME_HTTPS, URL_LEN_HTTPS);
01152       s->orig_scheme = URL_WKSIDX_HTTPS;
01153     } else {
01154       url->scheme_set(URL_SCHEME_HTTP, URL_LEN_HTTP);
01155       s->orig_scheme = URL_WKSIDX_HTTP;
01156     }
01157   }
01158 
01159   if (s->method == HTTP_WKSIDX_CONNECT && !request.is_port_in_header())
01160     url->port_set(80);
01161 
01162   
01163   
01164   
01165   
01166   
01167   hostname = request.host_get(&hostname_len);
01168   if (!request.is_target_in_url()) {
01169     s->hdr_info.client_req_is_server_style = true;
01170   }
01171 
01172   
01173   
01174   
01175   int max_forwards = -1;  
01176   if (request.presence(MIME_PRESENCE_MAX_FORWARDS)) {
01177     max_forwards = request.get_max_forwards();
01178   }
01179 
01180   if ((max_forwards != 0) && !s->hdr_info.client_req_is_server_style && s->method != HTTP_WKSIDX_CONNECT) {
01181     MIMEField *host_field = request.field_find(MIME_FIELD_HOST, MIME_LEN_HOST);
01182     int host_val_len = hostname_len;
01183     const char **host_val = &hostname;
01184     int port = url->port_get_raw();
01185     char *buf = NULL;
01186 
01187     
01188     if (port > 0) {
01189       buf = (char *)alloca(host_val_len + 15);
01190       memcpy(buf, hostname, host_val_len);
01191       host_val_len += snprintf(buf + host_val_len, 15, ":%d", port);
01192       host_val = (const char**)(&buf);
01193     }
01194 
01195     if (mimefield_value_equal(host_field, *host_val, host_val_len) == false) {
01196       if (!host_field) { 
01197         host_field = request.field_create(MIME_FIELD_HOST, MIME_LEN_HOST);
01198         request.field_attach(host_field);
01199       }
01200       request.field_value_set(host_field, *host_val, host_val_len);
01201       request.mark_target_dirty();
01202     }
01203   }
01204 
01205   if (s->txn_conf->normalize_ae_gzip) {
01206     
01207     MIMEField *ae_field = s->hdr_info.client_request.field_find(MIME_FIELD_ACCEPT_ENCODING, MIME_LEN_ACCEPT_ENCODING);
01208 
01209     if (ae_field) {
01210       if (HttpTransactCache::match_gzip(ae_field) == GZIP) {
01211         s->hdr_info.client_request.field_value_set(ae_field, "gzip", 4);
01212         DebugTxn("http_trans", "[ModifyRequest] normalized Accept-Encoding to gzip");
01213       } else {
01214         s->hdr_info.client_request.field_delete(ae_field);
01215         DebugTxn("http_trans", "[ModifyRequest] removed non-gzip Accept-Encoding");
01216       }
01217     }
01218   }
01219 
01220 
01221   
01222 
01223   if (s->txn_conf->accept_encoding_filter_enabled) {
01224     perform_accept_encoding_filtering(s);
01225   }
01226 
01227   DebugTxn("http_trans", "END HttpTransact::ModifyRequest");
01228 
01229   DebugTxn("http_trans", "Checking if transaction wants to upgrade");
01230   if(handle_upgrade_request(s)) {
01231     
01232     DebugTxn("http_trans", "Transaction will be upgraded by the appropriate upgrade handler.");
01233     return;
01234   }
01235 
01236   TRANSACT_RETURN(SM_ACTION_API_READ_REQUEST_HDR, HttpTransact::StartRemapRequest);
01237 }
01238 
01239 
01240 
01241 bool
01242 HttpTransact::handleIfRedirect(State *s)
01243 {
01244   int answer;
01245   URL redirect_url;
01246 
01247   answer = request_url_remap_redirect(&s->hdr_info.client_request, &redirect_url);
01248   if ((answer == PERMANENT_REDIRECT) || (answer == TEMPORARY_REDIRECT)) {
01249     int remap_redirect_len;
01250 
01251     s->remap_redirect = redirect_url.string_get(&s->arena, &remap_redirect_len);
01252     redirect_url.destroy();
01253     if (answer == TEMPORARY_REDIRECT) {
01254       if ((s->client_info).http_version.m_version == HTTP_VERSION(1, 1)) {
01255         build_error_response(s, HTTP_STATUS_TEMPORARY_REDIRECT, "Redirect", "redirect#moved_temporarily", NULL);
01256       } else {
01257         build_error_response(s, HTTP_STATUS_MOVED_TEMPORARILY, "Redirect", "redirect#moved_temporarily", NULL);
01258       }
01259     } else {
01260       build_error_response(s, HTTP_STATUS_MOVED_PERMANENTLY, "Redirect", "redirect#moved_permanently", NULL);
01261     }
01262     s->arena.str_free(s->remap_redirect);
01263     s->remap_redirect = NULL;
01264     return true;
01265   }
01266 
01267   return false;
01268 }
01269 
01270 void
01271 HttpTransact::HandleRequest(State* s)
01272 {
01273   DebugTxn("http_trans", "START HttpTransact::HandleRequest");
01274 
01275   ink_assert(!s->hdr_info.server_request.valid());
01276 
01277   HTTP_INCREMENT_TRANS_STAT(http_incoming_requests_stat);
01278 
01279   if (s->client_info.port_attribute == HttpProxyPort::TRANSPORT_SSL) {
01280     HTTP_INCREMENT_TRANS_STAT(https_incoming_requests_stat);
01281   }
01282 
01283   if (s->api_release_server_session == true) {
01284     s->api_release_server_session = false;
01285   }
01286 
01287   
01288 
01289 
01290   if (!(is_request_valid(s, &s->hdr_info.client_request))) {
01291     HTTP_INCREMENT_TRANS_STAT(http_invalid_client_requests_stat);
01292     DebugTxn("http_seq", "[HttpTransact::HandleRequest] request invalid.");
01293     s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
01294     
01295     return;
01296   }
01297   DebugTxn("http_seq", "[HttpTransact::HandleRequest] request valid.");
01298 
01299   if (is_debug_tag_set("http_chdr_describe")) {
01300     obj_describe(s->hdr_info.client_request.m_http, 1);
01301   }
01302 
01303   
01304   
01305   
01306   initialize_state_variables_from_request(s, &s->hdr_info.client_request);
01307 
01308   
01309   
01310   
01311   s->cache_info.action = CACHE_DO_NO_ACTION;
01312   s->current.mode = GENERIC_PROXY;
01313 
01314   
01315   update_cache_control_information_from_config(s);
01316 
01317   
01318   
01319   if (is_request_cache_lookupable(s))
01320     s->cache_info.action = CACHE_DO_LOOKUP;
01321 
01322   
01323   
01324   if (handle_internal_request(s, &s->hdr_info.client_request)) {
01325     TRANSACT_RETURN(SM_ACTION_INTERNAL_REQUEST, NULL);
01326   }
01327 
01328   
01329   
01330 
01331   if (!s->cop_test_page)
01332     DUMP_HEADER("http_hdrs", &s->hdr_info.client_request, s->state_machine_id, "Incoming Request");
01333 
01334   if (s->state_machine->plugin_tunnel_type == HTTP_PLUGIN_AS_INTERCEPT) {
01335     setup_plugin_request_intercept(s);
01336     return;
01337   }
01338 
01339   
01340   if (s->srv_lookup) {
01341     if (s->cop_test_page)
01342       s->srv_lookup = false;
01343     else {
01344       IpEndpoint addr;
01345       ats_ip_pton(s->server_info.name, &addr);
01346       s->srv_lookup = !ats_is_ip(&addr);
01347     }
01348   }
01349 
01350   
01351   
01352   
01353   
01354   
01355   if (handle_trace_and_options_requests(s, &s->hdr_info.client_request)) {
01356     TRANSACT_RETURN(SM_ACTION_INTERNAL_CACHE_NOOP, NULL);
01357   }
01358 
01359   if (s->http_config_param->no_dns_forward_to_parent
01360     && s->scheme != URL_WKSIDX_HTTPS
01361     && strcmp(s->server_info.name, "127.0.0.1") != 0
01362   ) {
01363     
01364     
01365     
01366     
01367     
01368     IpEndpoint addr;
01369     ats_ip_pton(s->server_info.name, &addr);
01370     if (ats_is_ip(&addr)) {
01371       ats_ip_copy(&s->request_data.dest_ip, &addr);
01372     }
01373 
01374     if (s->parent_params->parentExists(&s->request_data)) {
01375       
01376       
01377       
01378       
01379       ats_ip_invalidate(&s->server_info.addr);
01380       StartAccessControl(s);
01381       return;
01382     } else if (s->http_config_param->no_origin_server_dns) {
01383       build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Next Hop Connection Failed", "connect#failed_connect", NULL);
01384 
01385       TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01386     }
01387   }
01388 
01389   
01390   
01391   
01392   if (s->dns_info.lookup_name[0] <= '9' &&
01393       s->dns_info.lookup_name[0] >= '0' &&
01394       (!s->state_machine->enable_redirection || !s->redirect_info.redirect_in_process) &&
01395       s->parent_params->ParentTable->hostMatch) {
01396     s->force_dns = 1;
01397   }
01398   
01399   
01400   
01401   if (s->txn_conf->cache_http && s->redirect_info.redirect_in_process && s->state_machine->enable_redirection) {
01402     TRANSACT_RETURN(SM_ACTION_CACHE_LOOKUP, NULL);
01403   }
01404 
01405 
01406   if (s->force_dns) {
01407     TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);   
01408   } else {
01409     
01410     
01411     StartAccessControl(s);
01412   }
01413 }
01414 
01415 void
01416 HttpTransact::setup_plugin_request_intercept(State* s)
01417 {
01418   ink_assert(s->state_machine->plugin_tunnel != NULL);
01419 
01420   
01421   
01422   
01423   
01424   if (s->cache_info.action != HttpTransact::CACHE_DO_NO_ACTION) {
01425     s->cache_info.action = HttpTransact::CACHE_DO_NO_ACTION;
01426     s->current.mode = TUNNELLING_PROXY;
01427     HTTP_INCREMENT_TRANS_STAT(http_tunnels_stat);
01428   }
01429   
01430   
01431   s->scheme = s->next_hop_scheme = URL_WKSIDX_HTTP;
01432 
01433   
01434   update_current_info(&s->current, &s->server_info, HttpTransact::ORIGIN_SERVER, 0);
01435 
01436   
01437   
01438   s->server_info.http_version.set(1, 0);
01439   s->server_info.keep_alive = HTTP_NO_KEEPALIVE;
01440   s->host_db_info.app.http_data.http_version = HostDBApplicationInfo::HTTP_VERSION_10;
01441   s->host_db_info.app.http_data.pipeline_max = 1;
01442 
01443   
01444   build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->client_info.http_version);
01445 
01446   
01447   
01448   s->hdr_info.server_request.field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
01449 
01450   TRANSACT_RETURN(SM_ACTION_ORIGIN_SERVER_OPEN, NULL);
01451 }
01452 
01453 
01454 
01455 
01456 
01457 
01458 
01459 void
01460 HttpTransact::HandleApiErrorJump(State* s)
01461 {
01462   DebugTxn("http_trans", "[HttpTransact::HandleApiErrorJump]");
01463 
01464   
01465   
01466   
01467   
01468   
01469   if (s->next_hop_scheme < 0) {
01470     s->next_hop_scheme = URL_WKSIDX_HTTP;
01471   }
01472   
01473   
01474   
01475   
01476   
01477   if (s->hdr_info.client_response.valid()) {
01478     s->hdr_info.client_response.fields_clear();
01479     s->source = SOURCE_INTERNAL;
01480   }
01481   
01482 
01483 
01484 
01485 
01486   if ( s->http_return_code && s->http_return_code >= HTTP_STATUS_BAD_REQUEST ) {
01487     const char *reason = http_hdr_reason_lookup(s->http_return_code);;
01488     build_response(s, &s->hdr_info.client_response, s->client_info.http_version, s->http_return_code,
01489                    reason?reason:"Error" );
01490   }
01491   else {
01492     build_response(s, &s->hdr_info.client_response, s->client_info.http_version,
01493                    HTTP_STATUS_INTERNAL_SERVER_ERROR, "INKApi Error");
01494   }  
01495 
01496   TRANSACT_RETURN(SM_ACTION_INTERNAL_CACHE_NOOP, NULL);
01497   return;
01498 }
01499 
01500 
01501 
01502 
01503 
01504 
01505 
01506 
01507 
01508 
01509 
01510 
01511 
01512 
01513 
01514 
01515 
01516 
01517 
01518 
01519 
01520 void
01521 HttpTransact::PPDNSLookup(State* s)
01522 {
01523   ++s->dns_info.attempts;
01524 
01525   DebugTxn("http_trans", "[HttpTransact::PPDNSLookup] This was attempt %d", s->dns_info.attempts);
01526 
01527   ink_assert(s->dns_info.looking_up == PARENT_PROXY);
01528   if (!s->dns_info.lookup_success) {
01529     
01530     find_server_and_update_current_info(s);
01531     if (!ats_is_ip(&s->current.server->addr)) {
01532       if (s->current.request_to == PARENT_PROXY) {
01533         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
01534       } else {
01535         
01536         
01537         ink_assert(s->current.request_to == HOST_NONE);
01538         handle_parent_died(s);
01539       }
01540       return;
01541     }
01542   } else {
01543     
01544     ats_ip_copy(&s->parent_info.addr, s->host_db_info.ip());
01545     get_ka_info_from_host_db(s, &s->parent_info, &s->client_info, &s->host_db_info);
01546     s->parent_info.dns_round_robin = s->host_db_info.round_robin;
01547 
01548     char addrbuf[INET6_ADDRSTRLEN];
01549     DebugTxn("http_trans", "[PPDNSLookup] DNS lookup for sm_id[%" PRId64"] successful IP: %s",
01550           s->state_machine->sm_id, ats_ip_ntop(&s->parent_info.addr.sa, addrbuf, sizeof(addrbuf)));
01551   }
01552 
01553   
01554   
01555   if (!s->hdr_info.server_request.valid()) {
01556     build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->current.server->http_version);
01557 
01558     
01559     
01560     if (s->pending_work != NULL) {
01561       ink_assert(s->pending_work == issue_revalidate);
01562       (*s->pending_work) (s);
01563       s->pending_work = NULL;
01564     }
01565   }
01566   
01567   s->next_action = how_to_open_connection(s);
01568 }
01569 
01570 
01571 
01572 
01573 
01574 
01575 
01576 
01577 
01578 
01579 
01580 
01581 
01582 
01583 
01584 
01585 
01586 void
01587 HttpTransact::ReDNSRoundRobin(State* s)
01588 {
01589   ink_assert(s->current.server == &s->server_info);
01590   ink_assert(s->current.server->had_connect_fail());
01591 
01592   if (s->dns_info.lookup_success) {
01593     
01594     
01595     s->current.server->clear_connect_fail();
01596 
01597     
01598     
01599     ats_ip_copy(&s->server_info.addr, s->host_db_info.ip());
01600     ats_ip_copy(&s->request_data.dest_ip, &s->server_info.addr);
01601     get_ka_info_from_host_db(s, &s->server_info, &s->client_info, &s->host_db_info);
01602     s->server_info.dns_round_robin = s->host_db_info.round_robin;
01603 
01604     char addrbuf[INET6_ADDRSTRLEN];
01605     DebugTxn("http_trans", "[ReDNSRoundRobin] DNS lookup for O.S. successful IP: %s",
01606           ats_ip_ntop(&s->server_info.addr.sa, addrbuf, sizeof(addrbuf)));
01607 
01608     s->next_action = how_to_open_connection(s);
01609   } else {
01610     
01611     build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Cannot find server.", "connect#dns_failed", NULL);
01612     s->cache_info.action = CACHE_DO_NO_ACTION;
01613     s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
01614     
01615   }
01616 
01617   return;
01618 }
01619 
01620 
01621 
01622 
01623 
01624 
01625 
01626 
01627 
01628 
01629 
01630 
01631 
01632 
01633 
01634 
01635 
01636 
01637 
01638 
01639 
01640 
01641 
01642 
01643 
01644 
01645 
01646 
01647 
01648 void
01649 HttpTransact::OSDNSLookup(State* s)
01650 {
01651   static int max_dns_lookups = 3 + s->http_config_param->num_url_expansions;
01652   ++s->dns_info.attempts;
01653 
01654   DebugTxn("http_trans", "[HttpTransact::OSDNSLookup] This was attempt %d", s->dns_info.attempts);
01655 
01656   ink_assert(s->dns_info.looking_up == ORIGIN_SERVER);
01657 
01658   
01659   
01660 
01661   
01662   if (!s->request_will_not_selfloop) {
01663     if (will_this_request_self_loop(s)) {
01664       DebugTxn("http_trans", "[OSDNSLookup] request will selfloop - bailing out");
01665       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
01666       TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01667     }
01668   }
01669 
01670   if (!s->dns_info.lookup_success) {
01671     
01672     HostNameExpansionError_t host_name_expansion = try_to_expand_host_name(s);
01673 
01674     switch (host_name_expansion) {
01675     case RETRY_EXPANDED_NAME:
01676       
01677       HTTP_RELEASE_ASSERT(s->dns_info.attempts < max_dns_lookups);
01678       HTTP_RELEASE_ASSERT(s->http_config_param->enable_url_expandomatic);
01679       TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
01680       break;
01681     case EXPANSION_NOT_ALLOWED:
01682     case EXPANSION_FAILED:
01683     case DNS_ATTEMPTS_EXHAUSTED:
01684       if (DNSLookupInfo::OS_ADDR_TRY_HOSTDB == s->dns_info.os_addr_style) {
01685         
01686         s->dns_info.lookup_success = true;
01687         s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
01688         DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS lookup unsuccessful reverting to force client target address use");
01689       } else {
01690         if (host_name_expansion == EXPANSION_NOT_ALLOWED) {
01691           
01692           HTTP_RELEASE_ASSERT(!(s->http_config_param->enable_url_expandomatic));
01693           DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
01694         } else if (host_name_expansion == EXPANSION_FAILED) {
01695           
01696           DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
01697         } else if (host_name_expansion == DNS_ATTEMPTS_EXHAUSTED) {
01698           
01699           HTTP_RELEASE_ASSERT(s->dns_info.attempts >= max_dns_lookups);
01700           DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
01701         }
01702         
01703         SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
01704         build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Cannot find server.", "connect#dns_failed", NULL);
01705         
01706         TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01707       }
01708       break;
01709     default:
01710       ink_assert(!("try_to_expand_hostname returned an unsupported code"));
01711       break;
01712     }
01713     return;
01714   }
01715   
01716   ink_assert(s->dns_info.lookup_success);
01717   DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup successful");
01718 
01719   if (DNSLookupInfo::OS_ADDR_TRY_HOSTDB == s->dns_info.os_addr_style) {
01720     
01721     
01722     
01723     if (s->host_db_info.round_robin) {
01724       HostDBInfo* cta = s->host_db_info.rr()->select_next(&s->current.server->addr.sa);
01725       if (cta) {
01726         
01727         s->host_db_info = *cta;
01728         s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_HOSTDB;
01729       } else {
01730         
01731         s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
01732       }
01733     } else if (ats_ip_addr_eq(s->host_db_info.ip(), &s->server_info.addr.sa)) {
01734       s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
01735     } else {
01736       s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_HOSTDB;
01737     }
01738   }
01739 
01740   
01741   
01742   
01743   ats_ip_copy(&s->server_info.addr, s->host_db_info.ip());
01744   ats_ip_copy(&s->request_data.dest_ip, &s->server_info.addr);
01745   get_ka_info_from_host_db(s, &s->server_info, &s->client_info, &s->host_db_info);
01746   s->server_info.dns_round_robin = s->host_db_info.round_robin;
01747 
01748   char addrbuf[INET6_ADDRSTRLEN];
01749   DebugTxn("http_trans", "[OSDNSLookup] DNS lookup for O.S. successful "
01750         "IP: %s", ats_ip_ntop(&s->server_info.addr.sa, addrbuf, sizeof(addrbuf)));
01751 
01752   
01753   
01754   
01755   
01756   
01757 
01758   
01759   
01760   
01761   
01762   
01763   if (s->dns_info.attempts == max_dns_lookups && s->dns_info.looking_up == ORIGIN_SERVER && DNSLookupInfo::OS_ADDR_USE_CLIENT != s->dns_info.os_addr_style) {
01764     DebugTxn("http_trans", "[OSDNSLookup] DNS name resolution on expansion");
01765     DebugTxn("http_seq", "[OSDNSLookup] DNS name resolution on expansion - returning");
01766     build_redirect_response(s);
01767     
01768     TRANSACT_RETURN(SM_ACTION_INTERNAL_CACHE_NOOP, NULL);
01769   }
01770   
01771   
01772   
01773 
01774 
01775   
01776   
01777 
01778   if (s->cdn_remap_complete) {
01779     DebugTxn("cdn", "This is a late DNS lookup.  We are going to the OS, " "not to HandleFiltering.");
01780     ink_assert(s->cdn_saved_next_action == SM_ACTION_ORIGIN_SERVER_OPEN || s->cdn_saved_next_action == SM_ACTION_ORIGIN_SERVER_RAW_OPEN);
01781     DebugTxn("cdn", "outgoing version -- (pre  conversion) %d", s->hdr_info.server_request.m_http->m_version);
01782     (&s->hdr_info.server_request)->version_set(HTTPVersion(1, 1));
01783     HttpTransactHeaders::convert_request(s->current.server->http_version, &s->hdr_info.server_request);
01784     DebugTxn("cdn", "outgoing version -- (post conversion) %d", s->hdr_info.server_request.m_http->m_version);
01785     TRANSACT_RETURN(s->cdn_saved_next_action, NULL);
01786   } else if (DNSLookupInfo::OS_ADDR_USE_CLIENT == s->dns_info.os_addr_style ||
01787              DNSLookupInfo::OS_ADDR_USE_HOSTDB == s->dns_info.os_addr_style) {
01788     
01789     
01790     TRANSACT_RETURN(how_to_open_connection(s), HttpTransact::HandleResponse);
01791   } else if (s->dns_info.lookup_name[0] <= '9' &&
01792              s->dns_info.lookup_name[0] >= '0' &&
01793              s->parent_params->ParentTable->hostMatch &&
01794              !s->http_config_param->no_dns_forward_to_parent) {
01795     
01796     
01797     TRANSACT_RETURN(SM_ACTION_DNS_REVERSE_LOOKUP, HttpTransact::StartAccessControl);
01798   } else {
01799     
01800     
01801 
01802     if (s->force_dns) {
01803       StartAccessControl(s);    
01804       
01805     } else {
01806       if ((s->cache_info.action == CACHE_DO_NO_ACTION) &&
01807           (((s->hdr_info.client_request.presence(MIME_PRESENCE_RANGE) && !s->txn_conf->cache_range_write) ||
01808             s->range_setup == RANGE_NOT_SATISFIABLE || s->range_setup == RANGE_NOT_HANDLED))) {
01809         TRANSACT_RETURN(SM_ACTION_API_OS_DNS, HandleCacheOpenReadMiss);
01810       } else if (s->cache_lookup_result == HttpTransact::CACHE_LOOKUP_SKIPPED) {
01811         TRANSACT_RETURN(SM_ACTION_API_OS_DNS, LookupSkipOpenServer);
01812         
01813         
01814       } else if (s->cache_lookup_result == CACHE_LOOKUP_HIT_FRESH ||
01815                  s->cache_lookup_result == CACHE_LOOKUP_HIT_WARNING ||
01816                  s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE) {
01817         
01818         TRANSACT_RETURN(SM_ACTION_API_OS_DNS, HandleCacheOpenReadHit);
01819       } else if (s->cache_lookup_result == CACHE_LOOKUP_MISS || s->cache_info.action == CACHE_DO_NO_ACTION) {
01820         TRANSACT_RETURN(SM_ACTION_API_OS_DNS, HandleCacheOpenReadMiss);
01821         
01822       } else {
01823         build_error_response(s, HTTP_STATUS_INTERNAL_SERVER_ERROR, "Invalid Cache Lookup result", "default", NULL);
01824         Log::error("HTTP: Invalid CACHE LOOKUP RESULT : %d", s->cache_lookup_result);
01825         TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01826       }
01827     }
01828   }
01829 }
01830 
01831 void
01832 HttpTransact::StartAccessControl(State* s)
01833 {
01834   
01835     
01836     
01837     HandleRequestAuthorized(s);
01838   
01839  
01840   
01841   
01842   
01843   
01844     
01845    
01846   
01847   
01848   
01849 }
01850 
01851 void
01852 HttpTransact::HandleRequestAuthorized(State* s)
01853 {
01854   
01855   
01856   
01857    if (s->force_dns) {
01858     TRANSACT_RETURN(SM_ACTION_API_OS_DNS, HttpTransact::DecideCacheLookup);
01859   } else {
01860     HttpTransact::DecideCacheLookup(s);
01861   }
01862 }
01863 
01864 void
01865 HttpTransact::HandleFiltering(State* s)
01866 {
01867   ink_release_assert(!"Fix-Me AUTH MERGE");
01868 
01869   if (s->method == HTTP_WKSIDX_PUSH && s->http_config_param->push_method_enabled == 0) {
01870     
01871     
01872     DebugTxn("http_trans", "[HandleFiltering] access denied.");
01873     DebugTxn("http_seq", "[HttpTransact::HandleFiltering] Access Denied.");
01874 
01875     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
01876     
01877     build_error_response(s, HTTP_STATUS_FORBIDDEN, "Access Denied", "access#denied", NULL);
01878     
01879     TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
01880   }
01881 
01882   DebugTxn("http_seq", "[HttpTransact::HandleFiltering] Request Authorized.");
01883 
01884   
01885 
01886 
01887   
01888   
01889   DecideCacheLookup(s);
01890 }
01891 
01892 void
01893 HttpTransact::DecideCacheLookup(State* s)
01894 {
01895   
01896   if (s->redirect_info.redirect_in_process || s->cop_test_page) {
01897     
01898     
01899     s->cache_info.action = CACHE_DO_NO_ACTION;
01900     s->current.mode = GENERIC_PROXY;
01901   } else {
01902     if (is_request_cache_lookupable(s)) {
01903       s->cache_info.action = CACHE_DO_LOOKUP;
01904       s->current.mode = GENERIC_PROXY;
01905     } else {
01906       s->cache_info.action = CACHE_DO_NO_ACTION;
01907       s->current.mode = TUNNELLING_PROXY;
01908       HTTP_INCREMENT_TRANS_STAT(http_tunnels_stat);
01909     }
01910   }
01911 
01912   if (service_transaction_in_proxy_only_mode(s)) {
01913     s->cache_info.action = CACHE_DO_NO_ACTION;
01914     s->current.mode = TUNNELLING_PROXY;
01915     HTTP_INCREMENT_TRANS_STAT(http_throttled_proxy_only_stat);
01916   }
01917   
01918   
01919 
01920   
01921   if (s->cache_info.action == CACHE_DO_LOOKUP) {
01922     DebugTxn("http_trans", "[DecideCacheLookup] Will do cache lookup.");
01923     DebugTxn("http_seq", "[DecideCacheLookup] Will do cache lookup");
01924     ink_assert(s->current.mode != TUNNELLING_PROXY);
01925 
01926     if (s->cache_info.lookup_url == NULL) {
01927       HTTPHdr* incoming_request = &s->hdr_info.client_request;
01928 
01929       if (s->txn_conf->maintain_pristine_host_hdr) {
01930         s->cache_info.lookup_url_storage.create(NULL);
01931         s->cache_info.lookup_url_storage.copy(incoming_request->url_get());
01932         s->cache_info.lookup_url = &s->cache_info.lookup_url_storage;
01933         
01934         
01935         incoming_request->set_url_target_from_host_field(s->cache_info.lookup_url);
01936       } else {
01937         
01938         incoming_request->set_url_target_from_host_field();
01939         s->cache_info.lookup_url = incoming_request->url_get();
01940       }
01941 
01942       
01943       
01944       
01945       
01946       
01947       if (s->txn_conf->maintain_pristine_host_hdr) {
01948         char const* host_hdr;
01949         char const* port_hdr;
01950         int host_len, port_len;
01951         
01952         if (incoming_request->get_host_port_values(&host_hdr, &host_len, &port_hdr, &port_len)) {
01953           int port = 0;
01954           if (port_hdr) {
01955             s->cache_info.lookup_url->host_set(host_hdr, host_len);
01956             port = ink_atoi(port_hdr, port_len);
01957           } else {
01958             s->cache_info.lookup_url->host_set(host_hdr, host_len);
01959           }
01960           s->cache_info.lookup_url->port_set(port);
01961         }
01962       }
01963       ink_assert(s->cache_info.lookup_url->valid() == true);
01964     }
01965 
01966     TRANSACT_RETURN(SM_ACTION_CACHE_LOOKUP, NULL);
01967   } else {
01968     ink_assert(s->cache_info.action != CACHE_DO_LOOKUP && s->cache_info.action != CACHE_DO_SERVE);
01969 
01970     DebugTxn("http_trans", "[DecideCacheLookup] Will NOT do cache lookup.");
01971     DebugTxn("http_seq", "[DecideCacheLookup] Will NOT do cache lookup");
01972     
01973     
01974     if (s->method == HTTP_WKSIDX_PUSH) {
01975       HandlePushError(s, "Request Not Cachable");
01976       return;
01977     }
01978     
01979     if (s->redirect_info.redirect_in_process) {
01980       
01981       s->cache_info.action = CACHE_DO_WRITE;
01982       LookupSkipOpenServer(s);
01983     } else {
01984       
01985       
01986       s->cache_lookup_result = HttpTransact::CACHE_LOOKUP_SKIPPED;
01987       if (s->force_dns) {
01988         TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, LookupSkipOpenServer);
01989       } else {
01990         
01991         TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, CallOSDNSLookup);
01992       }
01993     }
01994   }
01995 
01996   return;
01997 }
01998 
01999 void
02000 HttpTransact::LookupSkipOpenServer(State* s)
02001 {
02002   
02003   
02004   find_server_and_update_current_info(s);
02005 
02006   if (s->current.request_to == PARENT_PROXY) {
02007     TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
02008   }
02009 
02010   ink_assert(s->current.request_to == ORIGIN_SERVER);
02011   
02012 
02013   build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->current.server->http_version);
02014 
02015   StateMachineAction_t next = how_to_open_connection(s);
02016   s->next_action = next;
02017   if (next == SM_ACTION_ORIGIN_SERVER_OPEN || next == SM_ACTION_ORIGIN_SERVER_RAW_OPEN) {
02018     TRANSACT_RETURN(next, HttpTransact::HandleResponse);
02019   }
02020 }
02021 
02022 
02023 
02024 
02025 
02026 
02027 
02028 
02029 
02030 
02031 void
02032 HttpTransact::HandleCacheOpenReadPush(State* s, bool read_successful)
02033 {
02034   if (read_successful) {
02035     s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
02036   } else {
02037     s->cache_info.action = CACHE_PREPARE_TO_WRITE;
02038   }
02039 
02040   TRANSACT_RETURN(SM_ACTION_READ_PUSH_HDR, HandlePushResponseHdr);
02041 }
02042 
02043 
02044 
02045 
02046 
02047 
02048 
02049 
02050 
02051 void
02052 HttpTransact::HandlePushResponseHdr(State* s)
02053 {
02054   
02055   int64_t body_bytes = s->hdr_info.request_content_length - s->state_machine->pushed_response_hdr_bytes;
02056   if (body_bytes < 0) {
02057     HandlePushError(s, "Bad Content Length");
02058     return;
02059   }
02060   
02061   s->hdr_info.server_request.create(HTTP_TYPE_REQUEST);
02062   s->hdr_info.server_request.copy(&s->hdr_info.client_request);
02063   s->hdr_info.server_request.method_set(HTTP_METHOD_GET, HTTP_LEN_GET);
02064   s->hdr_info.server_request.value_set("X-Inktomi-Source", 16, "http PUSH", 9);
02065 
02066   if (!s->cop_test_page)
02067     DUMP_HEADER("http_hdrs", &s->hdr_info.server_response, s->state_machine_id, "Pushed Response Header");
02068 
02069   if (!s->cop_test_page)
02070     DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Generated Request Header");
02071 
02072   s->response_received_time = s->request_sent_time = ink_cluster_time();
02073 
02074   if (is_response_cacheable(s, &s->hdr_info.server_request, &s->hdr_info.server_response)) {
02075     ink_assert(s->cache_info.action == CACHE_PREPARE_TO_WRITE || s->cache_info.action == CACHE_PREPARE_TO_UPDATE);
02076 
02077     TRANSACT_RETURN(SM_ACTION_CACHE_ISSUE_WRITE, HandlePushCacheWrite);
02078   } else {
02079     HandlePushError(s, "Response Not Cachable");
02080   }
02081 }
02082 
02083 
02084 
02085 
02086 
02087 
02088 
02089 
02090 
02091 void
02092 HttpTransact::HandlePushCacheWrite(State* s)
02093 {
02094   switch (s->cache_info.write_lock_state) {
02095   case CACHE_WL_SUCCESS:
02096     
02097     if (s->cache_info.action == CACHE_PREPARE_TO_WRITE) {
02098       s->cache_info.action = CACHE_DO_WRITE;
02099     } else if (s->cache_info.action == CACHE_PREPARE_TO_UPDATE) {
02100       s->cache_info.action = CACHE_DO_REPLACE;
02101     } else {
02102       ink_release_assert(0);
02103     }
02104     set_headers_for_cache_write(s, &s->cache_info.object_store, &s->hdr_info.server_request, &s->hdr_info.server_response);
02105 
02106     TRANSACT_RETURN(SM_ACTION_STORE_PUSH_BODY, NULL);
02107     break;
02108 
02109   case CACHE_WL_FAIL:
02110   case CACHE_WL_READ_RETRY:
02111     
02112     HandlePushError(s, "Cache Write Failed");
02113     break;
02114   case CACHE_WL_INIT:
02115   default:
02116     ink_release_assert(0);
02117   }
02118 }
02119 
02120 
02121 void
02122 HttpTransact::HandlePushTunnelSuccess(State* s)
02123 {
02124   ink_assert(s->cache_info.action == CACHE_DO_WRITE || s->cache_info.action == CACHE_DO_REPLACE);
02125 
02126   
02127   HTTPStatus resp_status = (s->cache_info.action == CACHE_DO_WRITE) ? HTTP_STATUS_CREATED : HTTP_STATUS_OK;
02128 
02129   build_response(s, &s->hdr_info.client_response, s->client_info.http_version, resp_status);
02130 
02131   TRANSACT_RETURN(SM_ACTION_INTERNAL_CACHE_NOOP, NULL);
02132 }
02133 
02134 
02135 void
02136 HttpTransact::HandlePushTunnelFailure(State* s)
02137 {
02138   HandlePushError(s, "Cache Error");
02139 }
02140 
02141 void
02142 HttpTransact::HandleBadPushRespHdr(State* s)
02143 {
02144   HandlePushError(s, "Malformed Pushed Response Header");
02145 }
02146 
02147 void
02148 HttpTransact::HandlePushError(State *s, const char *reason)
02149 {
02150   s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
02151 
02152   
02153   
02154   s->state_machine->set_ua_half_close_flag();
02155 
02156   build_error_response(s, HTTP_STATUS_BAD_REQUEST, reason, "default", NULL);
02157 }
02158 
02159 
02160 
02161 
02162 
02163 
02164 
02165 
02166 
02167 
02168 
02169 
02170 
02171 
02172 
02173 
02174 
02175 void
02176 HttpTransact::HandleCacheOpenRead(State* s)
02177 {
02178   DebugTxn("http_trans", "[HttpTransact::HandleCacheOpenRead]");
02179 
02180   SET_VIA_STRING(VIA_DETAIL_CACHE_TYPE, VIA_DETAIL_CACHE);
02181 
02182   bool read_successful = true;
02183 
02184   if (s->cache_info.object_read == 0) {
02185     read_successful = false;
02186     
02187     
02188     
02189     
02190     if (s->cache_lookup_result == CACHE_LOOKUP_DOC_BUSY) {
02191       s->cache_lookup_result = CACHE_LOOKUP_MISS;
02192       s->cache_info.action = CACHE_DO_NO_ACTION;
02193     }
02194   } else {
02195     CacheHTTPInfo *obj = s->cache_info.object_read;
02196     if (obj->response_get()->type_get() == HTTP_TYPE_UNKNOWN) {
02197       read_successful = false;
02198     }
02199     if (obj->request_get()->type_get() == HTTP_TYPE_UNKNOWN) {
02200       read_successful = false;
02201     }
02202   }
02203 
02204   if (s->method == HTTP_WKSIDX_PUSH) {
02205     HandleCacheOpenReadPush(s, read_successful);
02206   } else if (read_successful == false) {
02207     
02208     DebugTxn("http_trans", "CacheOpenRead -- miss");
02209     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_NOT_CACHED);
02210     
02211     if (s->force_dns) {
02212       HandleCacheOpenReadMiss(s);
02213     } else {
02214       
02215       TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
02216     }
02217   }
02218   else {
02219     
02220     DebugTxn("http_trans", "CacheOpenRead -- hit");
02221     TRANSACT_RETURN(SM_ACTION_API_READ_CACHE_HDR, HandleCacheOpenReadHitFreshness);
02222   }
02223 
02224   return;
02225 }
02226 
02227 
02228 
02229 
02230 
02231 
02232 
02233 
02234 
02235 
02236 
02237 
02238 
02239 
02240 
02241 
02242 
02243 
02244 
02245 
02246 void
02247 HttpTransact::issue_revalidate(State* s)
02248 {
02249   HTTPHdr *c_resp = find_appropriate_cached_resp(s);
02250   SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_STALE);
02251   ink_assert(GET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP) != ' ');
02252 
02253   if (s->www_auth_content == CACHE_AUTH_FRESH) {
02254     s->hdr_info.server_request.method_set(HTTP_METHOD_HEAD, HTTP_LEN_HEAD);
02255     
02256     
02257     
02258     s->cache_info.action = CACHE_DO_UPDATE;
02259     DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
02260     return;
02261   }
02262 
02263   if (s->cache_info.write_lock_state == CACHE_WL_INIT) {
02264     
02265     
02266     
02267     
02268     
02269     if (does_method_require_cache_copy_deletion(s->http_config_param, s->method)) {
02270       s->cache_info.action = CACHE_PREPARE_TO_DELETE;
02271       DebugTxn("http_seq", "[HttpTransact::issue_revalidate] cache action: DELETE");
02272     } else {
02273       s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
02274       DebugTxn("http_seq", "[HttpTransact::issue_revalidate] cache action: UPDATE");
02275     }
02276   } else {
02277     
02278     
02279     ink_assert(s->cache_info.write_lock_state == CACHE_WL_READ_RETRY);
02280     s->cache_info.action = CACHE_DO_NO_ACTION;
02281     return;
02282   }
02283 
02284   
02285 
02286   
02287   
02288   
02289   
02290   
02291   
02292   
02293   
02294   
02295   bool no_cache_in_request = false;
02296 
02297   if (s->hdr_info.client_request.is_pragma_no_cache_set() ||
02298       s->hdr_info.client_request.is_cache_control_set(HTTP_VALUE_NO_CACHE)) {
02299     DebugTxn("http_trans", "[issue_revalidate] no-cache header directive in request, folks");
02300     no_cache_in_request = true;
02301   }
02302 
02303   if ((!(s->hdr_info.client_request.presence(MIME_PRESENCE_IF_MODIFIED_SINCE))) &&
02304       (!(s->hdr_info.client_request.presence(MIME_PRESENCE_IF_NONE_MATCH))) &&
02305       (no_cache_in_request == true) &&
02306       (!s->txn_conf->cache_ims_on_client_no_cache) && (s->www_auth_content == CACHE_AUTH_NONE)) {
02307     DebugTxn("http_trans", "[issue_revalidate] Can not make this a conditional request. This is the force update of the cached copy case");
02308     
02309     
02310     s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
02311     return;
02312   }
02313   
02314   switch (c_resp->status_get()) {
02315   case HTTP_STATUS_OK:         
02316     
02317     
02318     if (s->txn_conf->cache_when_to_revalidate == 4)
02319       break;
02320     
02321     
02322     
02323     if (c_resp->get_last_modified() > 0 &&
02324         (s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_GET ||
02325                 s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD) && s->range_setup == RANGE_NONE) {
02326       
02327       int length;
02328       const char *str = c_resp->value_get(MIME_FIELD_LAST_MODIFIED, MIME_LEN_LAST_MODIFIED, &length);
02329 
02330       s->hdr_info.server_request.value_set(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE, str, length);
02331       if (!s->cop_test_page)
02332         DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
02333     }
02334     
02335     if (c_resp->presence(MIME_PRESENCE_ETAG) &&
02336                         (s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_GET ||
02337                          s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD)) {
02338       int length;
02339       const char *etag = c_resp->value_get(MIME_FIELD_ETAG, MIME_LEN_ETAG, &length);
02340       if ((length >= 2) && (etag[0] == 'W') && (etag[1] == '/')) {
02341         etag += 2;
02342         length -= 2;
02343       }
02344       s->hdr_info.server_request.value_set(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH, etag, length);
02345       if (!s->cop_test_page)
02346         DUMP_HEADER("http_hdrs", &s->hdr_info.server_request, s->state_machine_id, "Proxy's Request (Conditionalized)");
02347     }
02348     break;
02349   case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:      
02350     
02351   case HTTP_STATUS_MULTIPLE_CHOICES:   
02352     
02353   case HTTP_STATUS_MOVED_PERMANENTLY:  
02354     
02355   case HTTP_STATUS_GONE:       
02356     
02357   default:
02358     DebugTxn("http_trans", "[issue_revalidate] cached response is" "not a 200 response so no conditionalization.");
02359     s->cache_info.action = CACHE_PREPARE_TO_UPDATE;
02360     break;
02361   case HTTP_STATUS_PARTIAL_CONTENT:
02362     ink_assert(!"unexpected status code");
02363     break;
02364   }
02365 }
02366 
02367 
02368 void
02369 HttpTransact::HandleCacheOpenReadHitFreshness(State* s)
02370 {
02371   CacheHTTPInfo *&obj = s->cache_info.object_read;
02372 
02373   ink_release_assert((s->request_sent_time == UNDEFINED_TIME) && (s->response_received_time == UNDEFINED_TIME));
02374   DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHitFreshness] Hit in cache");
02375 
02376   if (delete_all_document_alternates_and_return(s, true)) {
02377     DebugTxn("http_trans", "[HandleCacheOpenReadHitFreshness] Delete and return");
02378     s->cache_info.action = CACHE_DO_DELETE;
02379     s->next_action = HttpTransact::SM_ACTION_INTERNAL_CACHE_DELETE;
02380     return;
02381   }
02382 
02383   s->request_sent_time = obj->request_sent_time_get();
02384   s->response_received_time = obj->response_received_time_get();
02385 
02386   
02387   
02388   
02389   
02390   
02391   s->request_sent_time = min(s->client_request_time, s->request_sent_time);
02392   s->response_received_time = min(s->client_request_time, s->response_received_time);
02393 
02394   ink_assert(s->request_sent_time <= s->response_received_time);
02395 
02396   DebugTxn("http_trans", "[HandleCacheOpenReadHitFreshness] request_sent_time      : %" PRId64,
02397            (int64_t)s->request_sent_time);
02398   DebugTxn("http_trans", "[HandleCacheOpenReadHitFreshness] response_received_time : %" PRId64,
02399            (int64_t)s->response_received_time);
02400   
02401   
02402   if (s->cache_lookup_result == HttpTransact::CACHE_LOOKUP_NONE) {
02403     
02404     
02405     Freshness_t freshness = what_is_document_freshness(s, &s->hdr_info.client_request, obj->response_get());
02406     switch (freshness) {
02407     case FRESHNESS_FRESH:
02408       DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHitFreshness] " "Fresh copy");
02409       s->cache_lookup_result = HttpTransact::CACHE_LOOKUP_HIT_FRESH;
02410       break;
02411     case FRESHNESS_WARNING:
02412       DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHitFreshness] " "Heuristic-based Fresh copy");
02413       s->cache_lookup_result = HttpTransact::CACHE_LOOKUP_HIT_WARNING;
02414       break;
02415     case FRESHNESS_STALE:
02416       DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHitFreshness] " "Stale in cache");
02417       s->cache_lookup_result = HttpTransact::CACHE_LOOKUP_HIT_STALE;
02418       s->is_revalidation_necessary = true;      
02419       break;
02420     default:
02421       ink_assert(!("what_is_document_freshness has returned unsupported code."));
02422       break;
02423     }
02424   }
02425 
02426   ink_assert(s->cache_lookup_result != HttpTransact::CACHE_LOOKUP_MISS);
02427   if (s->cache_lookup_result == HttpTransact::CACHE_LOOKUP_HIT_STALE)
02428     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_EXPIRED);
02429 
02430   if (!s->force_dns) {          
02431     if (need_to_revalidate(s)) {
02432       TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, CallOSDNSLookup); 
02433     } else {                    
02434       TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, HttpTransact::HandleCacheOpenReadHit);
02435     }
02436   } else {                      
02437     TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, HttpTransact::HandleCacheOpenReadHit);
02438   }
02439 }
02440 
02441 
02442 
02443 
02444 
02445 
02446 
02447 void
02448 HttpTransact::CallOSDNSLookup(State* s)
02449 {
02450   TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
02451 }
02452 
02453 
02454 
02455 
02456 
02457 
02458 
02459 
02460 bool
02461 HttpTransact::need_to_revalidate(State* s)
02462 {
02463   bool needs_revalidate, needs_authenticate = false;
02464   bool needs_cache_auth = false;
02465   CacheHTTPInfo *obj;
02466 
02467   if (s->api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02468     obj = &s->cache_info.object_store;
02469     ink_assert(obj->valid());
02470     if (!obj->valid())
02471       return true;
02472   } else
02473     obj = s->cache_info.object_read;
02474 
02475   
02476   
02477   Authentication_t authentication_needed =
02478     AuthenticationNeeded(s->txn_conf, &s->hdr_info.client_request, obj->response_get());
02479 
02480   switch (authentication_needed) {
02481   case AUTHENTICATION_SUCCESS:
02482     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication not needed");
02483     needs_authenticate = false;
02484     break;
02485   case AUTHENTICATION_MUST_REVALIDATE:
02486     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_METHOD);
02487     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed");
02488     needs_authenticate = true;
02489     break;
02490   case AUTHENTICATION_MUST_PROXY:
02491     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed");
02492     needs_authenticate = true;
02493     break;
02494   case AUTHENTICATION_CACHE_AUTH:
02495     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed for cache_auth_content");
02496     needs_authenticate = false;
02497     needs_cache_auth = true;
02498     break;
02499   default:
02500     ink_assert(!("AuthenticationNeeded has returned unsupported code."));
02501     return true;
02502     break;
02503   }
02504 
02505   ink_assert(s->cache_lookup_result == CACHE_LOOKUP_HIT_FRESH ||
02506              s->cache_lookup_result == CACHE_LOOKUP_HIT_WARNING || s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE);
02507   if (s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE &&
02508       s->api_update_cached_object != HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02509     needs_revalidate = true;
02510   } else
02511     needs_revalidate = false;
02512 
02513 
02514   bool
02515     send_revalidate = ((needs_authenticate == true) ||
02516                        (needs_revalidate == true) || (is_cache_response_returnable(s) == false));
02517   if (needs_cache_auth == true) {
02518     s->www_auth_content = send_revalidate ? CACHE_AUTH_STALE : CACHE_AUTH_FRESH;
02519     send_revalidate = true;
02520   }
02521   return send_revalidate;
02522 }
02523 
02524 
02525 
02526 
02527 
02528 
02529 
02530 
02531 
02532 
02533 
02534 
02535 
02536 
02537 
02538 
02539 
02540 
02541 
02542 
02543 
02544 
02545 
02546 
02547 
02548 
02549 
02550 
02551 
02552 
02553 
02554 
02555 
02556 void
02557 HttpTransact::HandleCacheOpenReadHit(State* s)
02558 {
02559   bool needs_revalidate, needs_authenticate = false;
02560   bool needs_cache_auth = false;
02561   bool server_up = true;
02562   CacheHTTPInfo *obj;
02563 
02564   if (s->api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02565     obj = &s->cache_info.object_store;
02566     ink_assert(obj->valid());
02567   } else
02568     obj = s->cache_info.object_read;
02569 
02570   
02571   
02572   Authentication_t authentication_needed =
02573     AuthenticationNeeded(s->txn_conf, &s->hdr_info.client_request, obj->response_get());
02574 
02575   switch (authentication_needed) {
02576   case AUTHENTICATION_SUCCESS:
02577     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication not needed");
02578     needs_authenticate = false;
02579     break;
02580   case AUTHENTICATION_MUST_REVALIDATE:
02581     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_METHOD);
02582     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed");
02583     needs_authenticate = true;
02584     break;
02585   case AUTHENTICATION_MUST_PROXY:
02586     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed");
02587     HandleCacheOpenReadMiss(s);
02588     return;
02589   case AUTHENTICATION_CACHE_AUTH:
02590     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Authentication needed for cache_auth_content");
02591     needs_authenticate = false;
02592     needs_cache_auth = true;
02593     break;
02594   default:
02595     ink_assert(!("AuthenticationNeeded has returned unsupported code."));
02596     break;
02597   }
02598 
02599   ink_assert(s->cache_lookup_result == CACHE_LOOKUP_HIT_FRESH ||
02600              s->cache_lookup_result == CACHE_LOOKUP_HIT_WARNING ||
02601              s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE);
02602   if (s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE &&
02603       s->api_update_cached_object != HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02604     needs_revalidate = true;
02605     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_EXPIRED);
02606   } else
02607     needs_revalidate = false;
02608 
02609   
02610   
02611   
02612   
02613   
02614   
02615   
02616   
02617   
02618   
02619   
02620   
02621   
02622   
02623   bool response_returnable = is_cache_response_returnable(s);
02624 
02625   
02626   
02627   
02628   bool send_revalidate = ((needs_authenticate == true) || (needs_revalidate == true) || (response_returnable == false));
02629 
02630   if (needs_cache_auth == true) {
02631     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_EXPIRED);
02632     s->www_auth_content = send_revalidate ? CACHE_AUTH_STALE : CACHE_AUTH_FRESH;
02633     send_revalidate = true;
02634   }
02635 
02636   DebugTxn("http_trans", "CacheOpenRead --- needs_auth          = %d", needs_authenticate);
02637   DebugTxn("http_trans", "CacheOpenRead --- needs_revalidate    = %d", needs_revalidate);
02638   DebugTxn("http_trans", "CacheOpenRead --- response_returnable = %d", response_returnable);
02639   DebugTxn("http_trans", "CacheOpenRead --- needs_cache_auth    = %d", needs_cache_auth);
02640   DebugTxn("http_trans", "CacheOpenRead --- send_revalidate    = %d", send_revalidate);
02641   if (send_revalidate) {
02642     DebugTxn("http_trans", "CacheOpenRead --- HIT-STALE");
02643     s->dns_info.attempts = 0;
02644 
02645     DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Revalidate document with server");
02646 
02647     if (s->http_config_param->icp_enabled && icp_dynamic_enabled && s->http_config_param->stale_icp_enabled &&
02648         needs_authenticate == false && needs_cache_auth == false &&
02649         !s->hdr_info.client_request.is_pragma_no_cache_set() &&
02650         !s->hdr_info.client_request.is_cache_control_set(HTTP_VALUE_NO_CACHE)) {
02651       DebugTxn("http_trans", "[HandleCacheOpenReadHit] ICP is configured" " and no no-cache in request; checking ICP for a STALE hit");
02652 
02653       s->stale_icp_lookup = true;
02654 
02655       
02656       
02657       s->icp_info.http_version.set(1, 0);
02658       if (!s->txn_conf->keep_alive_enabled_out) {
02659         s->icp_info.keep_alive = HTTP_NO_KEEPALIVE;
02660       } else {
02661         s->icp_info.keep_alive = HTTP_KEEPALIVE;
02662       }
02663 
02664       update_current_info(&s->current, &s->icp_info, HttpTransact::ICP_SUGGESTED_HOST, 1);
02665     }
02666 
02667     if (s->stale_icp_lookup == false) {
02668       find_server_and_update_current_info(s);
02669 
02670       
02671       
02672       
02673       
02674       
02675       
02676       
02677       
02678       if (s->current.request_to == ORIGIN_SERVER &&
02679           is_server_negative_cached(s) && response_returnable == true &&
02680           is_stale_cache_response_returnable(s) == true) {
02681         server_up = false;
02682         update_current_info(&s->current, NULL, UNDEFINED_LOOKUP, 0);
02683         DebugTxn("http_trans", "CacheOpenReadHit - server_down, returning stale document");
02684       }
02685     }
02686 
02687     if (server_up || s->stale_icp_lookup) {
02688       if (!s->stale_icp_lookup && !ats_is_ip(&s->current.server->addr)) {
02689 
02690 
02691 
02692         
02693         
02694         ink_assert(s->pending_work == NULL);
02695         s->pending_work = issue_revalidate;
02696 
02697         
02698         
02699         
02700         
02701         
02702         
02703         
02704         if (s->current.request_to == PARENT_PROXY) {
02705           TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
02706         } else if (s->current.request_to == ORIGIN_SERVER) {
02707           TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
02708         } else {
02709           handle_parent_died(s);
02710           return;
02711         }
02712       }
02713 
02714       build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->current.server->http_version);
02715 
02716       issue_revalidate(s);
02717 
02718       
02719       
02720       
02721       s->next_action = how_to_open_connection(s);
02722       if (s->stale_icp_lookup && s->next_action == SM_ACTION_ORIGIN_SERVER_OPEN) {
02723         s->next_action = SM_ACTION_ICP_QUERY;
02724       }
02725 
02726       ink_release_assert(s->next_action != SM_ACTION_ORIGIN_SERVER_RAW_OPEN);
02727       return;
02728     } else {                    
02729       SET_VIA_STRING(VIA_DETAIL_CACHE_TYPE, VIA_DETAIL_CACHE);
02730     }
02731   }
02732   
02733   
02734   
02735   
02736   
02737   
02738   
02739   
02740   
02741   
02742   
02743   
02744   
02745   
02746   
02747   
02748   
02749   
02750   ink_assert((send_revalidate == true && server_up == false) || (send_revalidate == false && server_up == true));
02751 
02752   DebugTxn("http_trans", "CacheOpenRead --- HIT-FRESH");
02753   DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] " "Serve from cache");
02754 
02755   if (s->cache_info.is_ram_cache_hit) {
02756     SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_RAM_CACHE_FRESH);
02757   } else {
02758     SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_FRESH);
02759   }
02760 
02761   if (s->cache_lookup_result == CACHE_LOOKUP_HIT_WARNING) {
02762     build_response_from_cache(s, HTTP_WARNING_CODE_HERUISTIC_EXPIRATION);
02763   } else if (s->cache_lookup_result == CACHE_LOOKUP_HIT_STALE) {
02764     ink_assert(server_up == false);
02765     build_response_from_cache(s, HTTP_WARNING_CODE_REVALIDATION_FAILED);
02766   } else {
02767     build_response_from_cache(s, HTTP_WARNING_CODE_NONE);
02768   }
02769 
02770   if (s->api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02771     s->saved_update_next_action = s->next_action;
02772     s->saved_update_cache_action = s->cache_info.action;
02773     s->next_action = SM_ACTION_CACHE_PREPARE_UPDATE;
02774   }
02775 }
02776 
02777 
02778 
02779 
02780 
02781 
02782 
02783 
02784 
02785 
02786 
02787 
02788 
02789 
02790 
02791 void
02792 HttpTransact::build_response_from_cache(State* s, HTTPWarningCode warning_code)
02793 {
02794   HTTPHdr *client_request = &s->hdr_info.client_request;
02795   HTTPHdr *cached_response = NULL;
02796   HTTPHdr *to_warn = &s->hdr_info.client_response;
02797   CacheHTTPInfo *obj;
02798 
02799   if (s->api_update_cached_object == HttpTransact::UPDATE_CACHED_OBJECT_CONTINUE) {
02800     obj = &s->cache_info.object_store;
02801     ink_assert(obj->valid());
02802   } else
02803     obj = s->cache_info.object_read;
02804   cached_response = obj->response_get();
02805 
02806   
02807   
02808   
02809   
02810   
02811   
02812   
02813   HTTPStatus client_response_code =
02814     HttpTransactCache::match_response_to_request_conditionals(client_request, cached_response);
02815 
02816   switch (client_response_code) {
02817   case HTTP_STATUS_NOT_MODIFIED:
02818     
02819     
02820     DebugTxn("http_trans", "[build_response_from_cache] Not modified");
02821     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_HIT_CONDITIONAL);
02822 
02823     build_response(s, cached_response, &s->hdr_info.client_response, s->client_info.http_version, client_response_code);
02824     s->cache_info.action = CACHE_DO_NO_ACTION;
02825     s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
02826     break;
02827 
02828   case HTTP_STATUS_PRECONDITION_FAILED:
02829     
02830     
02831     DebugTxn("http_trans", "[build_response_from_cache] Precondition Failed");
02832     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_CONDITIONAL);
02833 
02834     build_response(s, &s->hdr_info.client_response, s->client_info.http_version, client_response_code);
02835     s->cache_info.action = CACHE_DO_NO_ACTION;
02836     s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
02837     break;
02838 
02839   case HTTP_STATUS_RANGE_NOT_SATISFIABLE:
02840     
02841     
02842     
02843     
02844     
02845   default:
02846     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_HIT_SERVED);
02847     if (s->method == HTTP_WKSIDX_GET || s->api_resp_cacheable == true) {
02848       
02849       DebugTxn("http_trans", "[build_response_from_cache] Match! Serving full document.");
02850       s->cache_info.action = CACHE_DO_SERVE;
02851 
02852       
02853       
02854       
02855       if (client_response_code == HTTP_STATUS_OK && client_request->presence(MIME_PRESENCE_RANGE)) {
02856         s->state_machine->do_range_setup_if_necessary();
02857         if (s->range_setup == RANGE_NOT_SATISFIABLE) {
02858           build_error_response(s, HTTP_STATUS_RANGE_NOT_SATISFIABLE, "Requested Range Not Satisfiable", "default", NULL);
02859           s->cache_info.action = CACHE_DO_NO_ACTION;
02860           s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
02861           break;
02862         } else if (s->range_setup == RANGE_NOT_HANDLED) {
02863           
02864           
02865           
02866           DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] Out-of-order Range request - tunneling");
02867           s->cache_info.action = CACHE_DO_NO_ACTION;
02868           if (s->force_dns) {
02869             HandleCacheOpenReadMiss(s); 
02870           } else {
02871             TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);   
02872           }
02873           return;
02874         }
02875       }
02876 
02877       if (s->state_machine->do_transform_open()) {
02878         set_header_for_transform(s, cached_response);
02879         to_warn = &s->hdr_info.transform_response;
02880       } else {
02881         build_response(s, cached_response, &s->hdr_info.client_response, s->client_info.http_version);
02882       }
02883       s->next_action = SM_ACTION_SERVE_FROM_CACHE;
02884     }
02885     
02886     else if (s->method == HTTP_WKSIDX_HEAD) {
02887       DebugTxn("http_trans", "[build_response_from_cache] Match! Serving header only.");
02888 
02889       build_response(s, cached_response, &s->hdr_info.client_response, s->client_info.http_version);
02890       s->cache_info.action = CACHE_DO_NO_ACTION;
02891       s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
02892     } else {
02893       
02894       
02895       
02896       DebugTxn("http_trans", "[build_response_from_cache] No match! Connection failed.");
02897       build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Connection Failed", "connect#failed_connect", NULL);
02898       s->cache_info.action = CACHE_DO_NO_ACTION;
02899       s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
02900       warning_code = HTTP_WARNING_CODE_NONE;
02901     }
02902     break;
02903   }
02904 
02905   
02906   if (warning_code != HTTP_WARNING_CODE_NONE) {
02907     delete_warning_value(to_warn, warning_code);
02908     HttpTransactHeaders::insert_warning_header(s->http_config_param, to_warn, warning_code);
02909   }
02910 }
02911 
02912 
02913 
02914 
02915 
02916 
02917 
02918 
02919 
02920 
02921 
02922 
02923 
02924 void
02925 HttpTransact::handle_cache_write_lock(State* s)
02926 {
02927   bool remove_ims = false;
02928 
02929   ink_assert(s->cache_info.action == CACHE_PREPARE_TO_DELETE ||
02930              s->cache_info.action == CACHE_PREPARE_TO_UPDATE || s->cache_info.action == CACHE_PREPARE_TO_WRITE);
02931 
02932   switch (s->cache_info.write_lock_state) {
02933   case CACHE_WL_SUCCESS:
02934     
02935     SET_UNPREPARE_CACHE_ACTION(s->cache_info);
02936     break;
02937   case CACHE_WL_FAIL:
02938     
02939     
02940     s->cache_info.action = CACHE_DO_NO_ACTION;
02941     s->cache_info.write_status = CACHE_WRITE_LOCK_MISS;
02942     remove_ims = true;
02943     break;
02944   case CACHE_WL_READ_RETRY:
02945     
02946     
02947     
02948     
02949     s->request_sent_time = UNDEFINED_TIME;
02950     s->response_received_time = UNDEFINED_TIME;
02951     s->cache_info.action = CACHE_DO_LOOKUP;
02952     remove_ims = true;
02953     SET_VIA_STRING(VIA_DETAIL_CACHE_TYPE, VIA_DETAIL_CACHE);
02954     break;
02955   case CACHE_WL_INIT:
02956   default:
02957     ink_release_assert(0);
02958     break;
02959   }
02960 
02961   
02962   
02963   
02964   
02965   if (remove_ims) {
02966     s->hdr_info.server_request.field_delete(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE);
02967     s->hdr_info.server_request.field_delete(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH);
02968     MIMEField *c_ims = s->hdr_info.client_request.field_find(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE);
02969     MIMEField *c_inm = s->hdr_info.client_request.field_find(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH);
02970 
02971     if (c_ims) {
02972       int len;
02973       const char *value = c_ims->value_get(&len);
02974       s->hdr_info.server_request.value_set(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE, value, len);
02975     }
02976     if (c_inm) {
02977       int len;
02978       const char *value = c_inm->value_get(&len);
02979       s->hdr_info.server_request.value_set(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH, value, len);
02980     }
02981   }
02982 
02983   if (s->cache_info.write_lock_state == CACHE_WL_READ_RETRY) {
02984     s->hdr_info.server_request.destroy();
02985     HandleCacheOpenReadHitFreshness(s);
02986   } else {
02987     StateMachineAction_t next;
02988     if (s->stale_icp_lookup == false) {
02989       next = how_to_open_connection(s);
02990       if (next == SM_ACTION_ORIGIN_SERVER_OPEN || next == SM_ACTION_ORIGIN_SERVER_RAW_OPEN) {
02991         s->next_action = next;
02992         TRANSACT_RETURN(next, NULL);
02993       } else {
02994         
02995         s->next_action = next;
02996         ink_assert(s->next_action == SM_ACTION_DNS_LOOKUP);
02997         return;
02998       }
02999     } else {
03000       next = SM_ACTION_ICP_QUERY;
03001     }
03002 
03003     TRANSACT_RETURN(next, NULL);
03004   }
03005 }
03006 
03007 
03008 
03009 
03010 
03011 
03012 
03013 
03014 
03015 
03016 
03017 
03018 
03019 
03020 
03021 
03022 
03023 void
03024 HttpTransact::HandleCacheOpenReadMiss(State* s)
03025 {
03026   DebugTxn("http_trans", "[HandleCacheOpenReadMiss] --- MISS");
03027   DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadMiss] " "Miss in cache");
03028 
03029   if (delete_all_document_alternates_and_return(s, false)) {
03030     DebugTxn("http_trans", "[HandleCacheOpenReadMiss] Delete and return");
03031     s->cache_info.action = CACHE_DO_NO_ACTION;
03032     s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
03033     return;
03034   }
03035   
03036   s->cache_info.object_read = NULL;
03037   s->request_sent_time = UNDEFINED_TIME;
03038   s->response_received_time = UNDEFINED_TIME;
03039   SET_VIA_STRING(VIA_CACHE_RESULT, VIA_CACHE_MISS);
03040   if (GET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP) == ' ') {
03041     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_NOT_CACHED);
03042   }
03043   
03044   
03045   if (does_method_require_cache_copy_deletion(s->http_config_param, s->method) && s->api_req_cacheable == false) {
03046     s->cache_info.action = CACHE_DO_NO_ACTION;
03047   } else if ((s->hdr_info.client_request.presence(MIME_PRESENCE_RANGE) && !s->txn_conf->cache_range_write) ||
03048              s->range_setup == RANGE_NOT_SATISFIABLE || s->range_setup == RANGE_NOT_HANDLED) {
03049     s->cache_info.action = CACHE_DO_NO_ACTION;
03050   } else {
03051     s->cache_info.action = CACHE_PREPARE_TO_WRITE;
03052   }
03053 
03054   
03055   
03056   
03057   
03058 
03059   
03060   bool no_cache_in_request = false;
03061 
03062   if (s->hdr_info.client_request.is_pragma_no_cache_set() ||
03063       s->hdr_info.client_request.is_cache_control_set(HTTP_VALUE_NO_CACHE)) {
03064     no_cache_in_request = true;
03065   }
03066   
03067   
03068   if (s->http_config_param->icp_enabled && icp_dynamic_enabled != 0 && (no_cache_in_request == false)) {
03069     DebugTxn("http_trans", "[HandleCacheOpenReadMiss] " "ICP is configured and no no-cache in request; checking ICP");
03070     s->next_action = SM_ACTION_ICP_QUERY;
03071     return;
03072   }
03073 
03074   
03075   
03076   
03077   
03078 
03079 
03080   HTTPHdr *h = &s->hdr_info.client_request;
03081 
03082   if (!h->is_cache_control_set(HTTP_VALUE_ONLY_IF_CACHED)) {
03083     find_server_and_update_current_info(s);
03084     if (!ats_is_ip(&s->current.server->addr)) {
03085       ink_release_assert(s->current.request_to == PARENT_PROXY ||
03086                   s->http_config_param->no_dns_forward_to_parent != 0);
03087       if (s->current.request_to == PARENT_PROXY) {
03088         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, HttpTransact::PPDNSLookup);
03089       } else {
03090         handle_parent_died(s);
03091         return;
03092       }
03093     }
03094     build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->current.server->http_version);
03095 
03096     s->next_action = how_to_open_connection(s);
03097   } else {                      
03098     build_error_response(s, HTTP_STATUS_GATEWAY_TIMEOUT, "Not Cached", "cache#not_in_cache", NULL);
03099     s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
03100   }
03101 
03102   return;
03103 }
03104 
03105 
03106 
03107 
03108 
03109 
03110 
03111 
03112 
03113 
03114 
03115 
03116 
03117 
03118 
03119 
03120 void
03121 HttpTransact::HandleICPLookup(State* s)
03122 {
03123   SET_VIA_STRING(VIA_DETAIL_CACHE_TYPE, VIA_DETAIL_ICP);
03124   if (s->icp_lookup_success == true) {
03125     HTTP_INCREMENT_TRANS_STAT(http_icp_suggested_lookups_stat);
03126     DebugTxn("http_trans", "[HandleICPLookup] Success, sending request to icp suggested host.");
03127     ats_ip4_set(&s->icp_info.addr, s->icp_ip_result.sin_addr.s_addr);
03128     s->icp_info.port = ntohs(s->icp_ip_result.sin_port);
03129 
03130     
03131     
03132     ink_release_assert(
03133         (s->icp_info.port != s->client_info.port) || 
03134         (ats_ip_addr_cmp(&s->icp_info.addr.sa, &Machine::instance()->ip.sa) != 0)
03135     );        
03136 
03137     
03138     
03139     
03140     s->icp_info.http_version.set(1, 0);
03141     if (!s->txn_conf->keep_alive_enabled_out) {
03142       s->icp_info.keep_alive = HTTP_NO_KEEPALIVE;
03143     } else {
03144       s->icp_info.keep_alive = HTTP_KEEPALIVE;
03145     }
03146 
03147     s->icp_info.name = (char *) s->arena.alloc(17);
03148     unsigned char *p = (unsigned char *) &s->icp_ip_result.sin_addr.s_addr;
03149     snprintf(s->icp_info.name, 17, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
03150 
03151     update_current_info(&s->current, &s->icp_info, ICP_SUGGESTED_HOST, 1);
03152     s->next_hop_scheme = URL_WKSIDX_HTTP;
03153   } else {
03154     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_NOT_CACHED);
03155     DebugTxn("http_trans", "[HandleICPLookup] Failure, sending request to forward server.");
03156     s->parent_info.name = NULL;
03157     ink_zero(s->parent_info.addr);
03158 
03159     find_server_and_update_current_info(s);
03160     if (!ats_is_ip(&s->current.server->addr)) {
03161       if (s->current.request_to == PARENT_PROXY) {
03162         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
03163       } else {
03164         ink_release_assert(0);
03165       }
03166       return;
03167     }
03168   }
03169   if (!s->stale_icp_lookup) {
03170     build_request(s, &s->hdr_info.client_request, &s->hdr_info.server_request, s->current.server->http_version);
03171   } else {
03172     ink_assert(s->hdr_info.server_request.valid());
03173     s->stale_icp_lookup = false;
03174   }
03175   s->next_action = how_to_open_connection(s);
03176 
03177   return;
03178 }
03179 
03180 
03181 
03182 
03183 
03184 
03185 
03186 
03187 
03188 
03189 
03190 
03191 
03192 
03193 
03194 
03195 
03196 
03197 void
03198 HttpTransact::OriginServerRawOpen(State* s)
03199 {
03200   DebugTxn("http_trans", "[HttpTransact::OriginServerRawOpen]");
03201 
03202   switch (s->current.state) {
03203   case STATE_UNDEFINED:
03204     
03205   case OPEN_RAW_ERROR:
03206     
03207   case CONNECTION_ERROR:
03208     
03209   case CONNECTION_CLOSED:
03210     
03211   case CONGEST_CONTROL_CONGESTED_ON_F:
03212     
03213   case CONGEST_CONTROL_CONGESTED_ON_M:
03214     handle_server_died(s);
03215 
03216     ink_assert(s->cache_info.action == CACHE_DO_NO_ACTION);
03217     s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
03218     break;
03219   case CONNECTION_ALIVE:
03220     build_response(s, &s->hdr_info.client_response, s->client_info.http_version, HTTP_STATUS_OK);
03221 
03222     DebugTxn("http_trans", "[OriginServerRawOpen] connection alive. next action is ssl_tunnel");
03223     s->next_action = SM_ACTION_SSL_TUNNEL;
03224     break;
03225   default:
03226     ink_assert(!("s->current.state is set to something unsupported"));
03227     break;
03228   }
03229 
03230   return;
03231 }
03232 
03233 
03234 
03235 
03236 
03237 
03238 
03239 
03240 
03241 
03242 
03243 
03244 
03245 
03246 
03247 
03248 
03249 
03250 
03251 
03252 
03253 
03254 
03255 void
03256 HttpTransact::HandleResponse(State* s)
03257 {
03258   DebugTxn("http_trans", "[HttpTransact::HandleResponse]");
03259   DebugTxn("http_seq", "[HttpTransact::HandleResponse] Response received");
03260 
03261   s->source = SOURCE_HTTP_ORIGIN_SERVER;
03262   s->response_received_time = ink_cluster_time();
03263   ink_assert(s->response_received_time >= s->request_sent_time);
03264   s->current.now = s->response_received_time;
03265 
03266   DebugTxn("http_trans", "[HandleResponse] response_received_time: %" PRId64, (int64_t)s->response_received_time);
03267   if (!s->cop_test_page)
03268     DUMP_HEADER("http_hdrs", &s->hdr_info.server_response, s->state_machine_id, "Incoming O.S. Response");
03269 
03270   HTTP_INCREMENT_TRANS_STAT(http_incoming_responses_stat);
03271 
03272   ink_release_assert(s->current.request_to != UNDEFINED_LOOKUP);
03273   if (s->cache_info.action != CACHE_DO_WRITE) {
03274     ink_release_assert(s->cache_info.action != CACHE_DO_LOOKUP);
03275     ink_release_assert(s->cache_info.action != CACHE_DO_SERVE);
03276     ink_release_assert(s->cache_info.action != CACHE_PREPARE_TO_DELETE);
03277     ink_release_assert(s->cache_info.action != CACHE_PREPARE_TO_UPDATE);
03278     ink_release_assert(s->cache_info.action != CACHE_PREPARE_TO_WRITE);
03279   }
03280 
03281   if (!is_response_valid(s, &s->hdr_info.server_response)) {
03282     DebugTxn("http_seq", "[HttpTransact::HandleResponse] Response not valid");
03283   } else {
03284     DebugTxn("http_seq", "[HttpTransact::HandleResponse] Response valid");
03285     initialize_state_variables_from_response(s, &s->hdr_info.server_response);
03286   }
03287 
03288   switch (s->current.request_to) {
03289   case ICP_SUGGESTED_HOST:
03290     handle_response_from_icp_suggested_host(s);
03291     break;
03292   case PARENT_PROXY:
03293     handle_response_from_parent(s);
03294     break;
03295   case ORIGIN_SERVER:
03296     handle_response_from_server(s);
03297     break;
03298   default:
03299     ink_assert(!("s->current.request_to is not ICP, P.P. or O.S. - hmmm."));
03300     break;
03301   }
03302 
03303   return;
03304 }
03305 
03306 
03307 
03308 
03309 
03310 
03311 
03312 
03313 
03314 
03315 
03316 
03317 
03318 
03319 void
03320 HttpTransact::HandleUpdateCachedObject(State* s)
03321 {
03322   if (s->cache_info.write_lock_state == HttpTransact::CACHE_WL_SUCCESS) {
03323     ink_assert(s->cache_info.object_store.valid());
03324     ink_assert(s->cache_info.object_store.response_get() != NULL);
03325     ink_assert(s->cache_info.object_read != NULL);
03326     ink_assert(s->cache_info.object_read->valid());
03327 
03328     if (!s->cache_info.object_store.request_get())
03329       s->cache_info.object_store.request_set(s->cache_info.object_read->request_get());
03330     s->request_sent_time = s->cache_info.object_read->request_sent_time_get();
03331     s->response_received_time = s->cache_info.object_read->response_received_time_get();
03332     if (s->api_update_cached_object == UPDATE_CACHED_OBJECT_CONTINUE) {
03333       TRANSACT_RETURN(SM_ACTION_CACHE_ISSUE_UPDATE, HttpTransact::HandleUpdateCachedObjectContinue);
03334     } else {
03335       TRANSACT_RETURN(SM_ACTION_CACHE_ISSUE_UPDATE, HttpTransact::HandleApiErrorJump);
03336     }
03337   } else if (s->api_update_cached_object == UPDATE_CACHED_OBJECT_CONTINUE) {
03338     
03339     HandleUpdateCachedObjectContinue(s);
03340   } else {
03341     s->api_update_cached_object = UPDATE_CACHED_OBJECT_FAIL;
03342     HandleApiErrorJump(s);
03343   }
03344 }
03345 
03346 void
03347 HttpTransact::HandleUpdateCachedObjectContinue(State* s)
03348 {
03349   ink_assert(s->api_update_cached_object == UPDATE_CACHED_OBJECT_CONTINUE);
03350   s->cache_info.action = s->saved_update_cache_action;
03351   s->next_action = s->saved_update_next_action;
03352 }
03353 
03354 
03355 
03356 
03357 
03358 
03359 
03360 
03361 
03362 
03363 
03364 
03365 void
03366 HttpTransact::HandleStatPage(State* s)
03367 {
03368   HTTPStatus status;
03369 
03370   if (s->internal_msg_buffer) {
03371     status = HTTP_STATUS_OK;
03372   } else {
03373     status = HTTP_STATUS_BAD_REQUEST;
03374   }
03375 
03376   build_response(s, &s->hdr_info.client_response, s->client_info.http_version, status);
03377 
03378 
03379   
03380 
03381   s->hdr_info.client_response.set_content_length(s->internal_msg_buffer_size);
03382 
03383   if (s->internal_msg_buffer_type) {
03384     int len = strlen(s->internal_msg_buffer_type);
03385 
03386     if (len > 0) {
03387       s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE,
03388                                             s->internal_msg_buffer_type, len);
03389     }
03390   } else {
03391     s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE,
03392                                           "text/plain", 9);
03393   }
03394 
03395   s->cache_info.action = CACHE_DO_NO_ACTION;
03396   s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
03397 }
03398 
03399 
03400 
03401 
03402 
03403 
03404 
03405 
03406 
03407 
03408 
03409 
03410 
03411 
03412 
03413 
03414 
03415 void
03416 HttpTransact::handle_response_from_icp_suggested_host(State* s)
03417 {
03418   DebugTxn("http_trans", "[handle_response_from_icp_suggested_host] (hrfish)");
03419   HTTP_RELEASE_ASSERT(s->current.server == &s->icp_info);
03420 
03421   s->icp_info.state = s->current.state;
03422   switch (s->current.state) {
03423   case CONNECTION_ALIVE:
03424     DebugTxn("http_trans", "[hrfish] connection alive");
03425     SET_VIA_STRING(VIA_DETAIL_ICP_CONNECT, VIA_DETAIL_ICP_SUCCESS);
03426     handle_forward_server_connection_open(s);
03427     break;
03428   default:
03429     DebugTxn("http_trans", "[hrfish] connection not alive");
03430     SET_VIA_STRING(VIA_DETAIL_ICP_CONNECT, VIA_DETAIL_ICP_FAILURE);
03431 
03432     
03433     if (is_request_retryable(s) == false) {
03434       handle_server_died(s);
03435       return;
03436     }
03437     
03438     
03439     find_server_and_update_current_info(s);
03440     if (!ats_is_ip(&s->current.server->addr)) {
03441       if (s->current.request_to == PARENT_PROXY) {
03442         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
03443       } else {
03444         ink_release_assert(0);
03445       }
03446       return;
03447     }
03448     ink_assert(&s->hdr_info.server_request);
03449     s->next_action = how_to_open_connection(s);
03450     if (s->current.server == &s->server_info && s->next_hop_scheme == URL_WKSIDX_HTTP) {
03451       HttpTransactHeaders::remove_host_name_from_url(&s->hdr_info.server_request);
03452     }
03453     break;
03454   }
03455 }
03456 
03457 
03458 
03459 
03460 
03461 
03462 
03463 
03464 
03465 
03466 
03467 
03468 
03469 
03470 
03471 
03472 
03473 
03474 
03475 
03476 void
03477 HttpTransact::handle_response_from_parent(State* s)
03478 {
03479   DebugTxn("http_trans", "[handle_response_from_parent] (hrfp)");
03480   HTTP_RELEASE_ASSERT(s->current.server == &s->parent_info);
03481 
03482   s->parent_info.state = s->current.state;
03483   switch (s->current.state) {
03484   case CONNECTION_ALIVE:
03485     DebugTxn("http_trans", "[hrfp] connection alive");
03486     s->current.server->connect_result = 0;
03487     SET_VIA_STRING(VIA_DETAIL_PP_CONNECT, VIA_DETAIL_PP_SUCCESS);
03488     if (s->parent_result.retry) {
03489       s->parent_params->recordRetrySuccess(&s->parent_result);
03490     }
03491     handle_forward_server_connection_open(s);
03492     break;
03493   default:
03494     {
03495       LookingUp_t next_lookup = UNDEFINED_LOOKUP;
03496       DebugTxn("http_trans", "[hrfp] connection not alive");
03497       SET_VIA_STRING(VIA_DETAIL_PP_CONNECT, VIA_DETAIL_PP_FAILURE);
03498 
03499       ink_assert(s->hdr_info.server_request.valid());
03500 
03501       s->current.server->connect_result = ENOTCONN;
03502 
03503       char addrbuf[INET6_ADDRSTRLEN];
03504       DebugTxn("http_trans", "[%d] failed to connect to parent %s", s->current.attempts,
03505             ats_ip_ntop(&s->current.server->addr.sa, addrbuf, sizeof(addrbuf)));
03506 
03507       
03508       if (!is_request_retryable(s)) {
03509         s->parent_params->markParentDown(&s->parent_result);
03510         s->parent_result.r = PARENT_FAIL;
03511         handle_parent_died(s);
03512         return;
03513       }
03514 
03515       if (s->current.attempts < s->http_config_param->parent_connect_attempts) {
03516         s->current.attempts++;
03517 
03518         
03519         if ((s->current.attempts - 1) % s->http_config_param->per_parent_connect_attempts != 0) {
03520           
03521           s->next_action = how_to_open_connection(s);
03522           DebugTxn("http_trans", "%s Retrying parent for attempt %d, max %" PRId64,
03523                 "[handle_response_from_parent]", s->current.attempts, s->http_config_param->per_parent_connect_attempts);
03524           return;
03525         } else {
03526           DebugTxn("http_trans", "%s %d per parent attempts exhausted",
03527                 "[handle_response_from_parent]", s->current.attempts);
03528 
03529           
03530           
03531           
03532           if (s->current.state == CONNECTION_ERROR) {
03533             s->parent_params->markParentDown(&s->parent_result);
03534           }
03535           
03536           next_lookup = find_server_and_update_current_info(s);
03537         }
03538       } else {
03539         
03540         
03541         DebugTxn("http_trans", "[handle_response_from_parent] Error. No more retries.");
03542         s->parent_params->markParentDown(&s->parent_result);
03543         s->parent_result.r = PARENT_FAIL;
03544         next_lookup = find_server_and_update_current_info(s);
03545       }
03546 
03547       
03548       
03549       switch (next_lookup) {
03550       case PARENT_PROXY:
03551         ink_assert(s->current.request_to == PARENT_PROXY);
03552         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, PPDNSLookup);
03553         break;
03554       case ORIGIN_SERVER:
03555         s->current.attempts = 0;
03556         s->next_action = how_to_open_connection(s);
03557         if (s->current.server == &s->server_info && s->next_hop_scheme == URL_WKSIDX_HTTP) {
03558           HttpTransactHeaders::remove_host_name_from_url(&s->hdr_info.server_request);
03559         }
03560         break;
03561       case HOST_NONE:
03562         handle_parent_died(s);
03563         break;
03564       default:
03565         
03566         
03567         
03568         break;
03569       }
03570 
03571       break;
03572     }
03573   }
03574 }
03575 
03576 
03577 
03578 
03579 
03580 
03581 
03582 
03583 
03584 
03585 
03586 
03587 
03588 
03589 
03590 
03591 
03592 
03593 
03594 void
03595 HttpTransact::handle_response_from_server(State* s)
03596 {
03597   DebugTxn("http_trans", "[handle_response_from_server] (hrfs)");
03598   HTTP_RELEASE_ASSERT(s->current.server == &s->server_info);
03599   int max_connect_retries = 0;
03600 
03601   
03602   s->server_info.state = s->current.state;
03603   if (s->fp_tsremap_os_response) {
03604     s->fp_tsremap_os_response(s->remap_plugin_instance, reinterpret_cast<TSHttpTxn>(s->state_machine), s->current.state);
03605   }
03606 
03607   switch (s->current.state) {
03608   case CONNECTION_ALIVE:
03609     DebugTxn("http_trans", "[hrfs] connection alive");
03610     SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_SUCCESS);
03611     s->current.server->clear_connect_fail();
03612     handle_forward_server_connection_open(s);
03613     break;
03614   case CONGEST_CONTROL_CONGESTED_ON_F:
03615   case CONGEST_CONTROL_CONGESTED_ON_M:
03616     DebugTxn("http_trans", "[handle_response_from_server] Error. congestion control -- congested.");
03617     SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
03618     s->current.server->set_connect_fail(EUSERS); 
03619     handle_server_connection_not_open(s);
03620     break;
03621   case OPEN_RAW_ERROR:
03622     
03623   case CONNECTION_ERROR:
03624     
03625   case STATE_UNDEFINED:
03626     
03627   case INACTIVE_TIMEOUT:
03628     
03629   case PARSE_ERROR:
03630     
03631   case CONNECTION_CLOSED:
03632     
03633   case BAD_INCOMING_RESPONSE:
03634     
03635     if (!s->current.server->had_connect_fail())
03636       s->current.server->set_connect_fail(EIO);
03637 
03638     if (is_server_negative_cached(s)) {
03639       max_connect_retries = s->txn_conf->connect_attempts_max_retries_dead_server;
03640     } else {
03641       
03642       max_connect_retries = s->txn_conf->connect_attempts_max_retries;
03643     }
03644     if (s->pCongestionEntry != NULL)
03645       max_connect_retries = s->pCongestionEntry->connect_retries();
03646 
03647     if (is_request_retryable(s) && s->current.attempts < max_connect_retries) {
03648       
03649       
03650       if (DNSLookupInfo::OS_ADDR_TRY_CLIENT == s->dns_info.os_addr_style) {
03651         
03652         
03653         
03654         s->dns_info.lookup_success = false;
03655         
03656         s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_TRY_HOSTDB;
03657         
03658         
03659         
03660         s->state_machine->ua_session->host_res_style = ats_host_res_match(&s->current.server->addr.sa);
03661         TRANSACT_RETURN(SM_ACTION_DNS_LOOKUP, OSDNSLookup);
03662       } else if ((s->dns_info.srv_lookup_success || s->server_info.dns_round_robin) &&
03663                  (s->txn_conf->connect_attempts_rr_retries > 0) &&
03664                  (s->current.attempts % s->txn_conf->connect_attempts_rr_retries == 0)) {
03665         delete_server_rr_entry(s, max_connect_retries);
03666         return;
03667       } else {
03668         retry_server_connection_not_open(s, s->current.state, max_connect_retries);
03669         DebugTxn("http_trans", "[handle_response_from_server] Error. Retrying...");
03670         s->next_action = how_to_open_connection(s);
03671         return;
03672       }
03673     } else {
03674       DebugTxn("http_trans", "[handle_response_from_server] Error. No more retries.");
03675       SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
03676       handle_server_connection_not_open(s);
03677     }
03678     break;
03679   case ACTIVE_TIMEOUT:
03680     DebugTxn("http_trans", "[hrfs] connection not alive");
03681     SET_VIA_STRING(VIA_DETAIL_SERVER_CONNECT, VIA_DETAIL_SERVER_FAILURE);
03682     s->current.server->set_connect_fail(ETIMEDOUT);
03683     handle_server_connection_not_open(s);
03684     break;
03685   default:
03686     ink_assert(!("s->current.state is set to something unsupported"));
03687     break;
03688   }
03689 
03690   return;
03691 }
03692 
03693 
03694 
03695 
03696 
03697 
03698 
03699 
03700 
03701 
03702 
03703 
03704 
03705 
03706 
03707 void
03708 HttpTransact::delete_server_rr_entry(State* s, int max_retries)
03709 {
03710   char addrbuf[INET6_ADDRSTRLEN];
03711   
03712   DebugTxn("http_trans", "[%d] failed to connect to %s", s->current.attempts,
03713         ats_ip_ntop(&s->current.server->addr.sa, addrbuf, sizeof(addrbuf)));
03714   DebugTxn("http_trans", "[delete_server_rr_entry] marking rr entry " "down and finding next one");
03715   ink_assert(s->current.server->had_connect_fail());
03716   ink_assert(s->current.request_to == ORIGIN_SERVER);
03717   ink_assert(s->current.server == &s->server_info);
03718   update_dns_info(&s->dns_info, &s->current, 0, &s->arena);
03719   s->current.attempts++;
03720   DebugTxn("http_trans", "[delete_server_rr_entry] attempts now: %d, max: %d", s->current.attempts, max_retries);
03721   TRANSACT_RETURN(SM_ACTION_ORIGIN_SERVER_RR_MARK_DOWN, ReDNSRoundRobin);
03722 }
03723 
03724 
03725 
03726 
03727 
03728 
03729 
03730 
03731 
03732 
03733 
03734 
03735 
03736 void
03737 HttpTransact::retry_server_connection_not_open(State* s, ServerState_t conn_state, int max_retries)
03738 {
03739   ink_assert(s->current.state != CONNECTION_ALIVE);
03740   ink_assert(s->current.state != ACTIVE_TIMEOUT);
03741   ink_assert(s->current.attempts <= max_retries);
03742   ink_assert(s->current.server->had_connect_fail());
03743   char addrbuf[INET6_ADDRSTRLEN];
03744 
03745   char *url_string = s->hdr_info.client_request.url_string_get(&s->arena);
03746 
03747   DebugTxn("http_trans", "[%d] failed to connect [%d] to %s", s->current.attempts, conn_state,
03748         ats_ip_ntop(&s->current.server->addr.sa, addrbuf, sizeof(addrbuf)));
03749 
03750 
03751   
03752   
03753 
03754   if (0 == s->current.attempts)
03755     Log::error("CONNECT:[%d] could not connect [%s] to %s for '%s'",
03756      s->current.attempts,
03757      HttpDebugNames::get_server_state_name(conn_state),
03758      ats_ip_ntop(&s->current.server->addr.sa, addrbuf, sizeof(addrbuf)), url_string ? url_string : "<none>"
03759     );
03760 
03761   if (url_string) {
03762     s->arena.str_free(url_string);
03763   }
03764 
03765   
03766 
03767   s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
03768   s->current.attempts++;
03769 
03770   DebugTxn("http_trans", "[retry_server_connection_not_open] attempts now: %d, max: %d", s->current.attempts, max_retries);
03771 
03772   return;
03773 }
03774 
03775 
03776 
03777 
03778 
03779 
03780 
03781 
03782 
03783 
03784 
03785 void
03786 HttpTransact::handle_server_connection_not_open(State* s)
03787 {
03788   bool serve_from_cache = false;
03789 
03790   DebugTxn("http_trans", "[handle_server_connection_not_open] (hscno)");
03791   DebugTxn("http_seq", "[HttpTransact::handle_server_connection_not_open] ");
03792   ink_assert(s->current.state != CONNECTION_ALIVE);
03793   ink_assert(s->current.server->had_connect_fail());
03794 
03795   SET_VIA_STRING(VIA_SERVER_RESULT, VIA_SERVER_ERROR);
03796   HTTP_INCREMENT_TRANS_STAT(http_broken_server_connections_stat);
03797 
03798   
03799   s->state_machine->do_hostdb_update_if_necessary();
03800 
03801   switch (s->cache_info.action) {
03802   case CACHE_DO_UPDATE:
03803     serve_from_cache = is_stale_cache_response_returnable(s);
03804     break;
03805 
03806   case CACHE_PREPARE_TO_DELETE:
03807     
03808   case CACHE_PREPARE_TO_UPDATE:
03809     
03810   case CACHE_PREPARE_TO_WRITE:
03811     ink_release_assert(!"Why still preparing for cache action - " "we skipped a step somehow.");
03812     break;
03813 
03814   case CACHE_DO_LOOKUP:
03815     
03816   case CACHE_DO_SERVE:
03817     ink_assert(!("Why server response? Should have been a cache operation"));
03818     break;
03819 
03820   case CACHE_DO_DELETE:
03821     
03822     
03823     
03824     
03825     
03826   case CACHE_DO_UNDEFINED:
03827     
03828   case CACHE_DO_NO_ACTION:
03829     
03830   case CACHE_DO_WRITE:
03831     
03832   default:
03833     serve_from_cache = false;
03834     break;
03835   }
03836 
03837   if (serve_from_cache) {
03838     ink_assert(s->cache_info.object_read != NULL);
03839     ink_assert(s->cache_info.action == CACHE_DO_UPDATE);
03840     ink_assert(s->internal_msg_buffer == NULL);
03841 
03842     DebugTxn("http_trans", "[hscno] serving stale doc to client");
03843     build_response_from_cache(s, HTTP_WARNING_CODE_REVALIDATION_FAILED);
03844   } else {
03845     handle_server_died(s);
03846     s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
03847   }
03848 
03849   return;
03850 }
03851 
03852 
03853 
03854 
03855 
03856 
03857 
03858 
03859 
03860 
03861 
03862 
03863 
03864 
03865 
03866 
03867 
03868 void
03869 HttpTransact::handle_forward_server_connection_open(State* s)
03870 {
03871   DebugTxn("http_trans", "[handle_forward_server_connection_open] (hfsco)");
03872   DebugTxn("http_seq", "[HttpTransact::handle_server_connection_open] ");
03873   ink_release_assert(s->current.state == CONNECTION_ALIVE);
03874 
03875   if (s->hdr_info.server_response.version_get() == HTTPVersion(0, 9)) {
03876     DebugTxn("http_trans", "[hfsco] server sent 0.9 response, reading...");
03877     build_response(s, &s->hdr_info.client_response, s->client_info.http_version, HTTP_STATUS_OK, "Connection Established");
03878 
03879     s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
03880     s->cache_info.action = CACHE_DO_NO_ACTION;
03881     s->next_action = SM_ACTION_SERVER_READ;
03882     return;
03883 
03884   }
03885   else if (s->hdr_info.server_response.version_get() == HTTPVersion(1, 0)) {
03886     if (s->current.server->http_version == HTTPVersion(0, 9)) {
03887       
03888       s->updated_server_version = HostDBApplicationInfo::HTTP_VERSION_10;
03889     } else if (s->current.server->http_version == HTTPVersion(1, 1)) {
03890       
03891       s->updated_server_version = HostDBApplicationInfo::HTTP_VERSION_10;
03892     } else {
03893       
03894     }
03895   } else if (s->hdr_info.server_response.version_get() == HTTPVersion(1, 1)) {
03896     if (s->current.server->http_version == HTTPVersion(0, 9)) {
03897       
03898       s->updated_server_version = HostDBApplicationInfo::HTTP_VERSION_11;
03899     } else if (s->current.server->http_version == HTTPVersion(1, 0)) {
03900       
03901       s->updated_server_version = HostDBApplicationInfo::HTTP_VERSION_11;
03902     } else {
03903       
03904     }
03905   } else {
03906     
03907   }
03908 
03909   if (s->hdr_info.server_response.status_get() == HTTP_STATUS_CONTINUE) {
03910     handle_100_continue_response(s);
03911     return;
03912   }
03913 
03914   s->state_machine->do_hostdb_update_if_necessary();
03915 
03916   if (s->www_auth_content == CACHE_AUTH_FRESH) {
03917     
03918     
03919     if (s->hdr_info.server_response.status_get() == HTTP_STATUS_OK) {
03920       
03921       
03922       s->api_server_response_ignore = true;
03923     }
03924     
03925     
03926   }
03927 
03928   CacheVConnection* cw_vc = s->state_machine->get_cache_sm().cache_write_vc;
03929 
03930   if (s->redirect_info.redirect_in_process && s->state_machine->enable_redirection) {
03931     if (s->cache_info.action == CACHE_DO_NO_ACTION) {
03932       switch (s->hdr_info.server_response.status_get())
03933       {
03934       case HTTP_STATUS_MULTIPLE_CHOICES:     
03935       case HTTP_STATUS_MOVED_PERMANENTLY:    
03936       case HTTP_STATUS_MOVED_TEMPORARILY:    
03937       case HTTP_STATUS_SEE_OTHER:            
03938       case HTTP_STATUS_USE_PROXY:            
03939       case HTTP_STATUS_TEMPORARY_REDIRECT:   
03940         break;
03941       default:
03942         DebugTxn("http_trans", "[hfsco] redirect in progress, non-3xx response, setting cache_do_write");
03943         if (cw_vc) s->cache_info.action = CACHE_DO_WRITE;
03944         break;
03945       }
03946     }
03947   }
03948 
03949   switch (s->cache_info.action) {
03950   case CACHE_DO_WRITE:
03951     
03952   case CACHE_DO_UPDATE:
03953     
03954   case CACHE_DO_DELETE:
03955     DebugTxn("http_trans", "[hfsco] cache action: %s", HttpDebugNames::get_cache_action_name(s->cache_info.action));
03956     handle_cache_operation_on_forward_server_response(s);
03957     break;
03958   case CACHE_PREPARE_TO_DELETE:
03959     
03960   case CACHE_PREPARE_TO_UPDATE:
03961     
03962   case CACHE_PREPARE_TO_WRITE:
03963     ink_release_assert(!"Why still preparing for cache action - we skipped a step somehow.");
03964     break;
03965   case CACHE_DO_LOOKUP:
03966     
03967   case CACHE_DO_SERVE:
03968     ink_assert(!("Why server response? Should have been a cache operation"));
03969     break;
03970   case CACHE_DO_UNDEFINED:
03971     
03972   case CACHE_DO_NO_ACTION:
03973     
03974   default:
03975     
03976     DebugTxn("http_trans", "[hfsco] cache action: %s", HttpDebugNames::get_cache_action_name(s->cache_info.action));
03977     handle_no_cache_operation_on_forward_server_response(s);
03978     break;
03979   }
03980 
03981   return;
03982 }
03983 
03984 
03985 
03986 
03987 
03988 
03989 
03990 void
03991 HttpTransact::handle_100_continue_response(State* s)
03992 {
03993   bool forward_100 = false;
03994 
03995   HTTPVersion ver = s->hdr_info.client_request.version_get();
03996   if (ver == HTTPVersion(1, 1)) {
03997     forward_100 = true;
03998   } else if (ver == HTTPVersion(1, 0)) {
03999     if (s->hdr_info.client_request.value_get_int(MIME_FIELD_EXPECT, MIME_LEN_EXPECT) == 100) {
04000       forward_100 = true;
04001     }
04002   }
04003 
04004   if (forward_100) {
04005     
04006     
04007     
04008     build_response_copy(s, &s->hdr_info.server_response, &s->hdr_info.client_response, s->client_info.http_version);
04009     TRANSACT_RETURN(SM_ACTION_INTERNAL_100_RESPONSE, HandleResponse);
04010   } else {
04011     TRANSACT_RETURN(SM_ACTION_SERVER_PARSE_NEXT_HDR, HandleResponse);
04012   }
04013 }
04014 
04015 
04016 
04017 
04018 
04019 void
04020 HttpTransact::build_response_copy(State* s, HTTPHdr* base_response,HTTPHdr* outgoing_response, HTTPVersion outgoing_version)
04021 {
04022   HttpTransactHeaders::copy_header_fields(base_response, outgoing_response, s->txn_conf->fwd_proxy_auth_to_parent,
04023                                           s->current.now);
04024   HttpTransactHeaders::convert_response(outgoing_version, outgoing_response);   
04025   HttpTransactHeaders::add_server_header_to_response(s->txn_conf, outgoing_response);
04026 
04027   if (!s->cop_test_page)
04028     DUMP_HEADER("http_hdrs", outgoing_response, s->state_machine_id, "Proxy's Response");
04029 }
04030 
04031 
04032 
04033 
04034 
04035 
04036 
04037 
04038 
04039 
04040 
04041 
04042 
04043 
04044 
04045 
04046 
04047 
04048 
04049 
04050 
04051 
04052 
04053 
04054 
04055 
04056 
04057 
04058 
04059 
04060 
04061 
04062 
04063 
04064 
04065 
04066 
04067 
04068 
04069 
04070 
04071 
04072 
04073 void
04074 HttpTransact::handle_cache_operation_on_forward_server_response(State* s)
04075 {
04076   DebugTxn("http_trans", "[handle_cache_operation_on_forward_server_response] (hcoofsr)");
04077   DebugTxn("http_seq", "[handle_cache_operation_on_forward_server_response]");
04078 
04079   HTTPHdr *base_response = NULL;
04080   HTTPStatus server_response_code = HTTP_STATUS_NONE;
04081   HTTPStatus client_response_code = HTTP_STATUS_NONE;
04082   const char *warn_text = NULL;
04083   bool cacheable = false;
04084 
04085   cacheable = is_response_cacheable(s, &s->hdr_info.client_request, &s->hdr_info.server_response);
04086   DebugTxn("http_trans", "[hcoofsr] response %s cacheable", cacheable ? "is" : "is not");
04087 
04088   
04089 
04090   server_response_code = s->hdr_info.server_response.status_get();
04091   switch (server_response_code) {
04092   case HTTP_STATUS_NOT_MODIFIED:       
04093     SET_VIA_STRING(VIA_SERVER_RESULT, VIA_SERVER_NOT_MODIFIED);
04094 
04095     
04096     
04097     
04098     if (s->api_server_response_ignore && s->cache_info.action == CACHE_DO_UPDATE) {
04099       s->api_server_response_ignore = false;
04100       ink_assert(s->cache_info.object_read);
04101       base_response = s->cache_info.object_read->response_get();
04102       s->cache_info.action = CACHE_DO_SERVE;
04103       DebugTxn("http_trans", "[hcoofsr] not merging, cache action changed to: %s",
04104             HttpDebugNames::get_cache_action_name(s->cache_info.action));
04105       s->next_action = SM_ACTION_SERVE_FROM_CACHE;
04106       client_response_code = base_response->status_get();
04107     } else if ((s->cache_info.action == CACHE_DO_DELETE) || ((s->cache_info.action == CACHE_DO_UPDATE) && !cacheable)) {
04108       if (is_request_conditional(&s->hdr_info.client_request)) {
04109         client_response_code =
04110           HttpTransactCache::match_response_to_request_conditionals(&s->hdr_info.client_request,
04111                                                                     s->cache_info.object_read->response_get());
04112       } else {
04113         client_response_code = HTTP_STATUS_OK;
04114       }
04115 
04116       if (client_response_code != HTTP_STATUS_OK) {
04117         
04118         
04119         base_response = &s->hdr_info.server_response;
04120         client_response_code = base_response->status_get();
04121         s->cache_info.action = CACHE_DO_DELETE;
04122         s->next_action = SM_ACTION_INTERNAL_CACHE_DELETE;
04123       } else {
04124         
04125         
04126         
04127         
04128         if (s->method == HTTP_WKSIDX_HEAD) {
04129           s->cache_info.action = CACHE_DO_DELETE;
04130           s->next_action = SM_ACTION_SERVER_READ;
04131         } else {
04132           s->cache_info.action = CACHE_DO_SERVE_AND_DELETE;
04133           s->next_action = SM_ACTION_SERVE_FROM_CACHE;
04134         }
04135         base_response = s->cache_info.object_read->response_get();
04136         client_response_code = base_response->status_get();
04137       }
04138 
04139     } else if (s->cache_info.action == CACHE_DO_UPDATE && is_request_conditional(&s->hdr_info.server_request)) {
04140       
04141       if (is_request_conditional(&s->hdr_info.client_request)) {
04142         if (s->txn_conf->cache_when_to_revalidate != 4)
04143           client_response_code =
04144             HttpTransactCache::match_response_to_request_conditionals(&s->hdr_info.client_request,
04145                                                                       s->cache_info.object_read->response_get());
04146         else
04147           client_response_code = server_response_code;
04148       } else {
04149         client_response_code = HTTP_STATUS_OK;
04150       }
04151 
04152       if (client_response_code != HTTP_STATUS_OK) {
04153         
04154         if (s->txn_conf->cache_when_to_revalidate != 4) {
04155           s->cache_info.action = CACHE_DO_UPDATE;
04156           s->next_action = SM_ACTION_INTERNAL_CACHE_UPDATE_HEADERS;
04157           
04158         } else {
04159           s->cache_info.action = CACHE_DO_NO_ACTION;
04160           s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
04161           base_response = &s->hdr_info.server_response;
04162         }
04163       } else {
04164         if (s->method == HTTP_WKSIDX_HEAD) {
04165           s->cache_info.action = CACHE_DO_UPDATE;
04166           s->next_action = SM_ACTION_SERVER_READ;
04167         } else {
04168           if (s->hdr_info.client_request.presence(MIME_PRESENCE_RANGE)) {
04169             s->state_machine->do_range_setup_if_necessary();
04170             
04171             
04172             
04173           }
04174           s->cache_info.action = CACHE_DO_SERVE_AND_UPDATE;
04175           s->next_action = SM_ACTION_SERVE_FROM_CACHE;
04176         }
04177         
04178       }
04179 
04180     } else {                    
04181 
04182       
04183       
04184       
04185       DebugTxn("http_trans", "[hcoofsr] 304 for non-conditional request");
04186       s->cache_info.action = CACHE_DO_NO_ACTION;
04187       s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
04188       client_response_code = s->hdr_info.server_response.status_get();
04189       base_response = &s->hdr_info.server_response;
04190 
04191       
04192       
04193       
04194       
04195       
04196       
04197       
04198       if (is_request_likely_cacheable(s, &s->hdr_info.client_request)) {
04199         warn_text = "Proxy received unexpected 304 response; " "content may be stale";
04200       }
04201     }
04202 
04203     break;
04204 
04205   case HTTP_STATUS_HTTPVER_NOT_SUPPORTED:      
04206     {
04207       bool keep_alive = (s->current.server->keep_alive == HTTP_KEEPALIVE);
04208 
04209       s->next_action = how_to_open_connection(s);
04210 
04211       
04212       if (!HttpTransactHeaders::downgrade_request(&keep_alive, &s->hdr_info.server_request)) {
04213         build_error_response(s, HTTP_STATUS_HTTPVER_NOT_SUPPORTED, "HTTP Version Not Supported",
04214                              "response#bad_version", NULL);
04215         s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
04216         s->already_downgraded = true;
04217       } else {
04218         if (!keep_alive) {
04219           
04220           (s->hdr_info.server_request).field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
04221           
04222         }
04223         s->already_downgraded = true;
04224         s->next_action = how_to_open_connection(s);
04225       }
04226     }
04227     return;
04228 
04229   default:
04230     DebugTxn("http_trans", "[hcoofsr] response code: %d", server_response_code);
04231     SET_VIA_STRING(VIA_SERVER_RESULT, VIA_SERVER_SERVED);
04232     SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVED);
04233 
04234 
04235     
04236 
04237 
04238 
04239 
04240     if ((server_response_code == HTTP_STATUS_INTERNAL_SERVER_ERROR ||
04241          server_response_code == HTTP_STATUS_GATEWAY_TIMEOUT ||
04242          server_response_code == HTTP_STATUS_BAD_GATEWAY ||
04243          server_response_code == HTTP_STATUS_SERVICE_UNAVAILABLE) &&
04244         s->cache_info.action == CACHE_DO_UPDATE &&
04245         s->txn_conf->negative_revalidating_enabled && is_stale_cache_response_returnable(s)) {
04246       DebugTxn("http_trans", "[hcoofsr] negative revalidating: revalidate stale object and serve from cache");
04247 
04248       s->cache_info.object_store.create();
04249       s->cache_info.object_store.request_set(&s->hdr_info.client_request);
04250       s->cache_info.object_store.response_set(s->cache_info.object_read->response_get());
04251       base_response = s->cache_info.object_store.response_get();
04252       time_t exp_time = s->txn_conf->negative_revalidating_lifetime + ink_cluster_time();
04253       base_response->set_expires(exp_time);
04254 
04255       SET_VIA_STRING(VIA_CACHE_FILL_ACTION, VIA_CACHE_UPDATED);
04256       HTTP_INCREMENT_TRANS_STAT(http_cache_updates_stat);
04257 
04258       
04259       
04260       
04261       
04262       base_response->unset_cooked_cc_need_revalidate_once();
04263 
04264       if (is_request_conditional(&s->hdr_info.client_request) &&
04265           HttpTransactCache::match_response_to_request_conditionals(&s->hdr_info.client_request,
04266                                                                     s->cache_info.object_read->response_get()) == HTTP_STATUS_NOT_MODIFIED) {
04267         s->next_action = SM_ACTION_INTERNAL_CACHE_UPDATE_HEADERS;
04268         client_response_code = HTTP_STATUS_NOT_MODIFIED;
04269       } else {
04270         if (s->method == HTTP_WKSIDX_HEAD) {
04271           s->cache_info.action = CACHE_DO_UPDATE;
04272           s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
04273         } else {
04274           s->cache_info.action = CACHE_DO_SERVE_AND_UPDATE;
04275           s->next_action = SM_ACTION_SERVE_FROM_CACHE;
04276         }
04277 
04278         client_response_code = s->cache_info.object_read->response_get()->status_get();
04279       }
04280 
04281       ink_assert(base_response->valid());
04282 
04283       if (client_response_code == HTTP_STATUS_NOT_MODIFIED) {
04284         ink_assert(GET_VIA_STRING(VIA_CLIENT_REQUEST) != VIA_CLIENT_SIMPLE);
04285         SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_IMS);
04286         SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_NOT_MODIFIED);
04287       } else {
04288         SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVED);
04289       }
04290 
04291       ink_assert(client_response_code != HTTP_STATUS_NONE);
04292 
04293       if (s->next_action == SM_ACTION_SERVE_FROM_CACHE && s->state_machine->do_transform_open()) {
04294         set_header_for_transform(s, base_response);
04295       } else {
04296         build_response(s, base_response, &s->hdr_info.client_response, s->client_info.http_version, client_response_code);
04297       }
04298 
04299       return;
04300     }
04301 
04302     s->next_action = SM_ACTION_SERVER_READ;
04303     client_response_code = server_response_code;
04304     base_response = &s->hdr_info.server_response;
04305 
04306     s->negative_caching = is_negative_caching_appropriate(s);
04307 
04308     
04309     
04310     
04311     
04312     if (s->api_server_response_no_store) {
04313       s->cache_info.action = CACHE_DO_NO_ACTION;
04314     } else if (s->api_server_response_ignore &&
04315                server_response_code == HTTP_STATUS_OK &&
04316                s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD) {
04317       s->api_server_response_ignore = false;
04318       ink_assert(s->cache_info.object_read);
04319       base_response = s->cache_info.object_read->response_get();
04320       s->cache_info.action = CACHE_DO_SERVE;
04321       DebugTxn("http_trans", "[hcoofsr] ignoring server response, "
04322             "cache action changed to: %s", HttpDebugNames::get_cache_action_name(s->cache_info.action));
04323       s->next_action = SM_ACTION_SERVE_FROM_CACHE;
04324       client_response_code = base_response->status_get();
04325     } else if (s->cache_info.action == CACHE_DO_UPDATE) {
04326       if (s->www_auth_content == CACHE_AUTH_FRESH) {
04327         s->cache_info.action = CACHE_DO_NO_ACTION;
04328       } else if (s->www_auth_content == CACHE_AUTH_STALE && server_response_code == HTTP_STATUS_UNAUTHORIZED) {
04329         s->cache_info.action = CACHE_DO_NO_ACTION;
04330       } else if (!cacheable) {
04331         s->cache_info.action = CACHE_DO_DELETE;
04332       } else if (s->method == HTTP_WKSIDX_HEAD) {
04333         s->cache_info.action = CACHE_DO_DELETE;
04334       } else {
04335         ink_assert(s->cache_info.object_read != 0);
04336         s->cache_info.action = CACHE_DO_REPLACE;
04337       }
04338 
04339     } else if (s->cache_info.action == CACHE_DO_WRITE) {
04340       if (!cacheable && !s->negative_caching) {
04341         s->cache_info.action = CACHE_DO_NO_ACTION;
04342       } else if (s->method == HTTP_WKSIDX_HEAD) {
04343         s->cache_info.action = CACHE_DO_NO_ACTION;
04344       } else {
04345         s->cache_info.action = CACHE_DO_WRITE;
04346       }
04347 
04348     } else if (s->cache_info.action == CACHE_DO_DELETE) {
04349       
04350 
04351     } else {
04352       ink_assert(!("cache action inconsistent with current state"));
04353     }
04354     
04355     
04356     
04357 
04358     
04359     
04360     
04361     
04362     
04363     
04364     
04365     if (s->cache_info.action == CACHE_DO_WRITE ||
04366         s->cache_info.action == CACHE_DO_NO_ACTION || s->cache_info.action == CACHE_DO_REPLACE) {
04367       if (s->negative_caching) {
04368         HTTPHdr *resp;
04369         s->cache_info.object_store.create();
04370         s->cache_info.object_store.request_set(&s->hdr_info.client_request);
04371         s->cache_info.object_store.response_set(&s->hdr_info.server_response);
04372         resp = s->cache_info.object_store.response_get();
04373         if (!resp->presence(MIME_PRESENCE_EXPIRES)) {
04374           time_t exp_time = s->txn_conf->negative_caching_lifetime + ink_cluster_time();
04375 
04376           resp->set_expires(exp_time);
04377         }
04378       } else if (is_request_conditional(&s->hdr_info.client_request) && server_response_code == HTTP_STATUS_OK) {
04379         DebugTxn("http_trans", "[hcoofsr] conditional request, 200 " "response, send back 304 if possible");
04380         client_response_code =
04381           HttpTransactCache::match_response_to_request_conditionals(&s->hdr_info.client_request,
04382                                                                     &s->hdr_info.server_response);
04383 
04384         if ((client_response_code == HTTP_STATUS_NOT_MODIFIED) || (client_response_code == HTTP_STATUS_PRECONDITION_FAILED)) {
04385           switch (s->cache_info.action) {
04386           case CACHE_DO_WRITE:
04387           case CACHE_DO_REPLACE:
04388             s->next_action = SM_ACTION_INTERNAL_CACHE_WRITE;
04389             break;
04390           case CACHE_DO_DELETE:
04391             s->next_action = SM_ACTION_INTERNAL_CACHE_DELETE;
04392             break;
04393           default:
04394             s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
04395             break;
04396           }
04397         } else {
04398           SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVER_REVALIDATED);
04399         }
04400       }
04401     } else if (s->negative_caching) {
04402       s->negative_caching = false;
04403     }
04404 
04405     break;
04406   }
04407 
04408   
04409 
04410   switch (s->cache_info.action) {
04411   case CACHE_DO_SERVE_AND_DELETE:
04412     
04413   case CACHE_DO_DELETE:
04414     DebugTxn("http_trans", "[hcoofsr] delete cached copy");
04415     SET_VIA_STRING(VIA_CACHE_FILL_ACTION, VIA_CACHE_DELETED);
04416     HTTP_INCREMENT_TRANS_STAT(http_cache_deletes_stat);
04417     break;
04418   case CACHE_DO_WRITE:
04419     DebugTxn("http_trans", "[hcoofsr] cache write");
04420     SET_VIA_STRING(VIA_CACHE_FILL_ACTION, VIA_CACHE_WRITTEN);
04421     HTTP_INCREMENT_TRANS_STAT(http_cache_writes_stat);
04422     break;
04423   case CACHE_DO_SERVE_AND_UPDATE:
04424     
04425   case CACHE_DO_UPDATE:
04426     
04427   case CACHE_DO_REPLACE:
04428     DebugTxn("http_trans", "[hcoofsr] cache update/replace");
04429     SET_VIA_STRING(VIA_CACHE_FILL_ACTION, VIA_CACHE_UPDATED);
04430     HTTP_INCREMENT_TRANS_STAT(http_cache_updates_stat);
04431     break;
04432   default:
04433     break;
04434   }
04435 
04436   if ((client_response_code == HTTP_STATUS_NOT_MODIFIED) && (s->cache_info.action != CACHE_DO_NO_ACTION)) {
04437     
04438 
04439     DebugTxn("http_trans", "[hcoofsr] Client request was conditional");
04440     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_IMS);
04441     SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_NOT_MODIFIED);
04442   } else {
04443     SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVED);
04444   }
04445 
04446   ink_assert(client_response_code != HTTP_STATUS_NONE);
04447 
04448   
04449   
04450 
04451   
04452   if ((s->cache_info.action == CACHE_DO_UPDATE) || (s->cache_info.action == CACHE_DO_SERVE_AND_UPDATE)) {
04453     DebugTxn("http_trans", "[hcoofsr] merge and update cached copy");
04454     merge_and_update_headers_for_cache_update(s);
04455     base_response = s->cache_info.object_store.response_get();
04456     
04457     
04458     
04459     base_response->unset_cooked_cc_need_revalidate_once();
04460     
04461     
04462     delete_warning_value(base_response, HTTP_WARNING_CODE_REVALIDATION_FAILED);
04463   }
04464   ink_assert(base_response->valid());
04465 
04466   if ((s->cache_info.action == CACHE_DO_WRITE) || (s->cache_info.action == CACHE_DO_REPLACE)) {
04467     set_headers_for_cache_write(s, &s->cache_info.object_store, &s->hdr_info.server_request, &s->hdr_info.server_response);
04468   }
04469   
04470   if ((client_response_code == HTTP_STATUS_NOT_MODIFIED) || (client_response_code == HTTP_STATUS_PRECONDITION_FAILED)) {
04471     
04472     
04473     
04474     
04475     build_response(s, base_response, &s->hdr_info.client_response, s->client_info.http_version, client_response_code);
04476 
04477     
04478     
04479     MIMEField *resp_via = s->hdr_info.server_response.field_find(MIME_FIELD_VIA, MIME_LEN_VIA);
04480     if (resp_via) {
04481       MIMEField *our_via;
04482       our_via = s->hdr_info.client_response.field_find(MIME_FIELD_VIA, MIME_LEN_VIA);
04483       if (our_via == NULL) {
04484         our_via = s->hdr_info.client_response.field_create(MIME_FIELD_VIA, MIME_LEN_VIA);
04485         s->hdr_info.client_response.field_attach(our_via);
04486       }
04487       
04488       while (resp_via) {
04489         int clen;
04490         const char *cfield = resp_via->value_get(&clen);
04491         s->hdr_info.client_response.field_value_append(our_via, cfield, clen, true);
04492         resp_via = resp_via->m_next_dup;
04493       }
04494     }
04495     
04496     if (warn_text) {
04497       HttpTransactHeaders::insert_warning_header(s->http_config_param, &s->hdr_info.client_response,
04498                                                  HTTP_WARNING_CODE_MISC_WARNING, warn_text, strlen(warn_text));
04499     }
04500 
04501     if (!s->cop_test_page)
04502       DUMP_HEADER("http_hdrs", &s->hdr_info.client_response, s->state_machine_id, "Proxy's Response (Client Conditionals)");
04503     return;
04504   }
04505   
04506   else {
04507     if (((s->next_action == SM_ACTION_SERVE_FROM_CACHE) ||
04508          (s->next_action == SM_ACTION_SERVER_READ)) && s->state_machine->do_transform_open()) {
04509       set_header_for_transform(s, base_response);
04510     } else {
04511       build_response(s, base_response, &s->hdr_info.client_response, s->client_info.http_version, client_response_code);
04512     }
04513   }
04514 
04515   return;
04516 }
04517 
04518 
04519 
04520 
04521 
04522 
04523 
04524 
04525 
04526 
04527 
04528 
04529 
04530 void
04531 HttpTransact::handle_no_cache_operation_on_forward_server_response(State* s)
04532 {
04533   DebugTxn("http_trans", "[handle_no_cache_operation_on_forward_server_response] (hncoofsr)");
04534   DebugTxn("http_seq", "[handle_no_cache_operation_on_forward_server_response]");
04535 
04536   bool keep_alive = s->current.server->keep_alive == HTTP_KEEPALIVE;
04537   const char *warn_text = NULL;
04538 
04539   switch (s->hdr_info.server_response.status_get()) {
04540   case HTTP_STATUS_OK:
04541     DebugTxn("http_trans", "[hncoofsr] server sent back 200");
04542     SET_VIA_STRING(VIA_SERVER_RESULT, VIA_SERVER_SERVED);
04543     SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVED);
04544     if (s->method == HTTP_WKSIDX_CONNECT) {
04545       DebugTxn("http_trans", "[hncoofsr] next action is SSL_TUNNEL");
04546       s->next_action = SM_ACTION_SSL_TUNNEL;
04547     } else {
04548       DebugTxn("http_trans", "[hncoofsr] next action will be OS_READ_CACHE_NOOP");
04549 
04550       ink_assert(s->cache_info.action == CACHE_DO_NO_ACTION);
04551       s->next_action = SM_ACTION_SERVER_READ;
04552     }
04553     if (s->state_machine->redirect_url == NULL) {
04554       s->state_machine->enable_redirection = false;
04555     }
04556     break;
04557   case HTTP_STATUS_NOT_MODIFIED:
04558     DebugTxn("http_trans", "[hncoofsr] server sent back 304. IMS from client?");
04559     SET_VIA_STRING(VIA_SERVER_RESULT, VIA_SERVER_NOT_MODIFIED);
04560     SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_NOT_MODIFIED);
04561 
04562     if (!is_request_conditional(&s->hdr_info.client_request)) {
04563       
04564       
04565       
04566 
04567       
04568       warn_text = "Proxy received unexpected 304 response; content may be stale";
04569     }
04570 
04571     ink_assert(s->cache_info.action == CACHE_DO_NO_ACTION);
04572     s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP;
04573     break;
04574   case HTTP_STATUS_HTTPVER_NOT_SUPPORTED:
04575     s->next_action = how_to_open_connection(s);
04576 
04577     
04578     if (!HttpTransactHeaders::downgrade_request(&keep_alive, &s->hdr_info.server_request)) {
04579       s->already_downgraded = true;
04580       build_error_response(s, HTTP_STATUS_HTTPVER_NOT_SUPPORTED, "HTTP Version Not Supported", "response#bad_version",
04581                            NULL);
04582       s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
04583     } else {
04584       s->already_downgraded = true;
04585       s->next_action = how_to_open_connection(s);
04586     }
04587     return;
04588   case HTTP_STATUS_PARTIAL_CONTENT:
04589     
04590     ink_assert(s->cache_info.action == CACHE_DO_NO_ACTION);
04591     s->next_action = SM_ACTION_SERVER_READ;
04592     break;
04593   default:
04594     DebugTxn("http_trans", "[hncoofsr] server sent back something other than 100,304,200");
04595     
04596 
04597     ink_assert(s->cache_info.action == CACHE_DO_NO_ACTION);
04598     s->next_action = SM_ACTION_SERVER_READ;
04599     break;
04600   }
04601 
04602   HTTPHdr *to_warn;
04603   if (s->next_action == SM_ACTION_SERVER_READ && s->state_machine->do_transform_open()) {
04604     set_header_for_transform(s, &s->hdr_info.server_response);
04605     to_warn = &s->hdr_info.transform_response;
04606   } else {
04607     build_response(s, &s->hdr_info.server_response, &s->hdr_info.client_response, s->client_info.http_version);
04608     to_warn = &s->hdr_info.server_response;
04609   }
04610 
04611   if (warn_text) {
04612     HttpTransactHeaders::insert_warning_header(s->http_config_param, to_warn, HTTP_WARNING_CODE_MISC_WARNING,
04613                                                warn_text, strlen(warn_text));
04614   }
04615 
04616   return;
04617 }
04618 
04619 
04620 void
04621 HttpTransact::merge_and_update_headers_for_cache_update(State* s)
04622 {
04623   URL *s_url = NULL;
04624   
04625   
04626 
04627   if (!s->cache_info.object_store.valid()) {
04628     s->cache_info.object_store.create();
04629   }
04630 
04631   s->cache_info.object_store.request_set(&s->hdr_info.server_request);
04632 
04633   if (s->redirect_info.redirect_in_process)
04634     s_url = &s->redirect_info.original_url;
04635   else
04636     s_url = &s->cache_info.original_url;
04637   ink_assert(s_url != NULL);
04638 
04639   s->cache_info.object_store.request_get()->url_set(s_url->valid()? s_url : s->hdr_info.client_request.url_get());
04640 
04641   if (s->cache_info.object_store.request_get()->method_get_wksidx() == HTTP_WKSIDX_HEAD) {
04642     s->cache_info.object_store.request_get()->method_set(HTTP_METHOD_GET, HTTP_LEN_GET);
04643   }
04644 
04645   if (s->api_modifiable_cached_resp) {
04646     ink_assert(s->cache_info.object_store.response_get() != NULL && s->cache_info.object_store.response_get()->valid());
04647     s->api_modifiable_cached_resp = false;
04648   } else {
04649     s->cache_info.object_store.response_set(s->cache_info.object_read->response_get());
04650   }
04651 
04652   merge_response_header_with_cached_header(s->cache_info.object_store.response_get(), &s->hdr_info.server_response);
04653 
04654   
04655   
04656   if (s->hdr_info.server_response.status_get() == HTTP_STATUS_NOT_MODIFIED) {
04657     
04658     
04659     
04660     time_t date_value = s->hdr_info.server_response.get_date();
04661     HTTPHdr *cached_hdr = s->cache_info.object_store.response_get();
04662 
04663     if (date_value <= 0) {
04664       cached_hdr->set_date(s->request_sent_time);
04665       date_value = s->request_sent_time;
04666     }
04667     
04668     
04669     
04670     date_value = max(s->current.now - date_value, (ink_time_t)0);
04671     if (s->hdr_info.server_response.presence(MIME_PRESENCE_AGE)) {
04672       time_t new_age = s->hdr_info.server_response.get_age();
04673 
04674       if (new_age >= 0)
04675         cached_hdr->set_age(date_value + new_age);
04676       else
04677         cached_hdr->set_age(-1); 
04678     }
04679     delete_warning_value(cached_hdr, HTTP_WARNING_CODE_REVALIDATION_FAILED);
04680   }
04681 
04682   s->cache_info.object_store.request_get()->field_delete(MIME_FIELD_VIA, MIME_LEN_VIA);
04683 
04684 }
04685 
04686 void
04687 HttpTransact::handle_transform_cache_write(State* s)
04688 {
04689   ink_assert(s->cache_info.transform_action == CACHE_PREPARE_TO_WRITE);
04690 
04691   switch (s->cache_info.write_lock_state) {
04692   case CACHE_WL_SUCCESS:
04693     
04694     s->cache_info.transform_action = CACHE_DO_WRITE;
04695     break;
04696   case CACHE_WL_FAIL:
04697     
04698     s->cache_info.transform_action = CACHE_DO_NO_ACTION;
04699     s->cache_info.transform_write_status = CACHE_WRITE_LOCK_MISS;
04700     break;
04701   default:
04702     ink_release_assert(0);
04703   }
04704 
04705   TRANSACT_RETURN(SM_ACTION_TRANSFORM_READ, NULL);
04706 }
04707 
04708 void
04709 HttpTransact::handle_transform_ready(State* s)
04710 {
04711   ink_assert(s->hdr_info.transform_response.valid() == true);
04712 
04713   s->pre_transform_source = s->source;
04714   s->source = SOURCE_TRANSFORM;
04715 
04716   if (!s->cop_test_page)
04717     DUMP_HEADER("http_hdrs", &s->hdr_info.transform_response, s->state_machine_id, "Header From Transform");
04718 
04719   build_response(s, &s->hdr_info.transform_response, &s->hdr_info.client_response, s->client_info.http_version);
04720 
04721   if (s->cache_info.action != CACHE_DO_NO_ACTION &&
04722       s->cache_info.action != CACHE_DO_DELETE && s->api_info.cache_transformed && !s->range_setup) {
04723     HTTPHdr *transform_store_request = 0;
04724     switch (s->pre_transform_source) {
04725     case SOURCE_CACHE:
04726       
04727       
04728       
04729       transform_store_request = &s->hdr_info.client_request;
04730       break;
04731     case SOURCE_HTTP_ORIGIN_SERVER:
04732       transform_store_request = &s->hdr_info.server_request;
04733       break;
04734     default:
04735       ink_release_assert(0);
04736     }
04737     ink_assert(transform_store_request->valid() == true);
04738     set_headers_for_cache_write(s, &s->cache_info.transform_store, transform_store_request, &s->hdr_info.transform_response);
04739 
04740     
04741     if (is_action_tag_set("http_nullt")) {
04742       s->cache_info.transform_store.request_get()->value_set("InkXform", 8, "nullt", 5);
04743       s->cache_info.transform_store.response_get()->value_set("InkXform", 8, "nullt", 5);
04744     }
04745 
04746     s->cache_info.transform_action = CACHE_PREPARE_TO_WRITE;
04747     TRANSACT_RETURN(SM_ACTION_CACHE_ISSUE_WRITE_TRANSFORM, handle_transform_cache_write);
04748   } else {
04749     s->cache_info.transform_action = CACHE_DO_NO_ACTION;
04750     TRANSACT_RETURN(SM_ACTION_TRANSFORM_READ, NULL);
04751   }
04752 }
04753 
04754 void
04755 HttpTransact::set_header_for_transform(State* s, HTTPHdr* base_header)
04756 {
04757   s->hdr_info.transform_response.create(HTTP_TYPE_RESPONSE);
04758   s->hdr_info.transform_response.copy(base_header);
04759 
04760   
04761   
04762   
04763   s->hdr_info.transform_response.field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
04764 
04765   if (!s->cop_test_page)
04766     DUMP_HEADER("http_hdrs", &s->hdr_info.transform_response, s->state_machine_id, "Header To Transform");
04767 }
04768 
04769 void
04770 HttpTransact::set_headers_for_cache_write(State* s, HTTPInfo* cache_info, HTTPHdr* request, HTTPHdr* response)
04771 {
04772   URL *temp_url;
04773   ink_assert(request->type_get() == HTTP_TYPE_REQUEST);
04774   ink_assert(response->type_get() == HTTP_TYPE_RESPONSE);
04775 
04776   if (!cache_info->valid()) {
04777     cache_info->create();
04778   }
04779 
04780   
04781   
04782   
04783   
04784   
04785   
04786   
04787 
04788   
04789   
04790   if (s->redirect_info.redirect_in_process) {
04791     temp_url = &s->redirect_info.original_url;
04792     ink_assert(temp_url->valid());
04793     request->url_set(temp_url);
04794   } else if ((temp_url = &(s->cache_info.original_url))->valid()) {
04795     request->url_set(temp_url);
04796   } else if (request != &s->hdr_info.client_request) {
04797     request->url_set(s->hdr_info.client_request.url_get());
04798   }
04799   cache_info->request_set(request);
04800   
04801 
04802 
04803 
04804 
04805 
04806   if (!s->negative_caching || !cache_info->response_get()->valid())
04807     cache_info->response_set(response);
04808 
04809   if (s->api_server_request_body_set)
04810     cache_info->request_get()->method_set(HTTP_METHOD_GET, HTTP_LEN_GET);
04811 
04812   
04813   
04814   cache_info->response_get()->field_delete(MIME_FIELD_SET_COOKIE, MIME_LEN_SET_COOKIE);
04815   cache_info->request_get()->field_delete(MIME_FIELD_VIA, MIME_LEN_VIA);
04816   
04817   cache_info->request_get()->field_delete(MIME_FIELD_RANGE, MIME_LEN_RANGE);
04818 
04819   
04820   
04821   if (s->txn_conf->cache_ignore_auth) {
04822     cache_info->response_get()->field_delete(MIME_FIELD_WWW_AUTHENTICATE, MIME_LEN_WWW_AUTHENTICATE);
04823   }
04824 
04825   
04826     
04827     
04828    
04829   
04830   if (!s->cop_test_page)
04831     DUMP_HEADER("http_hdrs", cache_info->request_get(), s->state_machine_id, "Cached Request Hdr");
04832 }
04833 
04834 void
04835 HttpTransact::merge_response_header_with_cached_header(HTTPHdr* cached_header, HTTPHdr* response_header)
04836 {
04837   MIMEField *field;
04838   MIMEField *new_field;
04839   MIMEFieldIter fiter;
04840   const char *name;
04841   bool dups_seen = false;
04842 
04843 
04844   field = response_header->iter_get_first(&fiter);
04845 
04846   for (; field != NULL; field = response_header->iter_get_next(&fiter)) {
04847     int name_len;
04848     name = field->name_get(&name_len);
04849 
04850 
04851     
04852 
04853     if (HttpTransactHeaders::is_this_a_hop_by_hop_header(name)) {
04854       continue;
04855     }
04856 
04857     
04858 
04859     if (name == MIME_FIELD_CONTENT_LENGTH) {
04860       continue;
04861     }
04862 
04863     
04864 
04865     if (name == MIME_FIELD_SET_COOKIE) {
04866       continue;
04867     }
04868 
04869     
04870     
04871     
04872 
04873     if (name == MIME_FIELD_CONTENT_TYPE) {
04874       continue;
04875     }
04876 
04877     
04878     
04879     
04880 
04881     if (name == MIME_FIELD_WARNING) {
04882       continue;
04883     }
04884     
04885 
04886     
04887     
04888     
04889     
04890     
04891     
04892     
04893     
04894     
04895     
04896     
04897     
04898     if (field->m_next_dup) {
04899       if (dups_seen == false) {
04900         MIMEField *dfield;
04901         
04902         
04903         
04904         MIMEFieldIter fiter2 = fiter;
04905         const char *dname = name;
04906         int dlen = name_len;
04907 
04908         while (dname) {
04909           cached_header->field_delete(dname, dlen);
04910           dfield = response_header->iter_get_next(&fiter2);
04911           if (dfield) {
04912             dname = dfield->name_get(&dlen);
04913           } else {
04914             dname = NULL;
04915           }
04916         }
04917         dups_seen = true;
04918       }
04919     }
04920 
04921     int value_len;
04922     const char *value = field->value_get(&value_len);
04923 
04924     if (dups_seen == false) {
04925       cached_header->value_set(name, name_len, value, value_len);
04926     } else {
04927       new_field = cached_header->field_create(name, name_len);
04928       cached_header->field_attach(new_field);
04929       cached_header->field_value_set(new_field, value, value_len);
04930     }
04931   }
04932 
04933   merge_warning_header(cached_header, response_header);
04934 
04935   Debug("http_hdr_space", "Merged response header with %d dead bytes", cached_header->m_heap->m_lost_string_space);
04936 }
04937 
04938 
04939 void
04940 HttpTransact::merge_warning_header(HTTPHdr* cached_header, HTTPHdr* response_header)
04941 {
04942   
04943   
04944   
04945   
04946   
04947   
04948   
04949   
04950   
04951   
04952   
04953   
04954   
04955   
04956   
04957   MIMEField *c_warn = cached_header->field_find(MIME_FIELD_WARNING, MIME_LEN_WARNING);
04958   MIMEField *r_warn = response_header->field_find(MIME_FIELD_WARNING, MIME_LEN_WARNING);
04959   MIMEField *new_cwarn = NULL;
04960   int move_warn_len;
04961   const char *move_warn;
04962 
04963   
04964   
04965   if (c_warn) {
04966     HdrCsvIter csv;
04967 
04968     move_warn = csv.get_first(c_warn, &move_warn_len);
04969     while (move_warn) {
04970       int code = ink_atoi(move_warn, move_warn_len);
04971       if (code<100 || code> 199) {
04972         bool first_move;
04973         if (!new_cwarn) {
04974           new_cwarn = cached_header->field_create();
04975           first_move = true;
04976         } else {
04977           first_move = false;
04978         }
04979         cached_header->field_value_append(new_cwarn, move_warn, move_warn_len, !first_move);
04980       }
04981 
04982       move_warn = csv.get_next(&move_warn_len);
04983     }
04984 
04985     
04986     cached_header->field_delete(MIME_FIELD_WARNING, MIME_LEN_WARNING);
04987 
04988     
04989     if (new_cwarn) {
04990       new_cwarn->name_set(cached_header->m_heap, cached_header->m_mime, MIME_FIELD_WARNING, MIME_LEN_WARNING);
04991       cached_header->field_attach(new_cwarn);
04992     }
04993   }
04994   
04995   
04996   while (r_warn) {
04997     move_warn = r_warn->value_get(&move_warn_len);
04998 
04999     if (new_cwarn) {
05000       cached_header->field_value_append(new_cwarn, move_warn, move_warn_len, true);
05001     } else {
05002       new_cwarn = cached_header->field_create(MIME_FIELD_WARNING, MIME_LEN_WARNING);
05003       cached_header->field_attach(new_cwarn);
05004       cached_header->field_value_set(new_cwarn, move_warn, move_warn_len);
05005     }
05006 
05007     r_warn = r_warn->m_next_dup;
05008   }
05009 }
05010 
05011 void
05012 HttpTransact::get_ka_info_from_host_db(State *s, ConnectionAttributes *server_info,
05013                                        ConnectionAttributes * , HostDBInfo *host_db_info)
05014 {
05015 
05016   
05017   
05018   
05019   
05020 
05021 
05022   bool force_http11 = false;
05023   bool http11_if_hostdb = false;
05024 
05025   switch (s->txn_conf->send_http11_requests) {
05026   case HttpConfigParams::SEND_HTTP11_NEVER:
05027     
05028     
05029     break;
05030   case HttpConfigParams::SEND_HTTP11_ALWAYS:
05031     force_http11 = true;
05032     break;
05033   case HttpConfigParams::SEND_HTTP11_UPGRADE_HOSTDB:
05034     http11_if_hostdb = true;
05035     break;
05036   default:
05037     ink_assert(0);
05038     
05039   case HttpConfigParams::SEND_HTTP11_IF_REQUEST_11_AND_HOSTDB:
05040     if (s->hdr_info.client_request.version_get() == HTTPVersion(1, 1)) {
05041       http11_if_hostdb = true;
05042     }
05043     break;
05044   }
05045 
05046   if (force_http11 == true ||
05047       (http11_if_hostdb == true &&
05048        host_db_info->app.http_data.http_version == HostDBApplicationInfo::HTTP_VERSION_11)) {
05049     server_info->http_version.set(1, 1);
05050     server_info->keep_alive = HTTP_KEEPALIVE;
05051   } else if (host_db_info->app.http_data.http_version == HostDBApplicationInfo::HTTP_VERSION_10) {
05052     server_info->http_version.set(1, 0);
05053     server_info->keep_alive = HTTP_KEEPALIVE;
05054   } else if (host_db_info->app.http_data.http_version == HostDBApplicationInfo::HTTP_VERSION_09) {
05055     server_info->http_version.set(0, 9);
05056     server_info->keep_alive = HTTP_NO_KEEPALIVE;
05057   } else {
05058 
05059     
05060 
05061     server_info->http_version.set(1, 0);
05062     server_info->keep_alive = HTTP_KEEPALIVE;
05063     host_db_info->app.http_data.http_version = HostDBApplicationInfo::HTTP_VERSION_10;
05064   }
05065 
05066 
05067   
05068 
05069   if (!s->txn_conf->keep_alive_enabled_out) {
05070     server_info->keep_alive = HTTP_NO_KEEPALIVE;
05071   }
05072 
05073   return;
05074 }
05075 
05076 void
05077 HttpTransact::add_client_ip_to_outgoing_request(State* s, HTTPHdr* request)
05078 {
05079   char ip_string[INET6_ADDRSTRLEN + 1] = {'\0'};
05080   size_t ip_string_size = 0;
05081 
05082   if (!ats_is_ip(&s->client_info.addr.sa))
05083     return;
05084 
05085   
05086   if (ats_ip_ntop(&s->client_info.addr.sa, ip_string, sizeof(ip_string)) != NULL) {
05087     ip_string_size += strlen(ip_string);
05088   } else {
05089     
05090     ip_string_size = 0;
05091     ip_string[0] = 0;
05092   }
05093 
05094 
05095   
05096 
05097   if ((s->txn_conf->anonymize_insert_client_ip) && (!s->txn_conf->anonymize_remove_client_ip)) {
05098     bool client_ip_set = request->presence(MIME_PRESENCE_CLIENT_IP);
05099     DebugTxn("http_trans", "client_ip_set = %d", client_ip_set);
05100 
05101     if (!client_ip_set && ip_string_size > 0) {
05102       request->value_set(MIME_FIELD_CLIENT_IP, MIME_LEN_CLIENT_IP, ip_string, ip_string_size);
05103       DebugTxn("http_trans", "inserted request header 'Client-ip: %s'", ip_string);
05104     }
05105   }
05106 
05107   if (s->txn_conf->insert_squid_x_forwarded_for) {
05108     if (ip_string_size > 0) {
05109       MIMEField *x_for;
05110 
05111       if ((x_for = request->field_find(MIME_FIELD_X_FORWARDED_FOR, MIME_LEN_X_FORWARDED_FOR)) != 0) {
05112         
05113         
05114         
05115         
05116         
05117         
05118         
05119         request->field_value_append(x_for, ip_string, ip_string_size, true);  
05120       } else {
05121         request->value_set(MIME_FIELD_X_FORWARDED_FOR, MIME_LEN_X_FORWARDED_FOR, ip_string, ip_string_size);
05122       }
05123       DebugTxn("http_trans", "[add_client_ip_to_outgoing_request] Appended connecting client's "
05124             "(%s) to the X-Forwards header", ip_string);
05125     }
05126   }
05127 }
05128 
05129 
05130 
05131 
05132 
05133 
05134 
05135 
05136 
05137 
05138 
05139 
05140 HttpTransact::RequestError_t HttpTransact::check_request_validity(State* s, HTTPHdr* incoming_hdr)
05141 {
05142   if (incoming_hdr == 0) {
05143     return NON_EXISTANT_REQUEST_HEADER;
05144   }
05145 
05146   if (!(HttpTransactHeaders::is_request_proxy_authorized(incoming_hdr))) {
05147     return FAILED_PROXY_AUTHORIZATION;
05148   }
05149 
05150   URL *incoming_url = incoming_hdr->url_get();
05151   int hostname_len;
05152   const char *hostname = incoming_hdr->host_get(&hostname_len);
05153 
05154   if (hostname == NULL) {
05155     return MISSING_HOST_FIELD;
05156   }
05157 
05158   if (hostname_len >= MAXDNAME || hostname_len <= 0 || memchr(hostname, '\0', hostname_len)) {
05159     return BAD_HTTP_HEADER_SYNTAX;
05160   }
05161 
05162   int scheme = incoming_url->scheme_get_wksidx();
05163   int method = incoming_hdr->method_get_wksidx();
05164 
05165   
05166   if (incoming_hdr->presence(MIME_PRESENCE_TRANSFER_ENCODING)) {
05167     MIMEField *field = incoming_hdr->field_find(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
05168     HdrCsvIter enc_val_iter;
05169     int enc_val_len;
05170     const char *enc_value = enc_val_iter.get_first(field, &enc_val_len);
05171 
05172     while (enc_value) {
05173       const char *wks_value = hdrtoken_string_to_wks(enc_value, enc_val_len);
05174       if (wks_value == HTTP_VALUE_CHUNKED) {
05175           s->client_info.transfer_encoding = CHUNKED_ENCODING;
05176         break;
05177       }
05178         enc_value = enc_val_iter.get_next(&enc_val_len);
05179     }
05180   }
05181 
05182 
05183   
05184   
05185   
05186   
05187 
05188   if (method != HTTP_WKSIDX_TRACE) {
05189     int64_t length = incoming_hdr->get_content_length();
05190     s->hdr_info.request_content_length = (length >= 0) ? length : HTTP_UNDEFINED_CL;    
05191 
05192     DebugTxn("http_trans", "[init_stat_vars_from_req] set req cont length to %" PRId64,
05193           s->hdr_info.request_content_length);
05194 
05195   } else {
05196     s->hdr_info.request_content_length = 0;
05197   }
05198 
05199   if (!((scheme == URL_WKSIDX_HTTP) && (method == HTTP_WKSIDX_GET))) {
05200     if (scheme != URL_WKSIDX_HTTP && scheme != URL_WKSIDX_HTTPS &&
05201         method != HTTP_WKSIDX_CONNECT &&
05202         ((scheme == URL_WKSIDX_WS || scheme == URL_WKSIDX_WSS) && !s->is_websocket)) {
05203       if (scheme < 0) {
05204         return NO_REQUEST_SCHEME;
05205       } else {
05206         return SCHEME_NOT_SUPPORTED;
05207       }
05208     }
05209 
05210     if (!HttpTransactHeaders::is_this_method_supported(scheme, method)) {
05211       return METHOD_NOT_SUPPORTED;
05212     }
05213     if ((method == HTTP_WKSIDX_CONNECT) && !s->transparent_passthrough && (!is_port_in_range(incoming_hdr->url_get()->port_get(), s->http_config_param->connect_ports))) {
05214       return BAD_CONNECT_PORT;
05215     }
05216 
05217     
05218     if ((scheme == URL_WKSIDX_HTTP || scheme == URL_WKSIDX_HTTPS) &&
05219         (method == HTTP_WKSIDX_POST || method == HTTP_WKSIDX_PUSH || method == HTTP_WKSIDX_PUT) &&
05220         s->client_info.transfer_encoding != CHUNKED_ENCODING) {
05221       if ((s->txn_conf->post_check_content_length_enabled) &&
05222           !incoming_hdr->presence(MIME_PRESENCE_CONTENT_LENGTH)) {
05223         return NO_POST_CONTENT_LENGTH;
05224       }
05225       if (HTTP_UNDEFINED_CL == s->hdr_info.request_content_length) {
05226         return INVALID_POST_CONTENT_LENGTH;
05227       }
05228     }
05229   }
05230   
05231   if (!incoming_hdr->presence(MIME_PRESENCE_HOST) && incoming_hdr->version_get() != HTTPVersion(0, 9)) {
05232     
05233     
05234     HTTP_INCREMENT_TRANS_STAT(http_missing_host_hdr_stat);
05235   }
05236   
05237   
05238   
05239 
05240   if (incoming_hdr->presence(MIME_PRESENCE_TE)) {
05241     MIMEField *te_field = incoming_hdr->field_find(MIME_FIELD_TE, MIME_LEN_TE);
05242     HTTPValTE *te_val;
05243 
05244     if (te_field) {
05245       HdrCsvIter csv_iter;
05246       int te_raw_len;
05247       const char *te_raw = csv_iter.get_first(te_field, &te_raw_len);
05248 
05249       while (te_raw) {
05250         te_val = http_parse_te(te_raw, te_raw_len, &s->arena);
05251         if (te_val->encoding == HTTP_VALUE_IDENTITY) {
05252           if (te_val->qvalue <= 0.0) {
05253             s->arena.free(te_val, sizeof(HTTPValTE));
05254             return UNACCEPTABLE_TE_REQUIRED;
05255           }
05256         }
05257         s->arena.free(te_val, sizeof(HTTPValTE));
05258         te_raw = csv_iter.get_next(&te_raw_len);
05259       }
05260     }
05261   }
05262 
05263   return NO_REQUEST_HEADER_ERROR;
05264 }
05265 
05266 HttpTransact::ResponseError_t HttpTransact::check_response_validity(State* s, HTTPHdr* incoming_hdr)
05267 {
05268   ink_assert(s->next_hop_scheme == URL_WKSIDX_HTTP || s->next_hop_scheme == URL_WKSIDX_HTTPS);
05269 
05270   if (incoming_hdr == 0) {
05271     return NON_EXISTANT_RESPONSE_HEADER;
05272   }
05273 
05274   if (incoming_hdr->type_get() != HTTP_TYPE_RESPONSE) {
05275     return NOT_A_RESPONSE_HEADER;
05276   }
05277   
05278   
05279   if (did_forward_server_send_0_9_response(s) == true) {
05280     return NO_RESPONSE_HEADER_ERROR;
05281   }
05282 
05283   HTTPStatus incoming_status = incoming_hdr->status_get();
05284   if (!incoming_status) {
05285     return MISSING_STATUS_CODE;
05286   }
05287 
05288   if (incoming_status == HTTP_STATUS_INTERNAL_SERVER_ERROR) {
05289     return STATUS_CODE_SERVER_ERROR;
05290   }
05291 
05292   if (!incoming_hdr->presence(MIME_PRESENCE_DATE)) {
05293     incoming_hdr->set_date(s->current.now);
05294   }
05295 
05296 
05297 
05298 
05299 #ifdef REALLY_NEED_TO_CHECK_DATE_VALIDITY
05300 
05301   if (incoming_hdr->presence(MIME_PRESENCE_DATE)) {
05302     time_t date_value = incoming_hdr->get_date();
05303     if (date_value <= 0) {
05304 
05305 
05306 
05307 
05308 
05309 
05310 
05311 
05312 
05313       DebugTxn("http_trans", "[check_response_validity] Bogus date in response");
05314       return BOGUS_OR_NO_DATE_IN_RESPONSE;
05315     }
05316   } else {
05317     DebugTxn("http_trans", "[check_response_validity] No date in response");
05318     return BOGUS_OR_NO_DATE_IN_RESPONSE;
05319   }
05320 #endif
05321 
05322   return NO_RESPONSE_HEADER_ERROR;
05323 }
05324 
05325 bool
05326 HttpTransact::did_forward_server_send_0_9_response(State* s)
05327 {
05328   if (s->hdr_info.server_response.version_get() == HTTPVersion(0, 9)) {
05329     s->current.server->http_version.set(0, 9);
05330     return true;
05331   }
05332   return false;
05333 }
05334 
05335 bool
05336 HttpTransact::handle_internal_request(State* , HTTPHdr* incoming_hdr)
05337 {
05338   URL *url;
05339 
05340   ink_assert(incoming_hdr->type_get() == HTTP_TYPE_REQUEST);
05341 
05342   if (incoming_hdr->method_get_wksidx() != HTTP_WKSIDX_GET) {
05343     return false;
05344   }
05345 
05346   url = incoming_hdr->url_get();
05347 
05348   int scheme = url->scheme_get_wksidx();
05349   if (scheme != URL_WKSIDX_HTTP && scheme != URL_WKSIDX_HTTPS) {
05350     return false;
05351   }
05352 
05353   if (!statPagesManager.is_stat_page(url)) {
05354     return false;
05355   }
05356 
05357   return true;
05358 }
05359 
05360 bool
05361 HttpTransact::handle_trace_and_options_requests(State* s, HTTPHdr* incoming_hdr)
05362 {
05363   ink_assert(incoming_hdr->type_get() == HTTP_TYPE_REQUEST);
05364 
05365   
05366   if ((s->method != HTTP_WKSIDX_TRACE) && (s->method != HTTP_WKSIDX_OPTIONS))
05367     return false;
05368 
05369   
05370   if (!incoming_hdr->presence(MIME_PRESENCE_MAX_FORWARDS)) {
05371     
05372     
05373     s->current.mode = TUNNELLING_PROXY;
05374     HTTP_INCREMENT_TRANS_STAT(http_tunnels_stat);
05375     return false;
05376   }
05377 
05378   int max_forwards = incoming_hdr->get_max_forwards();
05379   if (max_forwards <= 0) {
05380 
05381     
05382     
05383 
05384     DebugTxn("http_trans", "[handle_trace] max-forwards: 0, building response...");
05385     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
05386     build_response(s, &s->hdr_info.client_response, s->client_info.http_version, HTTP_STATUS_OK);
05387 
05388 
05389     
05390     
05391 
05392     if (s->method == HTTP_WKSIDX_TRACE) {
05393       DebugTxn("http_trans", "[handle_trace] inserting request in body.");
05394       int req_length = incoming_hdr->length_get();
05395       HTTP_RELEASE_ASSERT(req_length > 0);
05396 
05397       s->internal_msg_buffer_index = 0;
05398       s->internal_msg_buffer_size = req_length * 2;
05399       s->free_internal_msg_buffer();
05400 
05401       if (s->internal_msg_buffer_size <= max_iobuffer_size) {
05402         s->internal_msg_buffer_fast_allocator_size = buffer_size_to_index(s->internal_msg_buffer_size);
05403         s->internal_msg_buffer = (char *) ioBufAllocator[s->internal_msg_buffer_fast_allocator_size].alloc_void();
05404       } else {
05405         s->internal_msg_buffer_fast_allocator_size = -1;
05406         s->internal_msg_buffer = (char *)ats_malloc(s->internal_msg_buffer_size);
05407       }
05408 
05409       
05410       memset(s->internal_msg_buffer, '\0', s->internal_msg_buffer_size);
05411 
05412       int offset = 0;
05413       int used = 0;
05414       int done;
05415       done = incoming_hdr->print(s->internal_msg_buffer, s->internal_msg_buffer_size, &used, &offset);
05416       HTTP_RELEASE_ASSERT(done);
05417       s->internal_msg_buffer_size = used;
05418 
05419       s->hdr_info.client_response.set_content_length(used);
05420     } else {
05421       
05422       DebugTxn("http_trans", "[handle_options] inserting methods in Allow.");
05423       HttpTransactHeaders::insert_supported_methods_in_response(&s->hdr_info.client_response, s->scheme);
05424 
05425     }
05426     return true;
05427   } else {                      
05428 
05429     if ((max_forwards <= 0) || (max_forwards > INT_MAX)) {
05430       Log::error("HTTP: snapping invalid max-forwards value %d to %d", max_forwards, INT_MAX);
05431       max_forwards = INT_MAX;
05432     }
05433 
05434     --max_forwards;
05435     DebugTxn("http_trans", "[handle_trace_options] Decrementing max_forwards to %d", max_forwards);
05436     incoming_hdr->set_max_forwards(max_forwards);
05437 
05438     
05439     
05440     s->current.mode = TUNNELLING_PROXY;
05441     HTTP_INCREMENT_TRANS_STAT(http_tunnels_stat);
05442   }
05443 
05444   return false;
05445 }
05446 
05447 void
05448 HttpTransact::initialize_state_variables_for_origin_server(State* s, HTTPHdr* incoming_request, bool second_time)
05449 {
05450   if (s->server_info.name && !second_time) {
05451     ink_assert(s->server_info.port != 0);
05452   }
05453 
05454   int host_len;
05455   const char *host = incoming_request->host_get(&host_len);
05456   s->server_info.name = s->arena.str_store(host, host_len);
05457   s->server_info.port = incoming_request->port_get();
05458 
05459   if (second_time) {
05460     s->dns_info.attempts = 0;
05461     s->dns_info.lookup_name = s->server_info.name;
05462   }
05463 }
05464 
05465 void
05466 HttpTransact::bootstrap_state_variables_from_request(State* s, HTTPHdr* incoming_request)
05467 {
05468   s->current.now = s->client_request_time = ink_cluster_time();
05469   s->client_info.http_version = incoming_request->version_get();
05470 }
05471 
05472 void
05473 HttpTransact::initialize_state_variables_from_request(State* s, HTTPHdr* obsolete_incoming_request)
05474 {
05475   HTTPHdr* incoming_request = &s->hdr_info.client_request;
05476 
05477   
05478   ink_assert(incoming_request == obsolete_incoming_request);
05479 
05480   int host_len;
05481   const char *host_name = incoming_request->host_get(&host_len);
05482 
05483   
05484   if (incoming_request->presence(MIME_PRESENCE_IF_MODIFIED_SINCE | MIME_PRESENCE_IF_NONE_MATCH)) {
05485     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_IMS);
05486   } else {
05487     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_SIMPLE);
05488   }
05489 
05490   
05491   
05492   
05493   
05494   
05495   
05496   
05497   
05498   
05499   
05500   
05501   MIMEField *pc = incoming_request->field_find(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
05502 
05503   
05504   if (pc != NULL) {
05505     s->client_info.proxy_connect_hdr = true;
05506   }
05507 
05508   if (!s->txn_conf->keep_alive_enabled_in) {
05509     s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
05510   } else {
05511     
05512     if (pc != NULL) {
05513       s->client_info.keep_alive = is_header_keep_alive(s->client_info.http_version, s->client_info.http_version, pc);
05514     } else {
05515       MIMEField *c = incoming_request->field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
05516 
05517       s->client_info.keep_alive = is_header_keep_alive(s->client_info.http_version, s->client_info.http_version, c);
05518     }
05519   }
05520 
05521   if (s->client_info.keep_alive == HTTP_KEEPALIVE && s->client_info.http_version == HTTPVersion(1, 1)) {
05522     s->client_info.pipeline_possible = true;
05523   }
05524 
05525   if (!s->server_info.name || s->redirect_info.redirect_in_process) {
05526     s->server_info.name = s->arena.str_store(host_name, host_len);
05527     s->server_info.port = incoming_request->port_get();
05528   } else {
05529     ink_assert(s->server_info.port != 0);
05530   }
05531 
05532   s->next_hop_scheme = s->scheme = incoming_request->url_get()->scheme_get_wksidx();
05533 
05534   
05535   
05536   
05537   
05538   
05539   if (s->is_websocket) {
05540     if (s->next_hop_scheme == URL_WKSIDX_WS) {
05541       DebugTxn("http_trans", "Switching WS next hop scheme to http.");
05542       s->next_hop_scheme = URL_WKSIDX_HTTP;
05543       s->scheme = URL_WKSIDX_HTTP;
05544       
05545     } else if (s->next_hop_scheme == URL_WKSIDX_WSS) {
05546       DebugTxn("http_trans", "Switching WSS next hop scheme to https.");
05547       s->next_hop_scheme = URL_WKSIDX_HTTPS;
05548       s->scheme = URL_WKSIDX_HTTPS;
05549       
05550     } else {
05551       Error("Scheme doesn't match websocket...!");
05552     }
05553 
05554     s->current.mode = GENERIC_PROXY;
05555     s->cache_info.action = CACHE_DO_NO_ACTION;
05556   }
05557 
05558   s->method = incoming_request->method_get_wksidx();
05559 
05560   if (s->method == HTTP_WKSIDX_GET) {
05561     HTTP_INCREMENT_TRANS_STAT(http_get_requests_stat);
05562   } else if (s->method == HTTP_WKSIDX_HEAD) {
05563     HTTP_INCREMENT_TRANS_STAT(http_head_requests_stat);
05564   } else if (s->method == HTTP_WKSIDX_POST) {
05565     HTTP_INCREMENT_TRANS_STAT(http_post_requests_stat);
05566   } else if (s->method == HTTP_WKSIDX_PUT) {
05567     HTTP_INCREMENT_TRANS_STAT(http_put_requests_stat);
05568   } else if (s->method == HTTP_WKSIDX_CONNECT) {
05569     HTTP_INCREMENT_TRANS_STAT(http_connect_requests_stat);
05570   } else if (s->method == HTTP_WKSIDX_DELETE) {
05571     HTTP_INCREMENT_TRANS_STAT(http_delete_requests_stat);
05572   } else if (s->method == HTTP_WKSIDX_PURGE) {
05573     HTTP_INCREMENT_TRANS_STAT(http_purge_requests_stat);
05574   } else if (s->method == HTTP_WKSIDX_TRACE) {
05575     HTTP_INCREMENT_TRANS_STAT(http_trace_requests_stat);
05576   } else if (s->method == HTTP_WKSIDX_PUSH) {
05577     HTTP_INCREMENT_TRANS_STAT(http_push_requests_stat);
05578   } else if (s->method == HTTP_WKSIDX_OPTIONS) {
05579     HTTP_INCREMENT_TRANS_STAT(http_options_requests_stat);
05580   } else if (s->method == HTTP_WKSIDX_TRACE) {
05581     HTTP_INCREMENT_TRANS_STAT(http_trace_requests_stat);
05582   } else {
05583     HTTP_INCREMENT_TRANS_STAT(http_extension_method_requests_stat);
05584     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_METHOD);
05585     s->squid_codes.log_code = SQUID_LOG_TCP_MISS;
05586     s->hdr_info.extension_method = true;
05587   }
05588 
05589   
05590   if (s->client_info.transfer_encoding == CHUNKED_ENCODING) {
05591     s->hdr_info.request_content_length = HTTP_UNDEFINED_CL;
05592   }
05593   s->request_data.hdr = &s->hdr_info.client_request;
05594 
05595   s->request_data.hostname_str = s->arena.str_store(host_name, host_len);
05596   ats_ip_copy(&s->request_data.src_ip, &s->client_info.addr);
05597   memset(&s->request_data.dest_ip, 0, sizeof(s->request_data.dest_ip));
05598   if (s->state_machine->ua_session) {
05599     s->request_data.incoming_port = s->state_machine->ua_session->get_netvc()->get_local_port();
05600   }
05601   s->request_data.xact_start = s->client_request_time;
05602   s->request_data.api_info = &s->api_info;
05603 
05604 
05605   
05606   
05607   
05608 
05609   s->dns_info.looking_up = ORIGIN_SERVER;
05610   s->dns_info.attempts = 0;
05611   s->dns_info.lookup_name = s->server_info.name;
05612 }
05613 
05614 void
05615 HttpTransact::initialize_state_variables_from_response(State* s, HTTPHdr* incoming_response)
05616 {
05617   
05618   s->cache_info.directives.does_server_permit_storing =
05619     HttpTransactHeaders::does_server_allow_response_to_be_stored(&s->hdr_info.server_response);
05620 
05621   
05622 
05623 
05624 
05625 
05626 
05627   MIMEField *c_hdr;
05628   if ((s->current.request_to != ORIGIN_SERVER) &&
05629       (s->current.request_to == PARENT_PROXY ||
05630        s->current.request_to == ICP_SUGGESTED_HOST)) {
05631     c_hdr = s->hdr_info.server_response.field_find(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
05632 
05633     
05634     
05635     if (c_hdr == NULL) {
05636       c_hdr = s->hdr_info.server_response.field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
05637     }
05638   } else {
05639     c_hdr = s->hdr_info.server_response.field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
05640   }
05641 
05642   s->current.server->keep_alive = is_header_keep_alive(s->hdr_info.server_response.version_get(),
05643                                                        s->hdr_info.server_request.version_get(), c_hdr);
05644 
05645   
05646   if (s->is_upgrade_request) {
05647     s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
05648   }
05649 
05650   if (s->current.server->keep_alive == HTTP_KEEPALIVE) {
05651     if (!s->cop_test_page)
05652       DebugTxn("http_hdrs", "[initialize_state_variables_from_response]" "Server is keep-alive.");
05653   } else if (s->state_machine->ua_session && s->state_machine->ua_session->f_outbound_transparent && s->state_machine->t_state.http_config_param->use_client_source_port) {
05654     
05655 
05656 
05657 
05658     s->state_machine->t_state.client_info.keep_alive = HTTP_NO_KEEPALIVE;
05659   }
05660 
05661 
05662   HTTPStatus status_code = incoming_response->status_get();
05663   if (is_response_body_precluded(status_code, s->method)) {
05664     s->hdr_info.response_content_length = 0;
05665     s->hdr_info.trust_response_cl = true;
05666   } else {
05667     
05668     if (incoming_response->presence(MIME_PRESENCE_CONTENT_LENGTH)) {
05669       int64_t cl = incoming_response->get_content_length();
05670 
05671       s->hdr_info.response_content_length = (cl >= 0) ? cl : HTTP_UNDEFINED_CL;
05672       s->hdr_info.trust_response_cl = true;
05673     } else {
05674       s->hdr_info.response_content_length = HTTP_UNDEFINED_CL;
05675       s->hdr_info.trust_response_cl = false;
05676     }
05677   }
05678 
05679   if (incoming_response->presence(MIME_PRESENCE_TRANSFER_ENCODING)) {
05680     MIMEField *field = incoming_response->field_find(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
05681 
05682     HdrCsvIter enc_val_iter;
05683     int enc_val_len;
05684     const char *enc_value = enc_val_iter.get_first(field, &enc_val_len);
05685 
05686     while (enc_value) {
05687       const char *wks_value = hdrtoken_string_to_wks(enc_value, enc_val_len);
05688 
05689       if (wks_value == HTTP_VALUE_CHUNKED) {
05690         if (!s->cop_test_page) {
05691           DebugTxn("http_hdrs", "[init_state_vars_from_resp] transfer encoding: chunked!");
05692         }
05693         s->current.server->transfer_encoding = CHUNKED_ENCODING;
05694 
05695         s->hdr_info.response_content_length = HTTP_UNDEFINED_CL;
05696         s->hdr_info.trust_response_cl = false;
05697 
05698         
05699         
05700         
05701         MIMEField *new_enc_field = NULL;
05702         HdrCsvIter new_enc_iter;
05703         int new_enc_len;
05704         const char *new_enc_val = new_enc_iter.get_first(field, &new_enc_len);
05705 
05706         
05707         
05708         while (new_enc_val) {
05709           const char *new_wks_value = hdrtoken_string_to_wks(new_enc_val, new_enc_len);
05710           if (new_wks_value != wks_value) {
05711             if (new_enc_field) {
05712               new_enc_field->value_append(incoming_response->m_heap, incoming_response->m_mime, new_enc_val, new_enc_len, true);
05713             } else {
05714               new_enc_field = incoming_response->field_create();
05715               incoming_response->field_value_set(new_enc_field, new_enc_val, new_enc_len);
05716             }
05717           }
05718 
05719           new_enc_val = new_enc_iter.get_next(&new_enc_len);
05720         }
05721 
05722         
05723         
05724         incoming_response->field_delete(field);
05725 
05726         
05727         
05728         if (new_enc_field) {
05729           new_enc_field->name_set(incoming_response->m_heap, incoming_response->m_mime, MIME_FIELD_TRANSFER_ENCODING,
05730                                   MIME_LEN_TRANSFER_ENCODING);
05731           incoming_response->field_attach(new_enc_field);
05732         }
05733 
05734         return;
05735       }                         
05736 
05737       enc_value = enc_val_iter.get_next(&enc_val_len);
05738     }
05739   }
05740 
05741   s->current.server->transfer_encoding = NO_TRANSFER_ENCODING;
05742 }
05743 
05744 
05745 bool
05746 HttpTransact::is_cache_response_returnable(State* s)
05747 {
05748   if (s->cache_control.never_cache) {
05749     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_CONFIG);
05750     return false;
05751   }
05752 
05753   if (!s->cache_info.directives.does_client_permit_lookup) {
05754     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_CLIENT);
05755     return false;
05756   }
05757 
05758   if (!HttpTransactHeaders::is_method_cacheable(s->http_config_param, s->method) && s->api_resp_cacheable == false) {
05759     SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_NOT_ACCEPTABLE);
05760     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_METHOD);
05761     return false;
05762   }
05763   
05764   if ((s->cache_control.ttl_in_cache <= 0) &&
05765       do_cookies_prevent_caching((int) s->txn_conf->cache_responses_to_cookies,
05766                                  &s->hdr_info.client_request, s->cache_info.object_read->response_get(),
05767                                  s->cache_info.object_read->request_get())) {
05768     SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_NOT_ACCEPTABLE);
05769     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_COOKIE);
05770     return false;
05771   }
05772 
05773   return true;
05774 }
05775 
05776 
05777 
05778 
05779 
05780 
05781 
05782 
05783 
05784 
05785 
05786 bool
05787 HttpTransact::is_stale_cache_response_returnable(State* s)
05788 {
05789   HTTPHdr *cached_response = s->cache_info.object_read->response_get();
05790 
05791   
05792   
05793   
05794   
05795   if (!s->cache_info.directives.does_client_permit_lookup) {
05796     return false;
05797   }
05798   
05799   
05800   
05801   uint32_t cc_mask;
05802   cc_mask = (MIME_COOKED_MASK_CC_MUST_REVALIDATE |
05803              MIME_COOKED_MASK_CC_PROXY_REVALIDATE |
05804              MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE |
05805              MIME_COOKED_MASK_CC_NO_CACHE | MIME_COOKED_MASK_CC_NO_STORE | MIME_COOKED_MASK_CC_S_MAXAGE);
05806   if ((cached_response->get_cooked_cc_mask() & cc_mask) || cached_response->is_pragma_no_cache_set()) {
05807     DebugTxn("http_trans", "[is_stale_cache_response_returnable] " "document headers prevent serving stale");
05808     return false;
05809   }
05810   
05811   
05812   time_t current_age = HttpTransactHeaders::calculate_document_age(s->cache_info.object_read->request_sent_time_get(),
05813                                                                    s->cache_info.object_read->response_received_time_get(),
05814                                                                    cached_response,
05815                                                                    cached_response->get_date(),
05816                                                                    s->current.now);
05817   
05818   if ((current_age < 0) || (current_age > s->txn_conf->cache_max_stale_age)) {
05819     DebugTxn("http_trans", "[is_stale_cache_response_returnable] " "document age is too large %" PRId64,
05820              (int64_t)current_age);
05821     return false;
05822   }
05823   
05824   Authentication_t auth_needed = AuthenticationNeeded(s->txn_conf, &s->hdr_info.client_request, cached_response);
05825 
05826   if (auth_needed != AUTHENTICATION_SUCCESS) {
05827     DebugTxn("http_trans", "[is_stale_cache_response_returnable] " "authorization prevent serving stale");
05828     return false;
05829   }
05830 
05831   DebugTxn("http_trans", "[is_stale_cache_response_returnable] can serve stale");
05832   return true;
05833 }
05834 
05835 
05836 bool
05837 HttpTransact::url_looks_dynamic(URL* url)
05838 {
05839   const char *p_start, *p, *t;
05840   static const char *asp = ".asp";
05841   const char *part;
05842   int part_length;
05843 
05844   if (url->scheme_get_wksidx() != URL_WKSIDX_HTTP && url->scheme_get_wksidx() != URL_WKSIDX_HTTPS) {
05845     return false;
05846   }
05847 
05848   
05849 
05850 
05851   part = url->params_get(&part_length);
05852   if (part != NULL) {
05853     return true;
05854   }
05855   part = url->query_get(&part_length);
05856   if (part != NULL) {
05857     return true;
05858   }
05859 
05860   
05861 
05862 
05863   part = url->path_get(&part_length);
05864   if (part) {
05865     p = &part[part_length - 1];
05866     t = &asp[3];
05867 
05868     while (p != part) {
05869       if (ParseRules::ink_tolower(*p) == ParseRules::ink_tolower(*t)) {
05870         p -= 1;
05871         t -= 1;
05872         if (t == asp)
05873           return true;
05874       } else
05875         break;
05876     }
05877   }
05878 
05879   
05880 
05881 
05882   if (part && part_length >= 3) {
05883     for (p_start = part; p_start <= &part[part_length - 3]; p_start++) {
05884       if (((p_start[0] == 'c') || (p_start[0] == 'C')) &&
05885           ((p_start[1] == 'g') || (p_start[1] == 'G')) && ((p_start[2] == 'i') || (p_start[2] == 'I'))) {
05886         return (true);
05887       }
05888     }
05889   }
05890 
05891   return (false);
05892 }
05893 
05894 
05895 
05896 
05897 
05898 
05899 
05900 
05901 
05902 
05903 
05904 
05905 
05906 bool
05907 HttpTransact::is_request_cache_lookupable(State* s)
05908 {
05909   
05910   if (s->current.mode == TUNNELLING_PROXY) {
05911     return false;
05912   }
05913   
05914   if (s->cache_info.lookup_count > 0) {
05915     return true;
05916   }
05917   
05918   if (!s->txn_conf->cache_http) {
05919     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_CACHE_OFF);
05920     return false;
05921   }
05922   
05923   if (!HttpTransactHeaders::is_method_cache_lookupable(s->method) && s->api_req_cacheable == false) {
05924     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_METHOD);
05925     return false;
05926   }
05927   
05928   
05929   
05930   
05931   
05932 
05933   
05934   if ((!s->txn_conf->cache_urls_that_look_dynamic) &&
05935       url_looks_dynamic(s->hdr_info.client_request.url_get()) && (s->cache_control.ttl_in_cache <= 0)) {
05936     
05937     
05938     int max_forwards = -1;
05939     if (s->hdr_info.client_request.presence(MIME_PRESENCE_MAX_FORWARDS)) {
05940       MIMEField *max_forwards_f = s->hdr_info.client_request.field_find(MIME_FIELD_MAX_FORWARDS, MIME_LEN_MAX_FORWARDS);
05941 
05942       if (max_forwards_f)
05943         max_forwards = max_forwards_f->value_get_int();
05944     }
05945 
05946     if (max_forwards != 0) {
05947       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_URL);
05948       return false;
05949     }
05950   }
05951 
05952   
05953   if (!s->txn_conf->cache_range_lookup && s->hdr_info.client_request.presence(MIME_PRESENCE_RANGE)) {
05954     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_HEADER_FIELD);
05955     return false;
05956   }
05957 
05958   
05959   
05960   
05961   
05962 
05963   return true;
05964 }
05965 
05966 
05967 
05968 
05969 
05970 
05971 
05972 
05973 
05974 
05975 
05976 
05977 
05978 
05979 
05980 
05981 
05982 int
05983 response_cacheable_indicated_by_cc(HTTPHdr* response)
05984 {
05985   uint32_t cc_mask;
05986   
05987   cc_mask = (MIME_COOKED_MASK_CC_NO_STORE | MIME_COOKED_MASK_CC_PRIVATE);
05988   if (response->get_cooked_cc_mask() & cc_mask) {
05989     return -1;
05990   }
05991   
05992   cc_mask = (MIME_COOKED_MASK_CC_PUBLIC |
05993              MIME_COOKED_MASK_CC_MAX_AGE |
05994              MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MUST_REVALIDATE | MIME_COOKED_MASK_CC_PROXY_REVALIDATE);
05995   if (response->get_cooked_cc_mask() & cc_mask) {
05996     return 1;
05997   }
05998   
05999   return 0;
06000 }
06001 
06002 
06003 
06004 
06005 
06006 
06007 
06008 
06009 
06010 
06011 
06012 
06013 bool
06014 HttpTransact::is_response_cacheable(State* s, HTTPHdr* request, HTTPHdr* response)
06015 {
06016   
06017   
06018   
06019   
06020   
06021   if (!s->dns_info.lookup_validated
06022     && s->client_info.is_transparent) {
06023     DebugTxn("http_trans", "[is_response_cacheable] " "Lookup not validated.  Possible DNS cache poison.  Don't cache");
06024     return false;
06025   }
06026 
06027   
06028   
06029   
06030   
06031   
06032   int req_method = request->method_get_wksidx();
06033   if (!(HttpTransactHeaders::is_method_cacheable(s->http_config_param, req_method)) && s->api_req_cacheable == false) {
06034     DebugTxn("http_trans", "[is_response_cacheable] " "only GET, and some HEAD and POST are cachable");
06035     return false;
06036   }
06037   
06038   
06039   
06040   
06041   if (!(is_request_cache_lookupable(s))) {
06042     DebugTxn("http_trans", "[is_response_cacheable] " "request is not cache lookupable, response is not cachable");
06043     return (false);
06044   }
06045   
06046   if (s->range_setup == RANGE_NOT_HANDLED)
06047     return false;
06048 
06049   
06050   
06051   if ((s->cache_control.ttl_in_cache <= 0) &&
06052       do_cookies_prevent_caching((int) s->txn_conf->cache_responses_to_cookies, request, response)) {
06053     DebugTxn("http_trans", "[is_response_cacheable] " "response has uncachable cookies, response is not cachable");
06054     return (false);
06055   }
06056   
06057   if ((s->txn_conf->cache_ignore_auth) == 0 && response->presence(MIME_PRESENCE_WWW_AUTHENTICATE)) {
06058     DebugTxn("http_trans", "[is_response_cacheable] " "response has WWW-Authenticate, response is not cachable");
06059     return (false);
06060   }
06061   
06062   
06063   if (!s->cache_info.directives.does_server_permit_storing &&
06064       !s->cache_control.ignore_server_no_cache && (s->cache_control.ttl_in_cache <= 0)) {
06065     DebugTxn("http_trans", "[is_response_cacheable] server does not permit storing and config file does not "
06066           "indicate that server directive should be ignored");
06067     return (false);
06068   }
06069   
06070 
06071   
06072   
06073   if ((!s->cache_info.directives.does_config_permit_storing &&
06074        !s->cache_control.ignore_server_no_cache &&
06075        (s->cache_control.ttl_in_cache <= 0)) || (s->cache_control.never_cache)) {
06076     DebugTxn("http_trans", "[is_response_cacheable] config doesn't allow storing, and cache control does not "
06077           "say to ignore no-cache and does not specify never-cache or a ttl");
06078     return (false);
06079   }
06080   
06081 
06082   
06083   if (!s->cache_info.directives.does_client_permit_storing && !s->cache_control.ignore_client_no_cache) {
06084     DebugTxn("http_trans", "[is_response_cacheable] client does not permit storing, "
06085           "and cache control does not say to ignore client no-cache");
06086     return (false);
06087   }
06088   DebugTxn("http_trans", "[is_response_cacheable] client permits storing");
06089 
06090   HTTPStatus response_code = response->status_get();
06091 
06092   
06093   
06094   
06095   if (response_code == HTTP_STATUS_OK) {
06096     
06097     
06098     if (s->cache_control.ttl_in_cache <= 0) {
06099       uint32_t cc_mask = (MIME_COOKED_MASK_CC_MAX_AGE | MIME_COOKED_MASK_CC_S_MAXAGE);
06100       
06101       
06102       switch (s->txn_conf->cache_required_headers) {
06103       case HttpConfigParams::CACHE_REQUIRED_HEADERS_NONE:
06104         DebugTxn("http_trans", "[is_response_cacheable] " "no response headers required");
06105         break;
06106 
06107       case HttpConfigParams::CACHE_REQUIRED_HEADERS_AT_LEAST_LAST_MODIFIED:
06108         if (!response->presence(MIME_PRESENCE_EXPIRES) && !(response->get_cooked_cc_mask() & cc_mask) &&
06109             !response->get_last_modified()) {
06110           DebugTxn("http_trans", "[is_response_cacheable] " "last_modified, expires, or max-age is required");
06111 
06112           s->squid_codes.hit_miss_code = ((response->get_date() == 0) ? (SQUID_MISS_HTTP_NO_DLE) : (SQUID_MISS_HTTP_NO_LE));
06113           return (false);
06114         }
06115         break;
06116 
06117       case HttpConfigParams::CACHE_REQUIRED_HEADERS_CACHE_CONTROL:
06118         if (!response->presence(MIME_PRESENCE_EXPIRES) && !(response->get_cooked_cc_mask() & cc_mask)) {
06119           DebugTxn("http_trans", "[is_response_cacheable] " "expires header or max-age is required");
06120           return (false);
06121         }
06122         break;
06123 
06124       default:
06125         break;
06126       }
06127     }
06128   }
06129   
06130   if (response_code == HTTP_STATUS_PARTIAL_CONTENT || response_code == HTTP_STATUS_RANGE_NOT_SATISFIABLE) {
06131     DebugTxn("http_trans", "[is_response_cacheable] " "response code %d - don't cache", response_code);
06132     return false;
06133   }
06134 
06135   
06136   int indicator;
06137   indicator = response_cacheable_indicated_by_cc(response);
06138   if (indicator > 0) {          
06139     DebugTxn("http_trans", "[is_response_cacheable] YES by response cache control");
06140     
06141     s->www_auth_content = CACHE_AUTH_NONE;
06142     return true;
06143   } else if (indicator < 0) {   
06144 
06145     
06146     
06147     if (s->cache_control.ttl_in_cache > 0) {
06148       DebugTxn("http_trans", "[is_response_cacheable] Cache-control header directives in response overridden by ttl in cache.config");
06149     } else if (!s->cache_control.ignore_server_no_cache) {
06150       DebugTxn("http_trans", "[is_response_cacheable] NO by response cache control");
06151       return false;
06152     }
06153   }
06154   
06155   
06156 
06157   
06158   
06159  
06160     
06161   
06162   
06163    
06164    
06165     
06166   
06167   
06168 
06169   if (response->presence(MIME_PRESENCE_EXPIRES)) {
06170     DebugTxn("http_trans", "[is_response_cacheable] YES response w/ Expires");
06171     return true;
06172   }
06173   
06174   if (response_code == HTTP_STATUS_MOVED_TEMPORARILY || response_code == HTTP_STATUS_TEMPORARY_REDIRECT) {
06175     DebugTxn("http_trans", "[is_response_cacheable] cache-control or expires header is required for 302");
06176     return false;
06177   }
06178   
06179   if (req_method == HTTP_WKSIDX_POST) {
06180     
06181     if (s->cache_control.ttl_in_cache > 0) {
06182       DebugTxn("http_trans", "[is_response_cacheable] POST method with a TTL");
06183     } else {
06184       DebugTxn("http_trans", "[is_response_cacheable] NO POST w/o Expires or CC");
06185       return false;
06186     }
06187   }
06188   
06189   if (s->api_server_response_no_store) {
06190     return (false);
06191   }
06192   
06193   if (!s->txn_conf->negative_caching_enabled) {
06194     if ((response_code == HTTP_STATUS_OK) ||
06195         (response_code == HTTP_STATUS_NOT_MODIFIED) ||
06196         (response_code == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION) ||
06197         (response_code == HTTP_STATUS_MOVED_PERMANENTLY) ||
06198         (response_code == HTTP_STATUS_MULTIPLE_CHOICES) || (response_code == HTTP_STATUS_GONE)) {
06199       DebugTxn("http_trans", "[is_response_cacheable] YES by default ");
06200       return true;
06201     } else {
06202       DebugTxn("http_trans", "[is_response_cacheable] NO by default");
06203       return false;
06204     }
06205   }
06206   if (response_code == HTTP_STATUS_SEE_OTHER ||
06207       response_code == HTTP_STATUS_UNAUTHORIZED ||
06208       response_code == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED)
06209     return false;
06210   
06211   return true;
06212 
06213 
06214 
06215 
06216 
06217 
06218 
06219 
06220 
06221 
06222 
06223 
06224 
06225 
06226 
06227 
06228 
06229 
06230 
06231 
06232 
06233 
06234 }
06235 
06236 bool
06237 HttpTransact::is_request_valid(State* s, HTTPHdr* incoming_request)
06238 {
06239   RequestError_t incoming_error;
06240   URL *url = NULL;
06241 
06242   if (incoming_request)
06243     url = incoming_request->url_get();
06244 
06245   incoming_error = check_request_validity(s, incoming_request);
06246   switch (incoming_error) {
06247   case NO_REQUEST_HEADER_ERROR:
06248     DebugTxn("http_trans", "[is_request_valid]" "no request header errors");
06249     break;
06250   case FAILED_PROXY_AUTHORIZATION:
06251     DebugTxn("http_trans", "[is_request_valid]" "failed proxy authorization");
06252     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06253     build_error_response(s, HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required",
06254                          "access#proxy_auth_required", NULL);
06255     return false;
06256   case NON_EXISTANT_REQUEST_HEADER:
06257     
06258   case BAD_HTTP_HEADER_SYNTAX:
06259     {
06260       DebugTxn("http_trans", "[is_request_valid]" "non-existant/bad header");
06261       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06262       build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid HTTP Request", "request#syntax_error", NULL);
06263       return false;
06264     }
06265 
06266   case MISSING_HOST_FIELD:
06267 
06268 
06269     
06270     
06271     
06272     
06273     
06274     
06275     
06276     
06277     
06278     
06279     
06280     
06281 
06282 
06283     DebugTxn("http_trans", "[is_request_valid] missing host field");
06284     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06285     if (s->http_config_param->reverse_proxy_enabled) {   
06286       build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Host Header Required", "request#no_host", NULL);
06287     } else {
06288       
06289       build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Host Required In Request", "request#no_host", NULL);
06290     }
06291 
06292     return false;
06293   case SCHEME_NOT_SUPPORTED:
06294   case NO_REQUEST_SCHEME:
06295     {
06296       DebugTxn("http_trans", "[is_request_valid] unsupported " "or missing request scheme");
06297       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06298       build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Unsupported URL Scheme", "request#scheme_unsupported", NULL);
06299       return false;
06300     }
06301     
06302   case METHOD_NOT_SUPPORTED:
06303     DebugTxn("http_trans", "[is_request_valid]" "unsupported method");
06304     s->current.mode = TUNNELLING_PROXY;
06305     return true;
06306   case BAD_CONNECT_PORT:
06307     int port;
06308     port = url ? url->port_get() : 0;
06309     DebugTxn("http_trans", "[is_request_valid]" "%d is an invalid connect port", port);
06310     SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06311     build_error_response(s, HTTP_STATUS_FORBIDDEN, "Tunnel Forbidden", "access#connect_forbidden", NULL);
06312     return false;
06313   case NO_POST_CONTENT_LENGTH:
06314     {
06315       DebugTxn("http_trans", "[is_request_valid] post request without content length");
06316       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06317       build_error_response(s, HTTP_STATUS_LENGTH_REQUIRED, "Content Length Required", "request#no_content_length", NULL);
06318       return false;
06319     }
06320   case UNACCEPTABLE_TE_REQUIRED:
06321     {
06322       DebugTxn("http_trans", "[is_request_valid] TE required is unacceptable.");
06323       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06324       build_error_response(s, HTTP_STATUS_NOT_ACCEPTABLE, "Transcoding Not Available", "transcoding#unsupported", NULL);
06325       return false;
06326     }
06327   case INVALID_POST_CONTENT_LENGTH :
06328     {
06329       DebugTxn("http_trans", "[is_request_valid] post request with negative content length value");
06330       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06331       build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Invalid Content Length", "request#invalid_content_length", NULL);
06332       return false;
06333     }
06334   default:
06335     return true;
06336   }
06337 
06338   return true;
06339 }
06340 
06341 
06342 
06343 
06344 
06345 
06346 bool
06347 HttpTransact::is_request_retryable(State* s)
06348 {
06349   if (s->hdr_info.request_body_start == true) {
06350     return false;
06351   }
06352 
06353   if (s->state_machine->plugin_tunnel_type != HTTP_NO_PLUGIN_TUNNEL) {
06354     
06355     if (s->state_machine->plugin_tunnel_type == HTTP_PLUGIN_AS_SERVER && s->api_info.retry_intercept_failures == true) {
06356       
06357       
06358       s->state_machine->plugin_tunnel_type = HTTP_NO_PLUGIN_TUNNEL;
06359     } else {
06360       return false;
06361     }
06362   }
06363 
06364   return true;
06365 }
06366 
06367 bool
06368 HttpTransact::is_response_valid(State* s, HTTPHdr* incoming_response)
06369 {
06370   if (s->current.state != CONNECTION_ALIVE) {
06371     ink_assert((s->current.state == CONNECTION_ERROR) ||
06372                       (s->current.state == OPEN_RAW_ERROR) ||
06373                       (s->current.state == PARSE_ERROR) ||
06374                       (s->current.state == CONNECTION_CLOSED) ||
06375                       (s->current.state == INACTIVE_TIMEOUT) ||
06376                       (s->current.state == ACTIVE_TIMEOUT) ||
06377                       (s->current.state == CONGEST_CONTROL_CONGESTED_ON_M) ||
06378                       (s->current.state == CONGEST_CONTROL_CONGESTED_ON_F));
06379 
06380     s->hdr_info.response_error = CONNECTION_OPEN_FAILED;
06381     return false;
06382   }
06383 
06384   s->hdr_info.response_error = check_response_validity(s, incoming_response);
06385 
06386   switch (s->hdr_info.response_error) {
06387 #ifdef REALLY_NEED_TO_CHECK_DATE_VALIDITY
06388   case BOGUS_OR_NO_DATE_IN_RESPONSE:
06389     
06390 
06391     return true;
06392 #endif
06393   case NO_RESPONSE_HEADER_ERROR:
06394     DebugTxn("http_trans", "[is_response_valid] No errors in response");
06395     return true;
06396 
06397   case MISSING_REASON_PHRASE:
06398     DebugTxn("http_trans", "[is_response_valid] Response Error: Missing reason phrase - allowing");
06399     return true;
06400 
06401   case STATUS_CODE_SERVER_ERROR:
06402     DebugTxn("http_trans", "[is_response_valid] Response Error: Origin Server returned 500 - allowing");
06403     return true;
06404 
06405   case CONNECTION_OPEN_FAILED:
06406     DebugTxn("http_trans", "[is_response_valid] Response Error: connection open failed");
06407     s->current.state = CONNECTION_ERROR;
06408     return false;
06409 
06410   case NON_EXISTANT_RESPONSE_HEADER:
06411     DebugTxn("http_trans", "[is_response_valid] Response Error: No response header");
06412     s->current.state = BAD_INCOMING_RESPONSE;
06413     return false;
06414 
06415   case NOT_A_RESPONSE_HEADER:
06416     DebugTxn("http_trans", "[is_response_valid] Response Error: Not a response header");
06417     s->current.state = BAD_INCOMING_RESPONSE;
06418     return false;
06419 
06420   case MISSING_STATUS_CODE:
06421     DebugTxn("http_trans", "[is_response_valid] Response Error: Missing status code");
06422     s->current.state = BAD_INCOMING_RESPONSE;
06423     return false;
06424 
06425   default:
06426     DebugTxn("http_trans", "[is_response_valid] Errors in response");
06427     s->current.state = BAD_INCOMING_RESPONSE;
06428     return false;
06429   }
06430 }
06431 
06432 
06433 
06434 
06435 
06436 
06437 
06438 
06439 
06440 
06441 
06442 
06443 
06444 
06445 
06446 
06447 
06448 bool
06449 HttpTransact::service_transaction_in_proxy_only_mode(State* )
06450 {
06451   return false;
06452 }
06453 
06454 void
06455 HttpTransact::process_quick_http_filter(State* s, int method)
06456 {
06457   
06458   if (!s->client_connection_enabled) {
06459     return;
06460   }
06461 
06462   if (s->state_machine->ua_session) {
06463     const AclRecord *acl_record = s->state_machine->ua_session->acl_record;
06464     bool deny_request = (acl_record == NULL);
06465     if (acl_record && (acl_record->_method_mask != AclRecord::ALL_METHOD_MASK)) {
06466       if (method != -1) {
06467         deny_request = !acl_record->isMethodAllowed(method);
06468       } else {
06469         int method_str_len;
06470         const char *method_str = s->hdr_info.client_request.method_get(&method_str_len);
06471         deny_request = !acl_record->isNonstandardMethodAllowed(std::string(method_str, method_str_len));
06472       }
06473     }
06474     if (deny_request) {
06475       if (is_debug_tag_set("ip-allow")) {
06476         ip_text_buffer ipb;
06477         Debug("ip-allow", "Quick filter denial on %s:%s with mask %x", ats_ip_ntop(&s->client_info.addr.sa, ipb, sizeof(ipb)), hdrtoken_index_to_wks(method), acl_record ? acl_record->_method_mask : 0x0);
06478       }
06479       s->client_connection_enabled = false;
06480     }
06481   }
06482 }
06483 
06484 
06485 HttpTransact::HostNameExpansionError_t HttpTransact::try_to_expand_host_name(State* s)
06486 {
06487   static int max_dns_lookups = 2 + s->http_config_param->num_url_expansions;
06488   static int last_expansion = max_dns_lookups - 2;
06489 
06490   HTTP_RELEASE_ASSERT(!s->dns_info.lookup_success);
06491 
06492   if (s->dns_info.looking_up == ORIGIN_SERVER) {
06493 
06494     
06495     
06496 
06497     if (s->http_config_param->enable_url_expandomatic) {
06498       int attempts = s->dns_info.attempts;
06499       ink_assert(attempts >= 1 && attempts <= max_dns_lookups);
06500 
06501       if (attempts < max_dns_lookups) {
06502         
06503         if (attempts <= last_expansion) {
06504           char *expansion = s->http_config_param->url_expansions[attempts - 1];
06505           int length = strlen(s->server_info.name) + strlen(expansion) + 1;
06506 
06507           s->dns_info.lookup_name = s->arena.str_alloc(length);
06508           ink_string_concatenate_strings_n(s->dns_info.lookup_name, length + 1, s->server_info.name, ".", expansion, NULL);
06509         } else {
06510           if (ParseRules::strchr(s->server_info.name, '.')) {
06511             
06512             return (EXPANSION_FAILED);
06513           }
06514           
06515           int length = strlen(s->server_info.name) + 8;
06516 
06517           s->dns_info.lookup_name = s->arena.str_alloc(length);
06518           ink_string_concatenate_strings_n(s->dns_info.lookup_name, length + 1, "www.", s->server_info.name, ".com", NULL);
06519         }
06520         return (RETRY_EXPANDED_NAME);
06521       } else {
06522         return (DNS_ATTEMPTS_EXHAUSTED);
06523       }
06524     } else {
06525       return EXPANSION_NOT_ALLOWED;
06526     }
06527   } else {
06528 
06529     
06530     
06531 
06532     ink_assert(s->dns_info.looking_up == PARENT_PROXY);
06533 
06534     s->dns_info.lookup_name = s->server_info.name;
06535     s->dns_info.looking_up = ORIGIN_SERVER;
06536     s->dns_info.attempts = 0;
06537 
06538     return RETRY_EXPANDED_NAME;
06539   }
06540 }
06541 
06542 bool
06543 HttpTransact::will_this_request_self_loop(State* s)
06544 {
06545 
06546   
06547 
06548   if (s->dns_info.lookup_success) {
06549     if (ats_ip_addr_eq(s->host_db_info.ip(), &Machine::instance()->ip.sa)) {
06550       uint16_t host_port = s->hdr_info.client_request.url_get()->port_get();
06551       uint16_t local_port = ats_ip_port_host_order(&s->client_info.addr);
06552       if (host_port == local_port) {
06553         switch (s->dns_info.looking_up) {
06554         case ORIGIN_SERVER:
06555           DebugTxn("http_transact", "[will_this_request_self_loop] host ip and port same as local ip and port - bailing");
06556           break;
06557         case PARENT_PROXY:
06558           DebugTxn("http_transact", "[will_this_request_self_loop] "
06559                 "parent proxy ip and port same as local ip and port - bailing");
06560           break;
06561         default:
06562           DebugTxn("http_transact", "[will_this_request_self_loop] "
06563                 "unknown's ip and port same as local ip and port - bailing");
06564           break;
06565         }
06566         build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Cycle Detected", "request#cycle_detected", NULL);
06567         return true;
06568       }
06569     }
06570 
06571     
06572     
06573     
06574     if (ats_is_ip(&Machine::instance()->ip)) {
06575       MIMEField *via_field = s->hdr_info.client_request.field_find(MIME_FIELD_VIA, MIME_LEN_VIA);
06576 
06577       while (via_field) {
06578         
06579         
06580         int via_len;
06581         const char *via_string = via_field->value_get(&via_len);
06582 
06583         if (via_string && ptr_len_str(via_string, via_len, Machine::instance()->ip_hex_string)) {
06584           DebugTxn("http_transact", "[will_this_request_self_loop] Incoming via: %.*s has (%s[%s] (%s))", via_len, via_string,
06585                 s->http_config_param->proxy_hostname, Machine::instance()->ip_hex_string, s->http_config_param->proxy_request_via_string);
06586           build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Multi-Hop Cycle Detected", "request#cycle_detected", NULL);
06587           return true;
06588         }
06589 
06590         via_field = via_field->m_next_dup;
06591       }
06592     }
06593   }
06594   s->request_will_not_selfloop = true;
06595   return false;
06596 }
06597 
06598 
06599 
06600 
06601 
06602 
06603 void
06604 HttpTransact::handle_content_length_header(State* s, HTTPHdr* header, HTTPHdr* base)
06605 {
06606   int64_t cl = HTTP_UNDEFINED_CL;
06607   ink_assert(header->type_get() == HTTP_TYPE_RESPONSE);
06608   if (base->presence(MIME_PRESENCE_CONTENT_LENGTH)) {
06609     cl = base->get_content_length();
06610     if (cl >= 0) {
06611       
06612       ink_assert(header->get_content_length() == cl);
06613 
06614       switch (s->source) {
06615       case SOURCE_HTTP_ORIGIN_SERVER:
06616         
06617         
06618         if (s->range_setup != HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED)
06619           break;
06620 
06621       case SOURCE_CACHE:
06622         
06623         
06624         if (s->range_setup == HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED) {
06625           change_response_header_because_of_range_request(s,header);
06626           s->hdr_info.trust_response_cl = true;
06627         }
06628 
06629         
06630         
06631         
06632         
06633 
06634         else if ((int64_t) s->cache_info.object_read->object_size_get() == cl) {
06635           s->hdr_info.trust_response_cl = true;
06636         } else {
06637           DebugTxn("http_trans", "Content Length header and cache object size mismatch." "Disabling keep-alive");
06638           s->hdr_info.trust_response_cl = false;
06639         }
06640         break;
06641 
06642       case SOURCE_TRANSFORM:
06643         if (s->range_setup == HttpTransact::RANGE_REQUESTED) {
06644           header->set_content_length(s->range_output_cl);
06645           s->hdr_info.trust_response_cl = true;
06646         } else if (s->hdr_info.transform_response_cl == HTTP_UNDEFINED_CL) {
06647           s->hdr_info.trust_response_cl = false;
06648         } else {
06649           s->hdr_info.trust_response_cl = true;
06650         }
06651         break;
06652 
06653       default:
06654         ink_release_assert(0);
06655         break;
06656       }
06657     } else {
06658       header->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
06659       s->hdr_info.trust_response_cl = false;
06660     }
06661     Debug("http_trans", "[handle_content_length_header] RESPONSE cont len in hdr is %" PRId64, header->get_content_length());
06662   } else {
06663     
06664     if (s->source == SOURCE_CACHE) {
06665       
06666       
06667       
06668       
06669       
06670       cl = s->cache_info.object_read->object_size_get();
06671       if (cl == INT64_MAX) { 
06672         header->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
06673         s->hdr_info.trust_response_cl = false;
06674         s->hdr_info.request_content_length = HTTP_UNDEFINED_CL;
06675         ink_assert(s->range_setup == RANGE_NONE);
06676       }
06677       else if (s->range_setup == RANGE_NOT_TRANSFORM_REQUESTED) {
06678         
06679         
06680         change_response_header_because_of_range_request(s,header);
06681         s->hdr_info.trust_response_cl = true;
06682       }
06683       else {
06684         header->set_content_length(cl);
06685         s->hdr_info.trust_response_cl = true;
06686       }
06687     } else {
06688       
06689       
06690       
06691       if (is_response_body_precluded(header->status_get(), s->method)) {
06692         
06693         
06694         
06695         s->hdr_info.trust_response_cl = true;
06696       } else {
06697         s->hdr_info.trust_response_cl = false;
06698       }
06699       header->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
06700       ink_assert(s->range_setup != RANGE_NOT_TRANSFORM_REQUESTED);
06701     }
06702   }
06703   return;
06704 }                               
06705 
06706 
06707 
06708 
06709 
06710 
06711 
06712 
06713 
06714 
06715 
06716 
06717 
06718 void
06719 HttpTransact::handle_request_keep_alive_headers(State* s, HTTPVersion ver, HTTPHdr* heads)
06720 {
06721   enum KA_Action_t
06722   {
06723     KA_UNKNOWN,
06724     KA_DISABLED,
06725     KA_CLOSE,
06726     KA_CONNECTION
06727   };
06728 
06729   KA_Action_t ka_action = KA_UNKNOWN;
06730   bool upstream_ka = (s->current.server->keep_alive == HTTP_KEEPALIVE);
06731 
06732   ink_assert(heads->type_get() == HTTP_TYPE_REQUEST);
06733 
06734   
06735   if (!upstream_ka) {
06736     ka_action = KA_DISABLED;
06737   } else if (HTTP_MAJOR(ver.m_version) == 0) {  
06738     ka_action = KA_DISABLED;
06739   }
06740   
06741   if (ka_action == KA_UNKNOWN) {
06742     int method = heads->method_get_wksidx();
06743     if (method == HTTP_WKSIDX_GET ||
06744         method == HTTP_WKSIDX_HEAD ||
06745         method == HTTP_WKSIDX_OPTIONS ||
06746         method == HTTP_WKSIDX_PURGE || method == HTTP_WKSIDX_DELETE || method == HTTP_WKSIDX_TRACE) {
06747       
06748       ka_action = KA_CONNECTION;
06749     } else {
06750       
06751       if (heads->get_content_length() == -1) {
06752         ka_action = KA_CLOSE;
06753       } else {
06754         ka_action = KA_CONNECTION;
06755       }
06756     }
06757   }
06758 
06759   ink_assert(ka_action != KA_UNKNOWN);
06760 
06761   
06762   
06763   heads->field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
06764   heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
06765 
06766   if (!s->is_upgrade_request) {
06767     
06768     switch (ka_action) {
06769     case KA_CONNECTION:
06770       ink_assert(s->current.server->keep_alive != HTTP_NO_KEEPALIVE);
06771       if (ver == HTTPVersion(1, 0)) {
06772         if (s->current.request_to == PARENT_PROXY ||
06773             s->current.request_to == ICP_SUGGESTED_HOST) {
06774           heads->value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "keep-alive", 10);
06775         } else {
06776           heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, "keep-alive", 10);
06777         }
06778       }
06779       
06780       
06781       break;
06782     case KA_DISABLED:
06783     case KA_CLOSE:
06784       if (s->current.server->keep_alive != HTTP_NO_KEEPALIVE || (ver == HTTPVersion(1, 1))) {
06785         
06786         s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
06787         if (s->current.request_to == PARENT_PROXY ||
06788             s->current.request_to == ICP_SUGGESTED_HOST) {
06789           heads->value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "close", 5);
06790         } else {
06791           heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, "close", 5);
06792         }
06793       }
06794       
06795       
06796       break;
06797     case KA_UNKNOWN:
06798     default:
06799       ink_assert(0);
06800       break;
06801     }
06802   } else { 
06803     s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
06804     s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
06805     heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE);
06806 
06807     if (s->is_websocket) {
06808       heads->value_set(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE, "websocket", 9);
06809     }
06810   }
06811 }                               
06812 
06813 
06814 
06815 
06816 
06817 
06818 
06819 
06820 
06821 
06822 
06823 
06824 
06825 
06826 void
06827 HttpTransact::handle_response_keep_alive_headers(State* s, HTTPVersion ver, HTTPHdr* heads)
06828 {
06829   enum KA_Action_t
06830   { KA_UNKNOWN, KA_DISABLED, KA_CLOSE, KA_CONNECTION };
06831   KA_Action_t ka_action = KA_UNKNOWN;
06832 
06833   ink_assert(heads->type_get() == HTTP_TYPE_RESPONSE);
06834 
06835   
06836   
06837   heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
06838   heads->field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
06839 
06840   
06841   if (s->is_upgrade_request  &&
06842       heads->status_get() == HTTP_STATUS_SWITCHING_PROTOCOL &&
06843       s->source == SOURCE_HTTP_ORIGIN_SERVER) {
06844     s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
06845     if (s->is_websocket) {
06846       DebugTxn("http_trans", "transaction successfully upgraded to websockets.");
06847       
06848       heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE);
06849       heads->value_set(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE, "websocket", 9);
06850     }
06851 
06852     
06853     
06854     s->did_upgrade_succeed = true;
06855     return;
06856   }
06857 
06858   int c_hdr_field_len;
06859   const char *c_hdr_field_str;
06860   if (s->client_info.proxy_connect_hdr) {
06861     c_hdr_field_str = MIME_FIELD_PROXY_CONNECTION;
06862     c_hdr_field_len = MIME_LEN_PROXY_CONNECTION;
06863   } else {
06864     c_hdr_field_str = MIME_FIELD_CONNECTION;
06865     c_hdr_field_len = MIME_LEN_CONNECTION;
06866   }
06867 
06868   
06869   if (HTTP_MAJOR(ver.m_version) == 0) {  
06870     ka_action = KA_DISABLED;
06871   }
06872   else if (heads->status_get() == HTTP_STATUS_NO_CONTENT &&
06873       ((s->source == SOURCE_HTTP_ORIGIN_SERVER && s->current.server->transfer_encoding != NO_TRANSFER_ENCODING)
06874        || heads->get_content_length() != 0)) {
06875     
06876     
06877     ka_action = KA_CLOSE;
06878   } else {
06879     
06880     
06881     
06882     
06883     
06884 
06885     
06886     if (s->client_info.http_version == HTTPVersion(1, 1) && s->txn_conf->chunking_enabled == 1 &&
06887         
06888         !is_response_body_precluded(s->hdr_info.client_response.status_get(), s->method) &&
06889         
06890         
06891         (((s->source == SOURCE_HTTP_ORIGIN_SERVER || s->source == SOURCE_TRANSFORM) &&
06892           s->hdr_info.server_response.valid() &&
06893           
06894           
06895           s->hdr_info.server_response.status_get() != HTTP_STATUS_NOT_MODIFIED &&
06896           (s->current.server->transfer_encoding == HttpTransact::CHUNKED_ENCODING ||
06897            
06898            
06899            s->hdr_info.trust_response_cl == false)) ||
06900          
06901          (s->source == SOURCE_CACHE && s->hdr_info.trust_response_cl == false) ||
06902          
06903          (s->source == SOURCE_TRANSFORM && s->hdr_info.trust_response_cl == false ))) {
06904       s->client_info.receive_chunked_response = true;
06905       heads->value_append(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING, HTTP_VALUE_CHUNKED, HTTP_LEN_CHUNKED, true);
06906     } else {
06907       s->client_info.receive_chunked_response = false;
06908     }
06909 
06910     
06911     if ( s->client_info.receive_chunked_response ) {
06912       s->hdr_info.trust_response_cl = false;
06913 
06914       
06915       heads->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
06916     }
06917 
06918     
06919     
06920     
06921     
06922     if (s->client_info.keep_alive != HTTP_KEEPALIVE) {
06923        ka_action = KA_DISABLED;
06924     } else if (s->hdr_info.trust_response_cl == false &&
06925         !(s->client_info.receive_chunked_response == true ||
06926           (s->method == HTTP_WKSIDX_PUSH && s->client_info.keep_alive == HTTP_KEEPALIVE))) {
06927       ka_action = KA_CLOSE;
06928     } else {
06929       ka_action = KA_CONNECTION;
06930     }
06931   }
06932 
06933   
06934   switch (ka_action) {
06935   case KA_CONNECTION:
06936     ink_assert(s->client_info.keep_alive != HTTP_NO_KEEPALIVE);
06937     
06938     
06939     
06940     heads->value_set(c_hdr_field_str, c_hdr_field_len, "keep-alive", 10);
06941     
06942     
06943     break;
06944   case KA_CLOSE:
06945   case KA_DISABLED:
06946     if (s->client_info.keep_alive != HTTP_NO_KEEPALIVE || (ver == HTTPVersion(1, 1))) {
06947       heads->value_set(c_hdr_field_str, c_hdr_field_len, "close", 5);
06948       s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
06949     }
06950     
06951     
06952     break;
06953   case KA_UNKNOWN:
06954   default:
06955     ink_assert(0);
06956     break;
06957   }
06958 }                               
06959 
06960 
06961 bool
06962 HttpTransact::delete_all_document_alternates_and_return(State* s, bool cache_hit)
06963 {
06964   if (cache_hit == true) {
06965     if (s->cache_info.is_ram_cache_hit) {
06966       SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_RAM_CACHE_FRESH);
06967     } else {
06968       SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_FRESH);
06969     }
06970   } else {
06971     SET_VIA_STRING(VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_NOT_CACHED);
06972   }
06973 
06974   if ((s->method != HTTP_WKSIDX_GET) && (s->method == HTTP_WKSIDX_DELETE || s->method == HTTP_WKSIDX_PURGE)) {
06975     bool valid_max_forwards;
06976     int max_forwards = -1;
06977     MIMEField *max_forwards_f = s->hdr_info.client_request.field_find(MIME_FIELD_MAX_FORWARDS, MIME_LEN_MAX_FORWARDS);
06978 
06979     
06980     if (max_forwards_f) {
06981       valid_max_forwards = true;
06982       max_forwards = max_forwards_f->value_get_int();
06983     } else {
06984       valid_max_forwards = false;
06985     }
06986 
06987     if (s->method == HTTP_WKSIDX_PURGE || (valid_max_forwards && max_forwards <= 0)) {
06988       DebugTxn("http_trans", "[delete_all_document_alternates_and_return] " "DELETE with Max-Forwards: %d", max_forwards);
06989 
06990       SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
06991 
06992       
06993       
06994       
06995       
06996       s->hdr_info.trust_response_cl = true;
06997       build_response(s, &s->hdr_info.client_response, s->client_info.http_version,
06998                      (cache_hit == true) ? HTTP_STATUS_OK : HTTP_STATUS_NOT_FOUND);
06999 
07000       return true;
07001     } else {
07002       if (valid_max_forwards) {
07003         --max_forwards;
07004         DebugTxn("http_trans", "[delete_all_document_alternates_and_return] " "Decrementing max_forwards to %d", max_forwards);
07005         s->hdr_info.client_request.value_set_int(MIME_FIELD_MAX_FORWARDS, MIME_LEN_MAX_FORWARDS, max_forwards);
07006       }
07007     }
07008   }
07009 
07010   return false;
07011 }
07012 
07013 bool
07014 HttpTransact::does_client_request_permit_cached_response(const OverridableHttpConfigParams *p, CacheControlResult *c,
07015                                                          HTTPHdr *h, char *via_string)
07016 {
07017 
07018   
07019 
07020 
07021   if (!c->ignore_client_no_cache) {
07022     if (h->is_cache_control_set(HTTP_VALUE_NO_CACHE))
07023       return (false);
07024     if (h->is_pragma_no_cache_set()) {
07025       
07026       
07027       if (!p->cache_ims_on_client_no_cache) {
07028         via_string[VIA_CLIENT_REQUEST] = VIA_CLIENT_NO_CACHE;
07029       }
07030       return (false);
07031     }
07032   }
07033 
07034   return (true);
07035 }
07036 
07037 bool
07038 HttpTransact::does_client_request_permit_dns_caching(CacheControlResult* c, HTTPHdr* h)
07039 {
07040   if (h->is_pragma_no_cache_set() && h->is_cache_control_set(HTTP_VALUE_NO_CACHE) && (!c->ignore_client_no_cache)) {
07041     return (false);
07042   }
07043   return (true);
07044 }
07045 
07046 bool
07047 HttpTransact::does_client_request_permit_storing(CacheControlResult* c, HTTPHdr* h)
07048 {
07049 
07050   
07051 
07052   if (!c->ignore_client_no_cache) {
07053     if (h->is_cache_control_set(HTTP_VALUE_NO_STORE))
07054       return (false);
07055   }
07056 
07057   return (true);
07058 }
07059 
07060 
07061 
07062 int
07063 HttpTransact::calculate_document_freshness_limit(State *s, HTTPHdr *response, time_t response_date, bool *heuristic)
07064 {
07065   bool expires_set, date_set, last_modified_set;
07066   time_t date_value, expires_value, last_modified_value;
07067   MgmtInt min_freshness_bounds, max_freshness_bounds;
07068   int freshness_limit = 0;
07069   uint32_t cc_mask = response->get_cooked_cc_mask();
07070 
07071   *heuristic = false;
07072 
07073   if (cc_mask & (MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MAX_AGE)) {
07074     if (cc_mask & MIME_COOKED_MASK_CC_S_MAXAGE) {
07075       freshness_limit = (int) response->get_cooked_cc_s_maxage();
07076       DebugTxn("http_match", "calculate_document_freshness_limit --- s_max_age set, freshness_limit = %d", freshness_limit);
07077     } else if (cc_mask & MIME_COOKED_MASK_CC_MAX_AGE) {
07078       freshness_limit = (int) response->get_cooked_cc_max_age();
07079       DebugTxn("http_match", "calculate_document_freshness_limit --- max_age set, freshness_limit = %d", freshness_limit);
07080     }
07081     freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
07082   } else {
07083     date_set = last_modified_set = false;
07084 
07085     if (s->plugin_set_expire_time != UNDEFINED_TIME) {
07086       expires_set = true;
07087       expires_value = s->plugin_set_expire_time;
07088     } else {
07089       expires_set = (response->presence(MIME_PRESENCE_EXPIRES) != 0);
07090       expires_value = response->get_expires();
07091     }
07092 
07093     date_value = response_date;
07094     if (date_value > 0) {
07095       date_set = true;
07096     } else {
07097       date_value = s->request_sent_time;
07098       DebugTxn("http_match",
07099                "calculate_document_freshness_limit --- Expires header = %" PRId64 " no date, using sent time %" PRId64,
07100                (int64_t)expires_value, (int64_t)date_value);
07101     }
07102     ink_assert(date_value > 0);
07103 
07104     
07105     HttpCacheSM & cache_sm = s->state_machine->get_cache_sm();
07106 
07107     
07108     if (expires_set && !cache_sm.is_readwhilewrite_inprogress()) {
07109       if (expires_value == UNDEFINED_TIME || expires_value <= date_value) {
07110         expires_value = date_value;
07111         DebugTxn("http_match", "calculate_document_freshness_limit --- no expires, using date %" PRId64,
07112                  (int64_t)expires_value);
07113       }
07114       freshness_limit = (int) (expires_value - date_value);
07115 
07116       DebugTxn("http_match",
07117                "calculate_document_freshness_limit --- Expires: %" PRId64 ", Date: %" PRId64 ", freshness_limit = %d",
07118                (int64_t)expires_value, (int64_t)date_value, freshness_limit);
07119 
07120       freshness_limit = min(max(0, freshness_limit), NUM_SECONDS_IN_ONE_YEAR);
07121     } else {
07122       last_modified_value = 0;
07123       if (response->presence(MIME_PRESENCE_LAST_MODIFIED)) {
07124         last_modified_set = true;
07125         last_modified_value = response->get_last_modified();
07126         DebugTxn("http_match", "calculate_document_freshness_limit --- Last Modified header = %" PRId64,
07127                  (int64_t)last_modified_value);
07128 
07129         if (last_modified_value == UNDEFINED_TIME) {
07130           last_modified_set = false;
07131         } else if (last_modified_value > date_value) {
07132           last_modified_value = date_value;
07133           DebugTxn("http_match", "calculate_document_freshness_limit --- no last-modified, using sent time %" PRId64,
07134                    (int64_t)last_modified_value);
07135         }
07136       }
07137 
07138       *heuristic = true;
07139       if (date_set && last_modified_set) {
07140         MgmtFloat f = s->txn_conf->cache_heuristic_lm_factor;
07141         ink_assert((f >= 0.0) && (f <= 1.0));
07142         ink_time_t time_since_last_modify = date_value - last_modified_value;
07143         int h_freshness = (int) (time_since_last_modify * f);
07144         freshness_limit = max(h_freshness, 0);
07145         DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: date=%" PRId64 ", lm=%" PRId64
07146                  ", time_since_last_modify=%"  PRId64 ", f=%g, freshness_limit = %d",
07147                  (int64_t)date_value, (int64_t)last_modified_value, (int64_t)time_since_last_modify,
07148               f, freshness_limit);
07149       } else {
07150         freshness_limit = s->txn_conf->cache_heuristic_min_lifetime;
07151         DebugTxn("http_match", "calculate_document_freshness_limit --- heuristic: freshness_limit = %d", freshness_limit);
07152       }
07153     }
07154   }
07155 
07156   
07157   min_freshness_bounds = max((MgmtInt)0, s->txn_conf->cache_guaranteed_min_lifetime);
07158   max_freshness_bounds = min((MgmtInt)NUM_SECONDS_IN_ONE_YEAR, s->txn_conf->cache_guaranteed_max_lifetime);
07159 
07160   
07161   if (*heuristic) {
07162     min_freshness_bounds = max(min_freshness_bounds, s->txn_conf->cache_heuristic_min_lifetime);
07163     max_freshness_bounds = min(max_freshness_bounds, s->txn_conf->cache_heuristic_max_lifetime);
07164   }
07165   
07166   if (freshness_limit > max_freshness_bounds)
07167     freshness_limit = max_freshness_bounds;
07168   if (freshness_limit < min_freshness_bounds)
07169     freshness_limit = min_freshness_bounds;
07170 
07171   DebugTxn("http_match", "calculate_document_freshness_limit --- final freshness_limit = %d", freshness_limit);
07172 
07173   return (freshness_limit);
07174 }
07175 
07176 
07177 
07178 
07179 
07180 
07181 
07182 
07183 
07184 
07185 
07186 
07187 
07188 
07189 int
07190 HttpTransact::calculate_freshness_fuzz(State* s, int fresh_limit)
07191 {
07192   static double LOG_YEAR = log10((double)NUM_SECONDS_IN_ONE_YEAR);
07193   const uint32_t granularity = 1000;
07194   int result = 0;
07195 
07196   uint32_t random_num = this_ethread()->generator.random();
07197   uint32_t index = random_num % granularity;
07198   uint32_t range = (uint32_t) (granularity * s->txn_conf->freshness_fuzz_prob);
07199 
07200   if (index < range) {
07201     if (s->txn_conf->freshness_fuzz_min_time > 0) {
07202       
07203       int fresh_small = (int)rint((double)s->txn_conf->freshness_fuzz_min_time *
07204                                   pow(2, min((double)fresh_limit / (double)s->txn_conf->freshness_fuzz_time,
07205                                              sqrt((double)s->txn_conf->freshness_fuzz_time))));
07206       int fresh_large = max((int)s->txn_conf->freshness_fuzz_min_time,
07207                             (int)rint(s->txn_conf->freshness_fuzz_time *
07208                                       log10((double)(fresh_limit - s->txn_conf->freshness_fuzz_min_time) / LOG_YEAR)));
07209       result = min(fresh_small, fresh_large);
07210       DebugTxn("http_match", "calculate_freshness_fuzz using min/max --- freshness fuzz = %d", result);
07211     } else {
07212       result = s->txn_conf->freshness_fuzz_time;
07213       DebugTxn("http_match", "calculate_freshness_fuzz --- freshness fuzz = %d", result);
07214     }
07215   }
07216 
07217   return result;
07218 }
07219 
07220 
07221 
07222 
07223 
07224 
07225 
07226 
07227 
07228 
07229 
07230 
07231 
07232 
07233 HttpTransact::Freshness_t
07234 HttpTransact::what_is_document_freshness(State *s, HTTPHdr* client_request, HTTPHdr* cached_obj_response)
07235 {
07236   bool heuristic, do_revalidate = false;
07237   int age_limit;
07238   
07239   
07240   
07241   int fresh_limit;
07242   ink_time_t current_age, response_date;;
07243   uint32_t cc_mask, cooked_cc_mask;
07244   uint32_t os_specifies_revalidate;
07245 
07246 
07247   
07248   
07249   
07250 
07251   if (s->cache_control.ttl_in_cache > 0) {
07252     
07253     
07254     int resident_time = s->current.now - s->response_received_time;
07255 
07256     DebugTxn("http_match", "[..._document_freshness] ttl-in-cache = %d, resident time = %d", s->cache_control.ttl_in_cache,
07257           resident_time);
07258     if (resident_time > s->cache_control.ttl_in_cache) {
07259       return (FRESHNESS_STALE);
07260     } else {
07261       return (FRESHNESS_FRESH);
07262     }
07263   }
07264 
07265 
07266   cooked_cc_mask = cached_obj_response->get_cooked_cc_mask();
07267   os_specifies_revalidate = cooked_cc_mask &
07268     (MIME_COOKED_MASK_CC_MUST_REVALIDATE | MIME_COOKED_MASK_CC_PROXY_REVALIDATE);
07269   cc_mask = MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE;
07270 
07271   
07272 
07273   if ((cooked_cc_mask & cc_mask) && s->cache_control.revalidate_after <= 0) {
07274     DebugTxn("http_match", "[what_is_document_freshness] document stale due to " "server must-revalidate");
07275     return FRESHNESS_STALE;
07276   }
07277 
07278   response_date = cached_obj_response->get_date();
07279   fresh_limit = calculate_document_freshness_limit(s, cached_obj_response, response_date, &heuristic);
07280   ink_assert(fresh_limit >= 0);
07281 
07282   
07283   
07284   if (s->txn_conf->freshness_fuzz_time >= 0) {
07285     fresh_limit = fresh_limit - calculate_freshness_fuzz(s, fresh_limit);
07286     fresh_limit = max(0, fresh_limit);
07287     fresh_limit = min(NUM_SECONDS_IN_ONE_YEAR, fresh_limit);
07288   }
07289 
07290   current_age = HttpTransactHeaders::calculate_document_age(s->request_sent_time, s->response_received_time,
07291                                                             cached_obj_response, response_date, s->current.now);
07292 
07293   
07294   if (current_age < 0)
07295     current_age = NUM_SECONDS_IN_ONE_YEAR;  
07296   else
07297     current_age = min((time_t)NUM_SECONDS_IN_ONE_YEAR, current_age);
07298 
07299   DebugTxn("http_match", "[what_is_document_freshness] fresh_limit:  %d  current_age: %" PRId64,
07300            fresh_limit, (int64_t)current_age);
07301 
07302 
07303   
07304   
07305 
07306   ink_assert(client_request == &s->hdr_info.client_request);
07307 
07308   if (s->txn_conf->cache_when_to_revalidate == 0) {
07309     ;
07310     
07311   } else if (client_request->url_get()->scheme_get_wksidx() == URL_WKSIDX_HTTP) {
07312     switch (s->txn_conf->cache_when_to_revalidate) {
07313     case 1:                    
07314       if (heuristic) {
07315         DebugTxn("http_match", "[what_is_document_freshness] config requires FRESHNESS_STALE because heuristic calculation");
07316         return (FRESHNESS_STALE);
07317       }
07318       break;
07319     case 2:                    
07320       DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_STALE");
07321       return (FRESHNESS_STALE);
07322     case 3:                    
07323       DebugTxn("http_match", "[what_is_document_freshness] config " "specifies always FRESHNESS_FRESH");
07324       return (FRESHNESS_FRESH);
07325     case 4:                    
07326       if (client_request->presence(MIME_PRESENCE_IF_MODIFIED_SINCE)) {
07327         DebugTxn("http_match", "[what_is_document_freshness] config " "specifies FRESHNESS_STALE if IMS present");
07328         return (FRESHNESS_STALE);
07329       }
07330     default:                   
07331       break;
07332     }
07333   }
07334 
07335   
07336   
07337   
07338   
07339   
07340   
07341   
07342 
07343   age_limit = fresh_limit;      
07344   DebugTxn("http_match", "[..._document_freshness] initial age limit: %d", age_limit);
07345 
07346   cooked_cc_mask = client_request->get_cooked_cc_mask();
07347   cc_mask = (MIME_COOKED_MASK_CC_MAX_STALE | MIME_COOKED_MASK_CC_MIN_FRESH | MIME_COOKED_MASK_CC_MAX_AGE);
07348   if (cooked_cc_mask & cc_mask) {
07349 
07350     
07351 
07352     if (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_STALE) {
07353       if (os_specifies_revalidate) {
07354         DebugTxn("http_match", "[...document_freshness] OS specifies revalidation; "
07355               "ignoring client's max-stale request...");
07356       } else {
07357         int max_stale_val = client_request->get_cooked_cc_max_stale();
07358 
07359         if (max_stale_val != INT_MAX)
07360           age_limit += max_stale_val;
07361         else
07362           age_limit = max_stale_val;
07363         DebugTxn("http_match", "[..._document_freshness] max-stale set, age limit: %d", age_limit);
07364       }
07365     }
07366 
07367     
07368 
07369     if (cooked_cc_mask & MIME_COOKED_MASK_CC_MIN_FRESH) {
07370       age_limit = min(age_limit, fresh_limit - client_request->get_cooked_cc_min_fresh());
07371       DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
07372     }
07373 
07374     
07375 
07376     if (!s->cache_control.ignore_client_cc_max_age && (cooked_cc_mask & MIME_COOKED_MASK_CC_MAX_AGE)) {
07377       int age_val = client_request->get_cooked_cc_max_age();
07378       if (age_val == 0)
07379         do_revalidate = true;
07380       age_limit = min(age_limit, age_val);
07381       DebugTxn("http_match", "[..._document_freshness] min_fresh set, age limit: %d", age_limit);
07382     }
07383   }
07384 
07385   
07386 
07387   
07388   if (s->cache_control.revalidate_after >= 0) {
07389     
07390 
07391 
07392     
07393     age_limit = s->cache_control.revalidate_after;
07394 
07395     DebugTxn("http_match", "[..._document_freshness] revalidate_after set, age limit: %d", age_limit);
07396   }
07397 
07398   DebugTxn("http_match", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
07399   DebugTxn("http_match", "document_freshness --- age_limit   = %d", age_limit);
07400   DebugTxn("http_match", "document_freshness --- fresh_limit = %d", fresh_limit);
07401   DebugTxn("http_seq", "document_freshness --- current_age = %" PRId64, (int64_t)current_age);
07402   DebugTxn("http_seq", "document_freshness --- age_limit   = %d", age_limit);
07403   DebugTxn("http_seq", "document_freshness --- fresh_limit = %d", fresh_limit);
07404 
07405   
07406 
07407 
07408   if (do_revalidate || current_age > age_limit) { 
07409     DebugTxn("http_match", "[..._document_freshness] document needs revalidate/too old; "
07410             "returning FRESHNESS_STALE");
07411     return (FRESHNESS_STALE);
07412   } else if (current_age > fresh_limit) {  
07413     if (os_specifies_revalidate) {
07414       DebugTxn("http_match", "[..._document_freshness] document is stale and OS specifies revalidation; "
07415               "returning FRESHNESS_STALE");
07416       return (FRESHNESS_STALE);
07417     }
07418     DebugTxn("http_match", "[..._document_freshness] document is stale but no revalidation explicitly required; "
07419             "returning FRESHNESS_WARNING");
07420     return (FRESHNESS_WARNING);
07421   } else {
07422     DebugTxn("http_match", "[..._document_freshness] document is fresh; returning FRESHNESS_FRESH");
07423     return (FRESHNESS_FRESH);
07424   }
07425 }
07426 
07427 
07428 
07429 
07430 
07431 
07432 
07433 
07434 
07435 
07436 
07437 
07438 
07439 
07440 
07441 
07442 
07443 
07444 
07445 
07446 
07447 
07448 HttpTransact::Authentication_t
07449 HttpTransact::AuthenticationNeeded(const OverridableHttpConfigParams* p, HTTPHdr* client_request, HTTPHdr* obj_response)
07450 {
07451 
07452   
07453   
07454   
07455 
07456 
07457   if ((p->cache_ignore_auth == 0) && client_request->presence(MIME_PRESENCE_AUTHORIZATION)) {
07458     if (obj_response->is_cache_control_set(HTTP_VALUE_MUST_REVALIDATE) ||
07459         obj_response->is_cache_control_set(HTTP_VALUE_PROXY_REVALIDATE)) {
07460       return AUTHENTICATION_MUST_REVALIDATE;
07461     } else if (obj_response->is_cache_control_set(HTTP_VALUE_PROXY_REVALIDATE)) {
07462       return AUTHENTICATION_MUST_REVALIDATE;
07463     } else if (obj_response->is_cache_control_set(HTTP_VALUE_PUBLIC)) {
07464       return AUTHENTICATION_SUCCESS;
07465     } else {
07466       if (obj_response->field_find("@WWW-Auth", 9) && client_request->method_get_wksidx() == HTTP_WKSIDX_GET)
07467         return AUTHENTICATION_CACHE_AUTH;
07468       return AUTHENTICATION_MUST_PROXY;
07469     }
07470   }
07471 
07472   if (obj_response->field_find("@WWW-Auth", 9) && client_request->method_get_wksidx() == HTTP_WKSIDX_GET)
07473     return AUTHENTICATION_CACHE_AUTH;
07474 
07475   return (AUTHENTICATION_SUCCESS);
07476 }
07477 
07478 void
07479 HttpTransact::handle_parent_died(State* s)
07480 {
07481   ink_assert(s->parent_result.r == PARENT_FAIL);
07482 
07483   build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Next Hop Connection Failed", "connect#failed_connect", NULL);
07484   TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
07485 }
07486 
07487 void
07488 HttpTransact::handle_server_died(State* s)
07489 {
07490   const char *reason = NULL;
07491   const char *body_type = "UNKNOWN";
07492   HTTPStatus status = HTTP_STATUS_BAD_GATEWAY;
07493 
07494 
07495   
07496 
07497 
07498 
07499   
07500   
07501   
07502   if (s->pCongestionEntry != NULL) {
07503     s->congestion_congested_or_failed = 1;
07504     if (s->current.state != CONGEST_CONTROL_CONGESTED_ON_F && s->current.state != CONGEST_CONTROL_CONGESTED_ON_M) {
07505       s->pCongestionEntry->failed_at(s->current.now);
07506     }
07507   }
07508 
07509   switch (s->current.state) {
07510   case CONNECTION_ALIVE:       
07511     ink_release_assert(s->hdr_info.response_error != NO_RESPONSE_HEADER_ERROR);
07512     status = HTTP_STATUS_BAD_GATEWAY;
07513     reason = "Unknown Error";
07514     body_type = "response#bad_response";
07515     break;
07516   case CONNECTION_ERROR:
07517     status = HTTP_STATUS_BAD_GATEWAY;
07518     reason = (char *) get_error_string(s->cause_of_death_errno);
07519     body_type = "connect#failed_connect";
07520     break;
07521   case OPEN_RAW_ERROR:
07522     status = HTTP_STATUS_BAD_GATEWAY;
07523     reason = "Tunnel Connection Failed";
07524     body_type = "connect#failed_connect";
07525     break;
07526   case CONNECTION_CLOSED:
07527     status = HTTP_STATUS_BAD_GATEWAY;
07528     reason = "Server Hangup";
07529     body_type = "connect#hangup";
07530     break;
07531   case ACTIVE_TIMEOUT:
07532     if (s->api_txn_active_timeout_value != -1)
07533       DebugTxn("http_timeout", "Maximum active time of %d msec exceeded", s->api_txn_active_timeout_value);
07534     status = HTTP_STATUS_GATEWAY_TIMEOUT;
07535     reason = "Maximum Transaction Time Exceeded";
07536     body_type = "timeout#activity";
07537     break;
07538   case INACTIVE_TIMEOUT:
07539     if (s->api_txn_connect_timeout_value != -1)
07540       DebugTxn("http_timeout", "Maximum connect time of %d msec exceeded", s->api_txn_connect_timeout_value);
07541     status = HTTP_STATUS_GATEWAY_TIMEOUT;
07542     reason = "Connection Timed Out";
07543     body_type = "timeout#inactivity";
07544     break;
07545   case PARSE_ERROR:
07546   case BAD_INCOMING_RESPONSE:
07547     status = HTTP_STATUS_BAD_GATEWAY;
07548     reason = "Invalid HTTP Response";
07549     body_type = "response#bad_response";
07550     break;
07551   case CONGEST_CONTROL_CONGESTED_ON_F:
07552     status = HTTP_STATUS_SERVICE_UNAVAILABLE;
07553     reason = "Origin server congested";
07554     if (s->pCongestionEntry)
07555       body_type = s->pCongestionEntry->getErrorPage();
07556     else
07557       body_type = "congestion#retryAfter";
07558     s->hdr_info.response_error = TOTAL_RESPONSE_ERROR_TYPES;
07559     break;
07560   case CONGEST_CONTROL_CONGESTED_ON_M:
07561     status = HTTP_STATUS_SERVICE_UNAVAILABLE;
07562     reason = "Too many users";
07563     if (s->pCongestionEntry)
07564       body_type = s->pCongestionEntry->getErrorPage();
07565     else
07566       body_type = "congestion#retryAfter";
07567     s->hdr_info.response_error = TOTAL_RESPONSE_ERROR_TYPES;
07568     break;
07569   case STATE_UNDEFINED:
07570   case TRANSACTION_COMPLETE:
07571   default:                     
07572     ink_release_assert(!"[handle_server_died] Unreasonable state - not dead, shouldn't be here");
07573     status = HTTP_STATUS_BAD_GATEWAY;
07574     reason = NULL;
07575     body_type = "response#bad_response";
07576     break;
07577   }
07578 
07579   if (s->pCongestionEntry && s->pCongestionEntry->F_congested() && status != HTTP_STATUS_SERVICE_UNAVAILABLE) {
07580     s->pCongestionEntry->stat_inc_F();
07581     CONGEST_SUM_GLOBAL_DYN_STAT(congested_on_F_stat, 1);
07582     status = HTTP_STATUS_SERVICE_UNAVAILABLE;
07583     reason = "Service Unavailable";
07584     body_type = s->pCongestionEntry->getErrorPage();
07585     s->hdr_info.response_error = TOTAL_RESPONSE_ERROR_TYPES;
07586   }
07587 
07588   
07589 
07590 
07591   switch (s->hdr_info.response_error) {
07592   case NON_EXISTANT_RESPONSE_HEADER:
07593     status = HTTP_STATUS_BAD_GATEWAY;
07594     reason = "No Response Header From Server";
07595     body_type = "response#bad_response";
07596     break;
07597   case MISSING_REASON_PHRASE:
07598   case NO_RESPONSE_HEADER_ERROR:
07599   case NOT_A_RESPONSE_HEADER:
07600 #ifdef REALLY_NEED_TO_CHECK_DATE_VALIDITY
07601   case BOGUS_OR_NO_DATE_IN_RESPONSE:
07602 #endif
07603     status = HTTP_STATUS_BAD_GATEWAY;
07604     reason = "Malformed Server Response";
07605     body_type = "response#bad_response";
07606     break;
07607   case MISSING_STATUS_CODE:
07608     status = HTTP_STATUS_BAD_GATEWAY;
07609     reason = "Malformed Server Response Status";
07610     body_type = "response#bad_response";
07611     break;
07612   default:
07613     break;
07614   }
07615 
07616   if (reason == NULL) {
07617     status = HTTP_STATUS_BAD_GATEWAY;
07618     reason = "Server Connection Failed";
07619     body_type = "connect#failed_connect";
07620   }
07621 
07622   build_error_response(s, status, reason, body_type, NULL);
07623 
07624   return;
07625 }
07626 
07627 
07628 
07629 
07630 bool
07631 HttpTransact::is_request_likely_cacheable(State* s, HTTPHdr* request)
07632 {
07633   if ((s->method == HTTP_WKSIDX_GET || s->api_req_cacheable == true) &&
07634       !request->presence(MIME_PRESENCE_AUTHORIZATION) &&
07635       (!request->presence(MIME_PRESENCE_RANGE) || s->txn_conf->cache_range_write)) {
07636     return true;
07637   }
07638   return false;
07639 }
07640 
07641 void
07642 HttpTransact::build_request(State* s, HTTPHdr* base_request, HTTPHdr* outgoing_request, HTTPVersion outgoing_version)
07643 {
07644   
07645   
07646   
07647   
07648   if (base_request == &s->hdr_info.client_request) {
07649     if (s->redirect_info.redirect_in_process) {
07650       
07651       URL *r_url = &s->redirect_info.redirect_url;
07652 
07653       ink_assert(r_url->valid());
07654       base_request->url_get()->copy(r_url);
07655     } else {
07656       
07657       URL *o_url = &s->cache_info.original_url;
07658 
07659       if (o_url->valid())
07660         base_request->url_get()->copy(o_url);
07661     }
07662   }
07663 
07664   HttpTransactHeaders::copy_header_fields(base_request, outgoing_request, s->txn_conf->fwd_proxy_auth_to_parent);
07665   add_client_ip_to_outgoing_request(s, outgoing_request);
07666   HttpTransactHeaders::remove_privacy_headers_from_request(s->http_config_param, s->txn_conf, outgoing_request);
07667   HttpTransactHeaders::add_global_user_agent_header_to_request(s->txn_conf, outgoing_request);
07668   handle_request_keep_alive_headers(s, outgoing_version, outgoing_request);
07669 
07670   
07671   
07672   
07673   
07674   
07675 
07676   if (s->next_hop_scheme < 0)
07677     s->next_hop_scheme = URL_WKSIDX_HTTP;
07678   if (s->orig_scheme < 0)
07679     s->orig_scheme = URL_WKSIDX_HTTP;
07680 
07681   if (s->txn_conf->insert_request_via_string)
07682     HttpTransactHeaders::insert_via_header_in_request(s, outgoing_request);
07683 
07684   
07685   
07686   outgoing_request->version_set(HTTPVersion(1, 1));
07687 
07688   
07689   ink_assert(outgoing_version != HTTPVersion(0, 0));
07690 
07691   
07692 
07693 
07694   
07695   if (outgoing_version != HTTPVersion(0, 9) && !outgoing_request->presence(MIME_PRESENCE_HOST)) {
07696     URL *url = outgoing_request->url_get();
07697     int host_len;
07698     const char *host = url->host_get(&host_len);
07699 
07700     
07701     
07702     int port = url->port_get();
07703     if (port != url_canonicalize_port(URL_TYPE_HTTP, 0)) {
07704       char *buf = (char *) alloca(host_len + 15);
07705       memcpy(buf, host, host_len);
07706       host_len += snprintf(buf + host_len, 15, ":%d", port);
07707       outgoing_request->value_set(MIME_FIELD_HOST, MIME_LEN_HOST, buf, host_len);
07708     } else {
07709       outgoing_request->value_set(MIME_FIELD_HOST, MIME_LEN_HOST, host, host_len);
07710     }
07711   }
07712 
07713   if (s->current.server == &s->server_info &&
07714       (s->next_hop_scheme == URL_WKSIDX_HTTP || s->next_hop_scheme == URL_WKSIDX_HTTPS ||
07715        s->next_hop_scheme == URL_WKSIDX_WS || s->next_hop_scheme == URL_WKSIDX_WSS)) {
07716     DebugTxn("http_trans", "[build_request] removing host name from url");
07717     HttpTransactHeaders::remove_host_name_from_url(outgoing_request);
07718   }
07719 
07720   
07721   
07722   if (s->current.request_to == PARENT_PROXY &&
07723       !outgoing_request->is_target_in_url()) {
07724     DebugTxn("http_trans", "[build_request] adding target to URL for parent proxy");
07725 
07726     
07727     
07728     outgoing_request->set_url_target_from_host_field();
07729   }
07730 
07731   
07732   
07733   
07734   
07735   
07736   if (s->current.mode == GENERIC_PROXY) {
07737     if (is_request_likely_cacheable(s, base_request)) {
07738       if (s->txn_conf->cache_when_to_revalidate != 4) {
07739         DebugTxn("http_trans", "[build_request] " "request like cacheable and conditional headers removed");
07740         HttpTransactHeaders::remove_conditional_headers(outgoing_request);
07741       } else
07742         DebugTxn("http_trans", "[build_request] " "request like cacheable but keep conditional headers");
07743     } else {
07744       
07745       
07746       DebugTxn("http_trans", "[build_request] " "request not like cacheable and conditional headers not removed");
07747     }
07748   }
07749 
07750   if (s->http_config_param->send_100_continue_response) {
07751     HttpTransactHeaders::remove_100_continue_headers(s, outgoing_request);
07752     DebugTxn("http_trans", "[build_request] request expect 100-continue headers removed");
07753   }
07754 
07755   s->request_sent_time = ink_cluster_time();
07756   s->current.now = s->request_sent_time;
07757   
07758   ink_assert(s->request_sent_time >= s->response_received_time);
07759 
07760 
07761   DebugTxn("http_trans", "[build_request] request_sent_time: %" PRId64, (int64_t)s->request_sent_time);
07762   if (!s->cop_test_page)
07763     DUMP_HEADER("http_hdrs", outgoing_request, s->state_machine_id, "Proxy's Request");
07764 
07765   HTTP_INCREMENT_TRANS_STAT(http_outgoing_requests_stat);
07766 }
07767 
07768 
07769 
07770 
07771 void
07772 HttpTransact::build_response(State* s, HTTPHdr* base_response, HTTPHdr* outgoing_response, HTTPVersion outgoing_version)
07773 {
07774   build_response(s, base_response, outgoing_response, outgoing_version, HTTP_STATUS_NONE, NULL);
07775   return;
07776 }
07777 
07778 
07779 void
07780 HttpTransact::build_response(State* s, HTTPHdr* outgoing_response, HTTPVersion outgoing_version, HTTPStatus status_code,
07781                              const char *reason_phrase)
07782 {
07783   build_response(s, NULL, outgoing_response, outgoing_version, status_code, reason_phrase);
07784   return;
07785 }
07786 
07787 void
07788 HttpTransact::build_response(State* s, HTTPHdr* base_response, HTTPHdr* outgoing_response, HTTPVersion outgoing_version,
07789                              HTTPStatus status_code, const char *reason_phrase)
07790 {
07791   if (reason_phrase == NULL) {
07792     reason_phrase = http_hdr_reason_lookup(status_code);
07793   }
07794 
07795   if (base_response == NULL) {
07796     HttpTransactHeaders::build_base_response(outgoing_response, status_code, reason_phrase, strlen(reason_phrase), s->current.now);
07797   } else {
07798     if ((status_code == HTTP_STATUS_NONE) || (status_code == base_response->status_get())) {
07799       HttpTransactHeaders::copy_header_fields(base_response, outgoing_response, s->txn_conf->fwd_proxy_auth_to_parent);
07800 
07801       if (s->txn_conf->insert_age_in_response)
07802         HttpTransactHeaders::insert_time_and_age_headers_in_response(s->request_sent_time, s->response_received_time,
07803                                                                      s->current.now, base_response, outgoing_response);
07804 
07805       
07806       
07807       
07808       
07809       
07810       
07811       handle_content_length_header(s, outgoing_response, base_response);
07812     } else
07813       switch (status_code) {
07814       case HTTP_STATUS_NOT_MODIFIED:
07815         HttpTransactHeaders::build_base_response(outgoing_response, status_code, reason_phrase, strlen(reason_phrase),
07816                                                  s->current.now);
07817 
07818         
07819         
07820         
07821         
07822         
07823         
07824         
07825         {
07826           static const char *field_name[] = { MIME_FIELD_ETAG,
07827                                               MIME_FIELD_CONTENT_LOCATION,
07828                                               MIME_FIELD_EXPIRES,
07829                                               MIME_FIELD_CACHE_CONTROL,
07830                                               MIME_FIELD_VARY
07831           };
07832           static int field_len[] = { MIME_LEN_ETAG,
07833                                      MIME_LEN_CONTENT_LOCATION,
07834                                      MIME_LEN_EXPIRES,
07835                                      MIME_LEN_CACHE_CONTROL,
07836                                      MIME_LEN_VARY
07837           };
07838           static uint64_t field_presence[] = { MIME_PRESENCE_ETAG,
07839                                                MIME_PRESENCE_CONTENT_LOCATION,
07840                                                MIME_PRESENCE_EXPIRES,
07841                                                MIME_PRESENCE_CACHE_CONTROL,
07842                                                MIME_PRESENCE_VARY
07843           };
07844           MIMEField *field;
07845           int len;
07846           const char *value;
07847 
07848           for (size_t i = 0; i < sizeof(field_len) / sizeof(field_len[0]); i++) {
07849             if (base_response->presence(field_presence[i])) {
07850               field = base_response->field_find(field_name[i], field_len[i]);
07851               value = field->value_get(&len);
07852               outgoing_response->value_append(field_name[i], field_len[i], value, len, 0);
07853             }
07854           }
07855         }
07856         break;
07857 
07858       case HTTP_STATUS_PRECONDITION_FAILED:
07859         
07860       case HTTP_STATUS_RANGE_NOT_SATISFIABLE:
07861         HttpTransactHeaders::build_base_response(outgoing_response, status_code, reason_phrase,
07862                                                  strlen(reason_phrase), s->current.now);
07863         break;
07864       default:
07865         
07866         break;
07867       }
07868   }
07869 
07870   
07871 
07872   
07873   
07874   if (is_response_body_precluded(status_code, s->method))
07875     s->hdr_info.trust_response_cl = true;
07876 
07877   handle_response_keep_alive_headers(s, outgoing_version, outgoing_response);
07878 
07879   if (s->next_hop_scheme < 0)
07880     s->next_hop_scheme = URL_WKSIDX_HTTP;
07881 
07882   
07883   if (s->orig_scheme == URL_WKSIDX_HTTPS && s->txn_conf->proxy_response_hsts_max_age >= 0) {
07884     Debug("http_hdrs", "hsts max-age=%" PRId64, s->txn_conf->proxy_response_hsts_max_age);
07885     HttpTransactHeaders::insert_hsts_header_in_response(s, outgoing_response);
07886   }
07887 
07888   if (s->txn_conf->insert_response_via_string)
07889     HttpTransactHeaders::insert_via_header_in_response(s, outgoing_response);
07890 
07891   HttpTransactHeaders::convert_response(outgoing_version, outgoing_response);
07892 
07893   
07894   
07895   response_url_remap(outgoing_response);
07896 
07897   if (s->http_config_param->enable_http_stats) {
07898     HttpTransactHeaders::generate_and_set_squid_codes(outgoing_response, s->via_string, &s->squid_codes);
07899   }
07900 
07901   HttpTransactHeaders::add_server_header_to_response(s->txn_conf, outgoing_response);
07902 
07903   
07904  
07905   
07906  
07907 
07908   if (diags->on()) {
07909     if (base_response) {
07910       if (!s->cop_test_page)
07911         DUMP_HEADER("http_hdrs", base_response, s->state_machine_id, "Base Header for Building Response");
07912     }
07913     if (!s->cop_test_page)
07914       DUMP_HEADER("http_hdrs", outgoing_response, s->state_machine_id, "Proxy's Response 2");
07915   }
07916 
07917   return;
07918 }
07919 
07920 
07921 
07922 
07923 
07924 
07925 
07926 
07927 
07928 
07929 
07930 
07931 
07932 
07933 
07934 
07935 
07936 
07937 
07938 
07939 
07940 
07941 
07942 
07943 
07944 
07945 
07946 
07947 void
07948 HttpTransact::build_error_response(State *s, HTTPStatus status_code, const char *reason_phrase_or_null,
07949                                    const char *error_body_type, const char *format, ...)
07950 {
07951   va_list ap;
07952   const char *reason_phrase;
07953   char *url_string;
07954   char body_language[256], body_type[256];
07955 
07956   if (NULL == error_body_type) {
07957     error_body_type = "default";
07958   }
07959 
07960 
07961   
07962 
07963   if (s->hdr_info.client_request.valid()) {
07964     url_string = s->hdr_info.client_request.url_string_get(&s->arena);
07965   } else {
07966     url_string = NULL;
07967   }
07968 
07969 
07970   
07971   
07972   
07973   
07974 
07975   if (s->hdr_info.request_content_length != 0 &&
07976       s->state_machine->client_request_body_bytes < s->hdr_info.request_content_length) {
07977     s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
07978   } else {
07979     
07980     
07981     
07982     s->hdr_info.trust_response_cl = true;
07983   }
07984 
07985   switch (status_code) {
07986   case HTTP_STATUS_BAD_REQUEST:
07987     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_ERROR);
07988     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_HEADER_SYNTAX);
07989     break;
07990   case HTTP_STATUS_BAD_GATEWAY:
07991     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_CONNECTION);
07992     break;
07993   case HTTP_STATUS_GATEWAY_TIMEOUT:
07994     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_TIMEOUT);
07995     break;
07996   case HTTP_STATUS_NOT_FOUND:
07997     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_SERVER);
07998     break;
07999   case HTTP_STATUS_FORBIDDEN:
08000     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_ERROR);
08001     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_FORBIDDEN);
08002     break;
08003   case HTTP_STATUS_HTTPVER_NOT_SUPPORTED:
08004     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_ERROR);
08005     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_SERVER);
08006     break;
08007   case HTTP_STATUS_INTERNAL_SERVER_ERROR:
08008     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_DNS_FAILURE);
08009     break;
08010   case HTTP_STATUS_MOVED_TEMPORARILY:
08011     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_SERVER);
08012     break;
08013   case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
08014     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_ERROR);
08015     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_AUTHORIZATION);
08016     break;
08017   case HTTP_STATUS_UNAUTHORIZED:
08018     SET_VIA_STRING(VIA_CLIENT_REQUEST, VIA_CLIENT_ERROR);
08019     SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_AUTHORIZATION);
08020     break;
08021   default:
08022     break;
08023   }
08024 
08025   reason_phrase = (reason_phrase_or_null ? reason_phrase_or_null : (char *) (http_hdr_reason_lookup(status_code)));
08026   if (unlikely(!reason_phrase))
08027     reason_phrase = "Unknown HTTP Status";
08028 
08029   
08030   s->source = SOURCE_INTERNAL;
08031   build_response(s, &s->hdr_info.client_response, s->client_info.http_version, status_code, reason_phrase);
08032 
08033   if (status_code == HTTP_STATUS_SERVICE_UNAVAILABLE) {
08034     if (s->pCongestionEntry != NULL) {
08035       int ret_tmp;
08036       int retry_after = s->pCongestionEntry->client_retry_after();
08037 
08038       s->congestion_control_crat = retry_after;
08039       if (s->hdr_info.client_response.value_get(MIME_FIELD_RETRY_AFTER, MIME_LEN_RETRY_AFTER, &ret_tmp) == NULL)
08040         s->hdr_info.client_response.value_set_int(MIME_FIELD_RETRY_AFTER, MIME_LEN_RETRY_AFTER, retry_after);
08041     }
08042   }
08043   if (status_code == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
08044       s->method == HTTP_WKSIDX_CONNECT && s->hdr_info.client_response.presence(MIME_PRESENCE_PROXY_CONNECTION)) {
08045     int has_ua_msie = 0;
08046     int user_agent_value_len, slen;
08047     const char *user_agent_value, *c, *e;
08048 
08049     user_agent_value = s->hdr_info.client_request.value_get(MIME_FIELD_USER_AGENT, MIME_LEN_USER_AGENT, &user_agent_value_len);
08050     if (user_agent_value && user_agent_value_len >= 4) {
08051       c = user_agent_value;
08052       e = c + user_agent_value_len - 4;
08053       while (1) {
08054         slen = (int) (e - c);
08055         c = (const char *) memchr(c, 'M', slen);
08056         if (c == NULL || (e - c) < 3)
08057           break;
08058         if ((c[1] == 'S') && (c[2] == 'I') && (c[3] == 'E')) {
08059           has_ua_msie = 1;
08060           break;
08061         }
08062         c++;
08063       }
08064     }
08065 
08066     if (has_ua_msie)
08067       s->hdr_info.client_response.value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "close", 5);
08068   }
08069   
08070   
08071   
08072   s->hdr_info.client_response.value_set(MIME_FIELD_CACHE_CONTROL, MIME_LEN_CACHE_CONTROL, "no-store", 8);
08073   
08074   s->hdr_info.client_response.field_delete(MIME_FIELD_EXPIRES, MIME_LEN_EXPIRES);
08075   s->hdr_info.client_response.field_delete(MIME_FIELD_LAST_MODIFIED, MIME_LEN_LAST_MODIFIED);
08076 
08077   if ((status_code == HTTP_STATUS_TEMPORARY_REDIRECT ||
08078        status_code == HTTP_STATUS_MOVED_TEMPORARILY ||
08079        status_code == HTTP_STATUS_MOVED_PERMANENTLY) &&
08080       s->remap_redirect) {
08081     s->hdr_info.client_response.value_set(MIME_FIELD_LOCATION, MIME_LEN_LOCATION, s->remap_redirect, strlen(s->remap_redirect));
08082   }
08083 
08084 
08085 
08086 
08087   
08088   
08089   
08090   
08091 
08092 
08093   int64_t len;
08094   char * new_msg;
08095 
08096   va_start(ap, format);
08097   new_msg = body_factory->fabricate_with_old_api(error_body_type, s, 8192,
08098                                                        &len,
08099                                                        body_language, sizeof(body_language),
08100                                                        body_type, sizeof(body_type),
08101                                                        format, ap);
08102   va_end(ap);
08103 
08104   
08105   
08106   s->free_internal_msg_buffer();
08107   s->internal_msg_buffer = new_msg;
08108   s->internal_msg_buffer_size = len;
08109   s->internal_msg_buffer_index = 0;
08110   s->internal_msg_buffer_fast_allocator_size = -1;
08111 
08112   s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, body_type, strlen(body_type));
08113   s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_LANGUAGE, MIME_LEN_CONTENT_LANGUAGE, body_language,
08114                                         strlen(body_language));
08115 
08116 
08117   
08118 
08119 
08120   if (s->current.state == CONNECTION_ERROR) {
08121     char *reason_buffer;
08122     int buf_len = sizeof(char) * (strlen(get_error_string(s->cause_of_death_errno)) + 50);
08123     reason_buffer = (char *) alloca(buf_len);
08124     snprintf(reason_buffer, buf_len, "Connect Error <%s/%d>", get_error_string(s->cause_of_death_errno), s->cause_of_death_errno);
08125     reason_phrase = reason_buffer;
08126   }
08127 
08128   if (s->http_config_param->errors_log_error_pages && status_code >= HTTP_STATUS_BAD_REQUEST) {
08129     char ip_string[INET6_ADDRSTRLEN];
08130 
08131     Log::error("RESPONSE: sent %s status %d (%s) for '%s'", 
08132         ats_ip_ntop(&s->client_info.addr.sa, ip_string, sizeof(ip_string)), 
08133         status_code, 
08134         reason_phrase,
08135         (url_string ? url_string : "<none>"));
08136   }
08137 
08138   if (url_string) {
08139     s->arena.str_free(url_string);
08140   }
08141 
08142   s->next_action = SM_ACTION_SEND_ERROR_CACHE_NOOP;
08143   return;
08144 }
08145 
08146 void
08147 HttpTransact::build_redirect_response(State* s)
08148 {
08149   DebugTxn("http_redirect", "[HttpTransact::build_redirect_response]");
08150   URL *u;
08151   const char *old_host;
08152   int old_host_len;
08153   const char *new_url = NULL;
08154   int new_url_len;
08155   char *to_free = NULL;
08156   char body_language[256], body_type[256];
08157 
08158   HTTPStatus status_code = HTTP_STATUS_MOVED_TEMPORARILY;
08159   char *reason_phrase = (char *) (http_hdr_reason_lookup(status_code));
08160 
08161   build_response(s, &s->hdr_info.client_response, s->client_info.http_version, status_code, reason_phrase);
08162 
08163 
08164   
08165   
08166   
08167 
08168   u = s->hdr_info.client_request.url_get();
08169   old_host = u->host_get(&old_host_len);
08170   u->host_set(s->dns_info.lookup_name, strlen(s->dns_info.lookup_name));
08171   new_url = to_free = u->string_get(&s->arena, &new_url_len);
08172   if (new_url == NULL) {
08173     new_url = "";
08174   }
08175   u->host_set(old_host, old_host_len);
08176 
08177 
08178   
08179 
08180   HTTPHdr *h = &s->hdr_info.client_response;
08181   if (s->txn_conf->insert_response_via_string) {
08182     const char pa[] = "Proxy-agent";
08183 
08184     h->value_append(pa, sizeof(pa) - 1, s->http_config_param->proxy_response_via_string,
08185                     s->http_config_param->proxy_response_via_string_len);
08186   }
08187   h->value_set(MIME_FIELD_LOCATION, MIME_LEN_LOCATION, new_url, new_url_len);
08188 
08189 
08190   
08191 
08192   s->internal_msg_buffer_index = 0;
08193   s->free_internal_msg_buffer();
08194   s->internal_msg_buffer_fast_allocator_size = -1;
08195   s->internal_msg_buffer = body_factory->fabricate_with_old_api_build_va("redirect#moved_temporarily", s, 8192,
08196                                                                          &s->internal_msg_buffer_size,
08197                                                                          body_language, sizeof(body_language),
08198                                                                          body_type, sizeof(body_type), 
08199                                                                          "%s <a href=\"%s\">%s</a>.  %s.",
08200                                                                          "The document you requested is now",
08201                                                                          new_url, new_url,
08202                                                                          "Please update your documents and bookmarks accordingly", NULL);
08203 
08204 
08205   h->set_content_length(s->internal_msg_buffer_size);
08206   h->value_set(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, "text/html", 9);
08207 
08208   s->arena.str_free(to_free);
08209 }
08210 
08211 const char *
08212 HttpTransact::get_error_string(int erno)
08213 {
08214   if (erno >= 0) {
08215     return (strerror(erno));
08216   } else {
08217     switch (-erno) {
08218     case ENET_THROTTLING:
08219       return ("throttling");
08220     case ESOCK_DENIED:
08221       return ("socks error - denied");
08222     case ESOCK_TIMEOUT:
08223       return ("socks error - timeout");
08224     case ESOCK_NO_SOCK_SERVER_CONN:
08225       return ("socks error - no server connection");
08226 
08227 
08228 
08229 
08230     case UNKNOWN_INTERNAL_ERROR:
08231       return ("internal error - server connection terminated");
08232     default:
08233       return ("");
08234     }
08235   }
08236 }
08237 
08238 ink_time_t
08239 ink_cluster_time(void)
08240 {
08241   int highest_delta;
08242 
08243 #ifdef DEBUG
08244   ink_mutex_acquire(&http_time_lock);
08245   ink_time_t local_time = ink_get_hrtime() / HRTIME_SECOND;
08246   last_http_local_time = local_time;
08247   ink_mutex_release(&http_time_lock);
08248 #else
08249   ink_time_t local_time = ink_get_hrtime() / HRTIME_SECOND;
08250 #endif
08251 
08252   highest_delta = (int) HttpConfig::m_master.cluster_time_delta;
08253 
08254 
08255 
08256 
08257 
08258 
08259 
08260 
08261   Debug("http_trans", "[ink_cluster_time] local: %" PRId64 ", highest_delta: %d, cluster: %" PRId64,
08262         (int64_t)local_time, highest_delta, (int64_t)(local_time + (ink_time_t) highest_delta));
08263 
08264   ink_assert(highest_delta >= 0);
08265 
08266   return local_time + (ink_time_t) highest_delta;
08267 }
08268 
08269 
08270 
08271 
08272 void
08273 HttpTransact::histogram_response_document_size(State* s, int64_t doc_size)
08274 {
08275   if (doc_size >= 0 && doc_size <= 100) {
08276     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_100_stat);
08277   } else if (doc_size <= 1024) {
08278     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_1K_stat);
08279   } else if (doc_size <= 3072) {
08280     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_3K_stat);
08281   } else if (doc_size <= 5120) {
08282     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_5K_stat);
08283   } else if (doc_size <= 10240) {
08284     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_10K_stat);
08285   } else if (doc_size <= 1048576) {
08286     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_1M_stat);
08287   } else {
08288     HTTP_INCREMENT_TRANS_STAT(http_response_document_size_inf_stat);
08289   }
08290   return;
08291 }
08292 
08293 void
08294 HttpTransact::histogram_request_document_size(State* s, int64_t doc_size)
08295 {
08296   if (doc_size >= 0 && doc_size <= 100) {
08297     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_100_stat);
08298   } else if (doc_size <= 1024) {
08299     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_1K_stat);
08300   } else if (doc_size <= 3072) {
08301     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_3K_stat);
08302   } else if (doc_size <= 5120) {
08303     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_5K_stat);
08304   } else if (doc_size <= 10240) {
08305     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_10K_stat);
08306   } else if (doc_size <= 1048576) {
08307     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_1M_stat);
08308   } else {
08309     HTTP_INCREMENT_TRANS_STAT(http_request_document_size_inf_stat);
08310   }
08311   return;
08312 }
08313 
08314 void
08315 HttpTransact::user_agent_connection_speed(State* s, ink_hrtime transfer_time, int64_t nbytes)
08316 {
08317   float bytes_per_hrtime = (transfer_time == 0) ? (nbytes) : ((float) nbytes / (float) (int64_t) transfer_time);
08318   int bytes_per_sec = (int) (bytes_per_hrtime * HRTIME_SECOND);
08319 
08320   if (bytes_per_sec <= 100) {
08321     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_100_stat);
08322   } else if (bytes_per_sec <= 1024) {
08323     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_1K_stat);
08324   } else if (bytes_per_sec <= 10240) {
08325     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_10K_stat);
08326   } else if (bytes_per_sec <= 102400) {
08327     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_100K_stat);
08328   } else if (bytes_per_sec <= 1048576) {
08329     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_1M_stat);
08330   } else if (bytes_per_sec <= 10485760) {
08331     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_10M_stat);
08332   } else {
08333     HTTP_INCREMENT_TRANS_STAT(http_user_agent_speed_bytes_per_sec_100M_stat);
08334   }
08335 
08336   return;
08337 }
08338 
08339 
08340 
08341 
08342 void
08343 HttpTransact::client_result_stat(State* s, ink_hrtime total_time, ink_hrtime request_process_time)
08344 {
08345   ClientTransactionResult_t client_transaction_result = CLIENT_TRANSACTION_RESULT_UNDEFINED;
08346 
08347 
08348   
08349 
08350   if ((s->source == SOURCE_INTERNAL) && (s->hdr_info.client_response.status_get() >= 400)) {
08351     client_transaction_result = CLIENT_TRANSACTION_RESULT_ERROR_OTHER;
08352   }
08353 
08354   switch (s->squid_codes.log_code) {
08355   case SQUID_LOG_ERR_CONNECT_FAIL:
08356     HTTP_INCREMENT_TRANS_STAT(http_cache_miss_cold_stat);
08357     client_transaction_result = CLIENT_TRANSACTION_RESULT_ERROR_CONNECT_FAIL;
08358     break;
08359 
08360   case SQUID_LOG_TCP_MEM_HIT:
08361     HTTP_INCREMENT_TRANS_STAT(http_cache_hit_mem_fresh_stat);
08362   case SQUID_LOG_TCP_HIT:
08363     
08364     HTTP_INCREMENT_TRANS_STAT(http_cache_hit_fresh_stat);
08365     client_transaction_result = CLIENT_TRANSACTION_RESULT_HIT_FRESH;
08366     break;
08367 
08368   case SQUID_LOG_TCP_REFRESH_HIT:
08369     HTTP_INCREMENT_TRANS_STAT(http_cache_hit_reval_stat);
08370     client_transaction_result = CLIENT_TRANSACTION_RESULT_HIT_REVALIDATED;
08371     break;
08372 
08373   case SQUID_LOG_TCP_IMS_HIT:
08374     HTTP_INCREMENT_TRANS_STAT(http_cache_hit_ims_stat);
08375     client_transaction_result = CLIENT_TRANSACTION_RESULT_HIT_FRESH;
08376     break;
08377 
08378   case SQUID_LOG_TCP_REF_FAIL_HIT:
08379     HTTP_INCREMENT_TRANS_STAT(http_cache_hit_stale_served_stat);
08380     client_transaction_result = CLIENT_TRANSACTION_RESULT_HIT_FRESH;
08381     break;
08382 
08383   case SQUID_LOG_TCP_MISS:
08384     if ((GET_VIA_STRING(VIA_CACHE_RESULT) == VIA_IN_CACHE_NOT_ACCEPTABLE)
08385         || (GET_VIA_STRING(VIA_CACHE_RESULT) == VIA_CACHE_MISS)) {
08386       HTTP_INCREMENT_TRANS_STAT(http_cache_miss_cold_stat);
08387       client_transaction_result = CLIENT_TRANSACTION_RESULT_MISS_COLD;
08388     } else {
08389       
08390       HTTP_INCREMENT_TRANS_STAT(http_cache_miss_uncacheable_stat);
08391       client_transaction_result = CLIENT_TRANSACTION_RESULT_MISS_UNCACHABLE;
08392     }
08393     break;
08394 
08395   case SQUID_LOG_TCP_REFRESH_MISS:
08396     HTTP_INCREMENT_TRANS_STAT(http_cache_miss_changed_stat);
08397     client_transaction_result = CLIENT_TRANSACTION_RESULT_MISS_CHANGED;
08398     break;
08399 
08400   case SQUID_LOG_TCP_CLIENT_REFRESH:
08401     HTTP_INCREMENT_TRANS_STAT(http_cache_miss_client_no_cache_stat);
08402     client_transaction_result = CLIENT_TRANSACTION_RESULT_MISS_CLIENT_NO_CACHE;
08403     break;
08404 
08405   case SQUID_LOG_TCP_IMS_MISS:
08406     HTTP_INCREMENT_TRANS_STAT(http_cache_miss_ims_stat);
08407     client_transaction_result = CLIENT_TRANSACTION_RESULT_MISS_COLD;
08408     break;
08409 
08410   case SQUID_LOG_TCP_SWAPFAIL:
08411     HTTP_INCREMENT_TRANS_STAT(http_cache_read_error_stat);
08412     client_transaction_result = CLIENT_TRANSACTION_RESULT_HIT_FRESH;
08413     break;
08414 
08415   case SQUID_LOG_ERR_READ_TIMEOUT:
08416   case SQUID_LOG_TCP_DENIED:
08417     
08418     client_transaction_result = CLIENT_TRANSACTION_RESULT_ERROR_OTHER;
08419     break;
08420 
08421   default:
08422     
08423 
08424 
08425 
08426     
08427     
08428     
08429     
08430 
08431     break;
08432   }
08433 
08434 
08435   
08436 
08437   if (s->client_info.abort == ABORTED) {
08438     client_transaction_result = CLIENT_TRANSACTION_RESULT_ERROR_ABORT;
08439   } else if (s->client_info.abort == MAYBE_ABORTED) {
08440     client_transaction_result = CLIENT_TRANSACTION_RESULT_ERROR_POSSIBLE_ABORT;
08441   }
08442   
08443   if ((s->source != SOURCE_NONE) && (s->client_info.abort == DIDNOT_ABORT)) {
08444     int status_code = s->hdr_info.client_response.status_get();
08445 
08446     switch(status_code) {
08447     case 100: HTTP_INCREMENT_TRANS_STAT(http_response_status_100_count_stat); break;
08448     case 101: HTTP_INCREMENT_TRANS_STAT(http_response_status_101_count_stat); break;
08449     case 200: HTTP_INCREMENT_TRANS_STAT(http_response_status_200_count_stat); break;
08450     case 201: HTTP_INCREMENT_TRANS_STAT(http_response_status_201_count_stat); break;
08451     case 202: HTTP_INCREMENT_TRANS_STAT(http_response_status_202_count_stat); break;
08452     case 203: HTTP_INCREMENT_TRANS_STAT(http_response_status_203_count_stat); break;
08453     case 204: HTTP_INCREMENT_TRANS_STAT(http_response_status_204_count_stat); break;
08454     case 205: HTTP_INCREMENT_TRANS_STAT(http_response_status_205_count_stat); break;
08455     case 206: HTTP_INCREMENT_TRANS_STAT(http_response_status_206_count_stat); break;
08456     case 300: HTTP_INCREMENT_TRANS_STAT(http_response_status_300_count_stat); break;
08457     case 301: HTTP_INCREMENT_TRANS_STAT(http_response_status_301_count_stat); break;
08458     case 302: HTTP_INCREMENT_TRANS_STAT(http_response_status_302_count_stat); break;
08459     case 303: HTTP_INCREMENT_TRANS_STAT(http_response_status_303_count_stat); break;
08460     case 304: HTTP_INCREMENT_TRANS_STAT(http_response_status_304_count_stat); break;
08461     case 305: HTTP_INCREMENT_TRANS_STAT(http_response_status_305_count_stat); break;
08462     case 307: HTTP_INCREMENT_TRANS_STAT(http_response_status_307_count_stat); break;
08463     case 400: HTTP_INCREMENT_TRANS_STAT(http_response_status_400_count_stat); break;
08464     case 401: HTTP_INCREMENT_TRANS_STAT(http_response_status_401_count_stat); break;
08465     case 402: HTTP_INCREMENT_TRANS_STAT(http_response_status_402_count_stat); break;
08466     case 403: HTTP_INCREMENT_TRANS_STAT(http_response_status_403_count_stat); break;
08467     case 404: HTTP_INCREMENT_TRANS_STAT(http_response_status_404_count_stat); break;
08468     case 405: HTTP_INCREMENT_TRANS_STAT(http_response_status_405_count_stat); break;
08469     case 406: HTTP_INCREMENT_TRANS_STAT(http_response_status_406_count_stat); break;
08470     case 407: HTTP_INCREMENT_TRANS_STAT(http_response_status_407_count_stat); break;
08471     case 408: HTTP_INCREMENT_TRANS_STAT(http_response_status_408_count_stat); break;
08472     case 409: HTTP_INCREMENT_TRANS_STAT(http_response_status_409_count_stat); break;
08473     case 410: HTTP_INCREMENT_TRANS_STAT(http_response_status_410_count_stat); break;
08474     case 411: HTTP_INCREMENT_TRANS_STAT(http_response_status_411_count_stat); break;
08475     case 412: HTTP_INCREMENT_TRANS_STAT(http_response_status_412_count_stat); break;
08476     case 413: HTTP_INCREMENT_TRANS_STAT(http_response_status_413_count_stat); break;
08477     case 414: HTTP_INCREMENT_TRANS_STAT(http_response_status_414_count_stat); break;
08478     case 415: HTTP_INCREMENT_TRANS_STAT(http_response_status_415_count_stat); break;
08479     case 416: HTTP_INCREMENT_TRANS_STAT(http_response_status_416_count_stat); break;
08480     case 500: HTTP_INCREMENT_TRANS_STAT(http_response_status_500_count_stat); break;
08481     case 501: HTTP_INCREMENT_TRANS_STAT(http_response_status_501_count_stat); break;
08482     case 502: HTTP_INCREMENT_TRANS_STAT(http_response_status_502_count_stat); break;
08483     case 503: HTTP_INCREMENT_TRANS_STAT(http_response_status_503_count_stat); break;
08484     case 504: HTTP_INCREMENT_TRANS_STAT(http_response_status_504_count_stat); break;
08485     case 505: HTTP_INCREMENT_TRANS_STAT(http_response_status_505_count_stat); break;
08486     default: break;
08487     }
08488     switch(status_code / 100) {
08489     case 1: HTTP_INCREMENT_TRANS_STAT(http_response_status_1xx_count_stat); break;
08490     case 2: HTTP_INCREMENT_TRANS_STAT(http_response_status_2xx_count_stat); break;
08491     case 3: HTTP_INCREMENT_TRANS_STAT(http_response_status_3xx_count_stat); break;
08492     case 4: HTTP_INCREMENT_TRANS_STAT(http_response_status_4xx_count_stat); break;
08493     case 5: HTTP_INCREMENT_TRANS_STAT(http_response_status_5xx_count_stat); break;
08494     default: break;
08495     }
08496   }
08497   
08498   
08499   HTTP_INCREMENT_TRANS_STAT(http_completed_requests_stat);
08500 
08501   
08502   ink_hrtime total_msec = ink_hrtime_to_msec(total_time);
08503   ink_hrtime process_msec = ink_hrtime_to_msec(request_process_time);
08504   switch (client_transaction_result) {
08505   case CLIENT_TRANSACTION_RESULT_HIT_FRESH:
08506     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_hit_fresh_stat, total_msec);
08507     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_hit_fresh_process_stat, process_msec);
08508     break;
08509   case CLIENT_TRANSACTION_RESULT_HIT_REVALIDATED:
08510     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_hit_reval_stat, total_msec);
08511     break;
08512   case CLIENT_TRANSACTION_RESULT_MISS_COLD:
08513     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_miss_cold_stat, total_msec);
08514     break;
08515   case CLIENT_TRANSACTION_RESULT_MISS_CHANGED:
08516     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_miss_changed_stat, total_msec);
08517     break;
08518   case CLIENT_TRANSACTION_RESULT_MISS_CLIENT_NO_CACHE:
08519     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_miss_client_no_cache_stat, total_msec);
08520     break;
08521   case CLIENT_TRANSACTION_RESULT_MISS_UNCACHABLE:
08522     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_miss_uncacheable_stat, total_msec);
08523     break;
08524   case CLIENT_TRANSACTION_RESULT_ERROR_ABORT:
08525     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_errors_aborts_stat, total_msec);
08526     break;
08527   case CLIENT_TRANSACTION_RESULT_ERROR_POSSIBLE_ABORT:
08528     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_errors_possible_aborts_stat, total_msec);
08529     break;
08530   case CLIENT_TRANSACTION_RESULT_ERROR_CONNECT_FAIL:
08531     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_errors_connect_failed_stat, total_msec);
08532     break;
08533   case CLIENT_TRANSACTION_RESULT_ERROR_OTHER:
08534     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_errors_other_stat, total_msec);
08535     break;
08536   default:
08537     HTTP_SUM_TRANS_STAT(http_ua_msecs_counts_other_unclassified_stat, total_msec);
08538     
08539     DebugTxn("http", "Unclassified statistic");
08540     break;
08541   }
08542 }
08543 
08544 void
08545 HttpTransact::origin_server_connection_speed(State* s, ink_hrtime transfer_time, int64_t nbytes)
08546 {
08547   float bytes_per_hrtime = (transfer_time == 0) ? (nbytes) : ((float) nbytes / (float) (int64_t) transfer_time);
08548   int bytes_per_sec = (int) (bytes_per_hrtime * HRTIME_SECOND);
08549 
08550   if (bytes_per_sec <= 100) {
08551     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_100_stat);
08552   } else if (bytes_per_sec <= 1024) {
08553     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_1K_stat);
08554   } else if (bytes_per_sec <= 10240) {
08555     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_10K_stat);
08556   } else if (bytes_per_sec <= 102400) {
08557     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_100K_stat);
08558   } else if (bytes_per_sec <= 1048576) {
08559     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_1M_stat);
08560   } else if (bytes_per_sec <= 10485760) {
08561     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_10M_stat);
08562   } else {
08563     HTTP_INCREMENT_TRANS_STAT(http_origin_server_speed_bytes_per_sec_100M_stat);
08564   }
08565 
08566   return;
08567 }
08568 
08569 void
08570 HttpTransact::update_size_and_time_stats(State* s, ink_hrtime total_time, ink_hrtime user_agent_write_time,
08571                                          ink_hrtime origin_server_read_time, int user_agent_request_header_size,
08572                                          int64_t user_agent_request_body_size, int user_agent_response_header_size,
08573                                          int64_t user_agent_response_body_size, int origin_server_request_header_size,
08574                                          int64_t origin_server_request_body_size, int origin_server_response_header_size,
08575                                          int64_t origin_server_response_body_size, int pushed_response_header_size,
08576                                          int64_t pushed_response_body_size)
08577 {
08578   int64_t user_agent_request_size = user_agent_request_header_size + user_agent_request_body_size;
08579   int64_t user_agent_response_size = user_agent_response_header_size + user_agent_response_body_size;
08580   int64_t user_agent_bytes = user_agent_request_size + user_agent_response_size;
08581 
08582   int64_t origin_server_request_size = origin_server_request_header_size + origin_server_request_body_size;
08583   int64_t origin_server_response_size = origin_server_response_header_size + origin_server_response_body_size;
08584   int64_t origin_server_bytes = origin_server_request_size + origin_server_response_size;
08585 
08586   
08587   switch (s->state_machine->background_fill) {
08588   case BACKGROUND_FILL_COMPLETED:
08589     {
08590       int64_t bg_size = origin_server_response_body_size - user_agent_response_body_size;
08591       bg_size = max((int64_t)0, bg_size);
08592       HTTP_SUM_TRANS_STAT(http_background_fill_bytes_completed_stat, bg_size);
08593       break;
08594     }
08595   case BACKGROUND_FILL_ABORTED:
08596     {
08597       int64_t bg_size = origin_server_response_body_size - user_agent_response_body_size;
08598 
08599       if (bg_size < 0)
08600         bg_size = 0;
08601       HTTP_SUM_TRANS_STAT(http_background_fill_bytes_aborted_stat, bg_size);
08602       break;
08603     }
08604   case BACKGROUND_FILL_NONE:
08605     break;
08606   case BACKGROUND_FILL_STARTED:
08607   default:
08608     ink_assert(0);
08609   }
08610 
08611   
08612   switch (s->squid_codes.log_code) {
08613   case SQUID_LOG_TCP_HIT:
08614   case SQUID_LOG_TCP_MEM_HIT:
08615     
08616     HTTP_INCREMENT_TRANS_STAT(http_tcp_hit_count_stat);
08617     HTTP_SUM_TRANS_STAT(http_tcp_hit_user_agent_bytes_stat, user_agent_bytes);
08618     HTTP_SUM_TRANS_STAT(http_tcp_hit_origin_server_bytes_stat, origin_server_bytes);
08619     break;
08620   case SQUID_LOG_TCP_MISS:
08621     HTTP_INCREMENT_TRANS_STAT(http_tcp_miss_count_stat);
08622     HTTP_SUM_TRANS_STAT(http_tcp_miss_user_agent_bytes_stat, user_agent_bytes);
08623     HTTP_SUM_TRANS_STAT(http_tcp_miss_origin_server_bytes_stat, origin_server_bytes);
08624     break;
08625   case SQUID_LOG_TCP_EXPIRED_MISS:
08626     HTTP_INCREMENT_TRANS_STAT(http_tcp_expired_miss_count_stat);
08627     HTTP_SUM_TRANS_STAT(http_tcp_expired_miss_user_agent_bytes_stat, user_agent_bytes);
08628     HTTP_SUM_TRANS_STAT(http_tcp_expired_miss_origin_server_bytes_stat, origin_server_bytes);
08629     break;
08630   case SQUID_LOG_TCP_REFRESH_HIT:
08631     HTTP_INCREMENT_TRANS_STAT(http_tcp_refresh_hit_count_stat);
08632     HTTP_SUM_TRANS_STAT(http_tcp_refresh_hit_user_agent_bytes_stat, user_agent_bytes);
08633     HTTP_SUM_TRANS_STAT(http_tcp_refresh_hit_origin_server_bytes_stat, origin_server_bytes);
08634     break;
08635   case SQUID_LOG_TCP_REFRESH_MISS:
08636     HTTP_INCREMENT_TRANS_STAT(http_tcp_refresh_miss_count_stat);
08637     HTTP_SUM_TRANS_STAT(http_tcp_refresh_miss_user_agent_bytes_stat, user_agent_bytes);
08638     HTTP_SUM_TRANS_STAT(http_tcp_refresh_miss_origin_server_bytes_stat, origin_server_bytes);
08639     break;
08640   case SQUID_LOG_TCP_CLIENT_REFRESH:
08641     HTTP_INCREMENT_TRANS_STAT(http_tcp_client_refresh_count_stat);
08642     HTTP_SUM_TRANS_STAT(http_tcp_client_refresh_user_agent_bytes_stat, user_agent_bytes);
08643     HTTP_SUM_TRANS_STAT(http_tcp_client_refresh_origin_server_bytes_stat, origin_server_bytes);
08644     break;
08645   case SQUID_LOG_TCP_IMS_HIT:
08646     HTTP_INCREMENT_TRANS_STAT(http_tcp_ims_hit_count_stat);
08647     HTTP_SUM_TRANS_STAT(http_tcp_ims_hit_user_agent_bytes_stat, user_agent_bytes);
08648     HTTP_SUM_TRANS_STAT(http_tcp_ims_hit_origin_server_bytes_stat, origin_server_bytes);
08649     break;
08650   case SQUID_LOG_TCP_IMS_MISS:
08651     HTTP_INCREMENT_TRANS_STAT(http_tcp_ims_miss_count_stat);
08652     HTTP_SUM_TRANS_STAT(http_tcp_ims_miss_user_agent_bytes_stat, user_agent_bytes);
08653     HTTP_SUM_TRANS_STAT(http_tcp_ims_miss_origin_server_bytes_stat, origin_server_bytes);
08654     break;
08655   case SQUID_LOG_ERR_CLIENT_ABORT:
08656     HTTP_INCREMENT_TRANS_STAT(http_err_client_abort_count_stat);
08657     HTTP_SUM_TRANS_STAT(http_err_client_abort_user_agent_bytes_stat, user_agent_bytes);
08658     HTTP_SUM_TRANS_STAT(http_err_client_abort_origin_server_bytes_stat, origin_server_bytes);
08659     break;
08660   case SQUID_LOG_ERR_CONNECT_FAIL:
08661     HTTP_INCREMENT_TRANS_STAT(http_err_connect_fail_count_stat);
08662     HTTP_SUM_TRANS_STAT(http_err_connect_fail_user_agent_bytes_stat, user_agent_bytes);
08663     HTTP_SUM_TRANS_STAT(http_err_connect_fail_origin_server_bytes_stat, origin_server_bytes);
08664     break;
08665   default:
08666     HTTP_INCREMENT_TRANS_STAT(http_misc_count_stat);
08667     HTTP_SUM_TRANS_STAT(http_misc_user_agent_bytes_stat, user_agent_bytes);
08668     HTTP_SUM_TRANS_STAT(http_misc_origin_server_bytes_stat, origin_server_bytes);
08669     break;
08670   }
08671 
08672   
08673   HTTP_SUM_TRANS_STAT(http_total_transactions_time_stat, total_time);
08674 
08675   
08676   HTTP_SUM_TRANS_STAT(http_user_agent_request_header_total_size_stat, user_agent_request_header_size);
08677   HTTP_SUM_TRANS_STAT(http_user_agent_response_header_total_size_stat, user_agent_response_header_size);
08678   HTTP_SUM_TRANS_STAT(http_user_agent_request_document_total_size_stat, user_agent_request_body_size);
08679   HTTP_SUM_TRANS_STAT(http_user_agent_response_document_total_size_stat, user_agent_response_body_size);
08680 
08681   
08682   if (s->current.request_to == HttpTransact::PARENT_PROXY) {
08683     HTTP_SUM_TRANS_STAT(http_parent_proxy_request_total_bytes_stat,
08684                         origin_server_request_header_size + origin_server_request_body_size);
08685     HTTP_SUM_TRANS_STAT(http_parent_proxy_response_total_bytes_stat,
08686                         origin_server_response_header_size + origin_server_response_body_size);
08687     HTTP_SUM_TRANS_STAT(http_parent_proxy_transaction_time_stat, total_time);
08688   }
08689   
08690   
08691   if (origin_server_request_header_size > 0) {
08692     HTTP_SUM_TRANS_STAT(http_origin_server_request_header_total_size_stat, origin_server_request_header_size);
08693     HTTP_SUM_TRANS_STAT(http_origin_server_response_header_total_size_stat, origin_server_response_header_size);
08694     HTTP_SUM_TRANS_STAT(http_origin_server_request_document_total_size_stat, origin_server_request_body_size);
08695     HTTP_SUM_TRANS_STAT(http_origin_server_response_document_total_size_stat, origin_server_response_body_size);
08696   }
08697 
08698   if (s->method == HTTP_WKSIDX_PUSH) {
08699     HTTP_SUM_TRANS_STAT(http_pushed_response_header_total_size_stat, pushed_response_header_size);
08700     HTTP_SUM_TRANS_STAT(http_pushed_document_total_size_stat, pushed_response_body_size);
08701   }
08702 
08703   histogram_request_document_size(s, user_agent_request_body_size);
08704   histogram_response_document_size(s, user_agent_response_body_size);
08705 
08706   if (user_agent_write_time >= 0) {
08707     user_agent_connection_speed(s, user_agent_write_time, user_agent_response_size);
08708   }
08709 
08710   if (origin_server_request_header_size > 0 && origin_server_read_time > 0) {
08711     origin_server_connection_speed(s, origin_server_read_time, origin_server_response_size);
08712   }
08713 
08714   return;
08715 }
08716 
08717 
08718 
08719 
08720 
08721 
08722 void
08723 HttpTransact::add_new_stat_block(State* s)
08724 {
08725   
08726   
08727   
08728   ink_assert(s->current_stats->next_insert == StatBlockEntries);
08729   StatBlock *new_block = (StatBlock *) s->arena.alloc(sizeof(StatBlock));
08730   new_block->init();
08731   s->current_stats->next = new_block;
08732   s->current_stats = new_block;
08733   DebugTxn("http_trans", "Adding new large stat block");
08734 }
08735 
08736 
08737 void
08738 HttpTransact::delete_warning_value(HTTPHdr* to_warn, HTTPWarningCode warning_code)
08739 {
08740   int w_code = (int) warning_code;
08741   MIMEField *field = to_warn->field_find(MIME_FIELD_WARNING, MIME_LEN_WARNING);;
08742 
08743   
08744   if (field) {
08745     HdrCsvIter iter;
08746 
08747     int valid;
08748     int val_code;
08749 
08750     const char *value_str;
08751     int value_len;
08752 
08753     MIMEField *new_field = NULL;
08754     val_code = iter.get_first_int(field, &valid);
08755 
08756     while (valid) {
08757       if (val_code == w_code) {
08758         
08759         
08760         
08761         
08762         val_code = iter.get_first_int(field, &valid);
08763 
08764         while (valid) {
08765           if (val_code != warning_code) {
08766             value_str = iter.get_current(&value_len);
08767             if (new_field) {
08768               new_field->value_append(to_warn->m_heap, to_warn->m_mime, value_str, value_len, true);
08769             } else {
08770               new_field = to_warn->field_create();
08771               to_warn->field_value_set(new_field, value_str, value_len);
08772             }
08773 
08774           }
08775           val_code = iter.get_next_int(&valid);
08776         }
08777 
08778         to_warn->field_delete(MIME_FIELD_WARNING, MIME_LEN_WARNING);
08779         if (new_field) {
08780           new_field->name_set(to_warn->m_heap, to_warn->m_mime, MIME_FIELD_WARNING, MIME_LEN_WARNING);
08781           to_warn->field_attach(new_field);
08782         }
08783 
08784         return;
08785       }
08786 
08787       val_code = iter.get_next_int(&valid);
08788     }
08789   }
08790 }
08791 
08792 void
08793 HttpTransact::change_response_header_because_of_range_request(State *s, HTTPHdr * header)
08794 {
08795   MIMEField *field;
08796   char *reason_phrase;
08797 
08798   Debug("http_trans", "Partial content requested, re-calculating content-length");
08799 
08800   header->status_set(HTTP_STATUS_PARTIAL_CONTENT);
08801   reason_phrase = (char *) (http_hdr_reason_lookup(HTTP_STATUS_PARTIAL_CONTENT));
08802   header->reason_set(reason_phrase, strlen(reason_phrase));
08803 
08804   
08805   if (s->num_range_fields > 1) {
08806     field = header->field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
08807 
08808     if (field != NULL)
08809       header->field_delete(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
08810 
08811     field = header->field_create(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
08812     field->value_append(header->m_heap, header->m_mime, range_type, sizeof(range_type) - 1);
08813 
08814     header->field_attach(field);
08815     
08816     
08817     header->set_content_length(s->range_output_cl);
08818   } else {
08819     if (s->cache_info.object_read && s->cache_info.object_read->valid()) {
08820       
08821       
08822       
08823       
08824       char numbers[RANGE_NUMBERS_LENGTH];
08825       header->field_delete(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE);
08826       field = header->field_create(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE);
08827       snprintf(numbers, sizeof(numbers), "bytes %" PRId64"-%" PRId64"/%" PRId64, s->ranges[0]._start, s->ranges[0]._end,
08828                s->cache_info.object_read->object_size_get());
08829       field->value_set(header->m_heap, header->m_mime, numbers, strlen(numbers));
08830       header->field_attach(field);
08831     }
08832     
08833     header->set_content_length(s->range_output_cl);
08834   }
08835 }
08836 
08837 #if TS_HAS_TESTS
08838 void forceLinkRegressionHttpTransact();
08839 void forceLinkRegressionHttpTransactCaller() {
08840   forceLinkRegressionHttpTransact();
08841 }
08842 #endif