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