00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 #include "libts.h"
00024 
00025 #include "HttpTransact.h"
00026 #include "HttpTransactHeaders.h"
00027 #include "HTTP.h"
00028 #include "HdrUtils.h"
00029 #include "HttpCompat.h"
00030 
00031 #include "I_Machine.h"
00032 
00033 bool
00034 HttpTransactHeaders::is_method_cacheable(const HttpConfigParams *http_config_param, const int method)
00035 {
00036   return (method == HTTP_WKSIDX_GET || method == HTTP_WKSIDX_HEAD ||
00037           (http_config_param->cache_post_method == 1 && method == HTTP_WKSIDX_POST));
00038 }
00039 
00040 
00041 bool
00042 HttpTransactHeaders::is_method_cache_lookupable(int method)
00043 {
00044   
00045   
00046   return (method == HTTP_WKSIDX_GET ||
00047           method == HTTP_WKSIDX_HEAD ||
00048           method == HTTP_WKSIDX_POST ||
00049           method == HTTP_WKSIDX_DELETE ||
00050           method == HTTP_WKSIDX_PUT || method == HTTP_WKSIDX_PURGE || method == HTTP_WKSIDX_PUSH);
00051 }
00052 
00053 
00054 bool
00055 HttpTransactHeaders::is_this_a_hop_by_hop_header(const char *field_name)
00056 {
00057   if (!hdrtoken_is_wks(field_name))
00058     return (false);
00059   if ((hdrtoken_wks_to_flags(field_name) & MIME_FLAGS_HOPBYHOP) && (field_name != MIME_FIELD_KEEP_ALIVE)) {
00060     return (true);
00061   } else {
00062     return (false);
00063   }
00064 }
00065 
00066 
00067 bool
00068 HttpTransactHeaders::is_this_method_supported(int the_scheme, int the_method)
00069 {
00070   if (the_method == HTTP_WKSIDX_CONNECT) {
00071     return true;
00072   } else if (the_scheme == URL_WKSIDX_HTTP || the_scheme == URL_WKSIDX_HTTPS) {
00073     return is_this_http_method_supported(the_method);
00074   } else if ((the_scheme == URL_WKSIDX_WS || the_scheme == URL_WKSIDX_WSS) &&
00075             the_method == HTTP_WKSIDX_GET) {
00076     return true;
00077   } else
00078     return false;
00079 }
00080 
00081 
00082 void
00083 HttpTransactHeaders::insert_supported_methods_in_response(HTTPHdr *response, int scheme)
00084 {
00085   int method_output_lengths[32];
00086   const char *methods[] = {
00087     HTTP_METHOD_CONNECT,
00088     HTTP_METHOD_DELETE,
00089     HTTP_METHOD_GET,
00090     HTTP_METHOD_HEAD,
00091     HTTP_METHOD_ICP_QUERY,
00092     HTTP_METHOD_OPTIONS,
00093     HTTP_METHOD_POST,
00094     HTTP_METHOD_PURGE,
00095     HTTP_METHOD_PUT,
00096     HTTP_METHOD_PUSH,
00097     HTTP_METHOD_TRACE,
00098   };
00099   char inline_buffer[64];
00100   char *alloced_buffer, *value_buffer;
00101 
00102   int nmethods = sizeof(methods) / sizeof(methods[0]);
00103   ink_assert(nmethods <= 32);
00104 
00105   char *p;
00106   int i, is_supported;
00107   size_t bytes = 0;
00108   int num_methods_supported = 0;
00109   MIMEField *field;
00110 
00111   
00112   for (i = 0; i < nmethods; i++) {
00113     const char *method_wks = methods[i];
00114     ink_assert(hdrtoken_is_wks(method_wks));
00115 
00116     is_supported = is_this_method_supported(scheme, hdrtoken_wks_to_index(method_wks));
00117 
00118     if (is_supported) {
00119       ++num_methods_supported;
00120       method_output_lengths[i] = hdrtoken_wks_to_length(method_wks);
00121       bytes += method_output_lengths[i];
00122       if (num_methods_supported > 1)
00123         bytes += 2;             
00124     } else {
00125       method_output_lengths[i] = 0;
00126     }
00127   }
00128 
00129   
00130   field = response->field_find(MIME_FIELD_ALLOW, MIME_LEN_ALLOW);
00131   if (!field) {
00132     field = response->field_create(MIME_FIELD_ALLOW, MIME_LEN_ALLOW);
00133     response->field_attach(field);
00134   }
00135   
00136   if (bytes <= sizeof(inline_buffer)) {
00137     alloced_buffer = NULL;
00138     value_buffer = inline_buffer;
00139   } else {
00140     alloced_buffer = (char *)ats_malloc(bytes);
00141     value_buffer = alloced_buffer;
00142   }
00143 
00144   
00145   p = value_buffer;
00146   for (i = 0; i < nmethods; i++) {
00147     if (method_output_lengths[i]) {
00148       memcpy(p, methods[i], method_output_lengths[i]);
00149       p += method_output_lengths[i];
00150       if (num_methods_supported > 1) {
00151         *p++ = ',';
00152         *p++ = ' ';
00153       }
00154       --num_methods_supported;
00155     }
00156   }
00157 
00158   
00159 
00160   
00161   field->value_append(response->m_heap, response->m_mime, value_buffer, bytes);
00162 
00163   
00164   ats_free(alloced_buffer);
00165 }
00166 
00167 
00168 void
00169 HttpTransactHeaders::build_base_response(HTTPHdr *outgoing_response,
00170                                          HTTPStatus status,
00171                                          const char *reason_phrase, int reason_phrase_len, ink_time_t date)
00172 {
00173   if (!outgoing_response->valid()) {
00174     outgoing_response->create(HTTP_TYPE_RESPONSE);
00175   }
00176 
00177   ink_assert(outgoing_response->type_get() == HTTP_TYPE_RESPONSE);
00178 
00179   outgoing_response->version_set(HTTPVersion(1, 1));
00180   outgoing_response->status_set(status);
00181   outgoing_response->reason_set(reason_phrase, reason_phrase_len);
00182   outgoing_response->set_date(date);
00183 }
00184 
00185 
00186 
00187 
00188 
00189 
00190 void
00191 HttpTransactHeaders::copy_header_fields(HTTPHdr *src_hdr,
00192                                         HTTPHdr *new_hdr, bool retain_proxy_auth_hdrs, ink_time_t date)
00193 {
00194   ink_assert(src_hdr->valid());
00195   ink_assert(!new_hdr->valid());
00196 
00197   MIMEField *field;
00198   MIMEFieldIter field_iter;
00199   bool date_hdr = false;
00200 
00201   
00202   new_hdr->copy(src_hdr);
00203 
00204   
00205   
00206   
00207   
00208   
00209   
00210   
00211   
00212   
00213   
00214   
00215   
00216   
00217   
00218 
00219   for (field = new_hdr->iter_get_first(&field_iter); field != NULL; field = new_hdr->iter_get_next(&field_iter)) {
00220     if (field->m_wks_idx == -1)
00221       continue;
00222 
00223     int field_flags = hdrtoken_index_to_flags(field->m_wks_idx);
00224 
00225     if (field_flags & MIME_FLAGS_HOPBYHOP) {
00226       
00227       if ((!retain_proxy_auth_hdrs) || (!(field_flags & MIME_FLAGS_PROXYAUTH))) {
00228         new_hdr->field_delete(field);
00229       }
00230     } else if (field->m_wks_idx == MIME_WKSIDX_DATE) {
00231       date_hdr = true;
00232     }
00233   }
00234 
00235   
00236   if ((date_hdr == false) && (date > 0))
00237     new_hdr->set_date(date);
00238 }
00239 
00240 
00241 
00242 
00243 void
00244 HttpTransactHeaders::convert_request(HTTPVersion outgoing_ver, HTTPHdr *outgoing_request)
00245 {
00246   if (outgoing_ver == HTTPVersion(1, 0)) {
00247     convert_to_1_0_request_header(outgoing_request);
00248   } else if (outgoing_ver == HTTPVersion(1, 1)) {
00249     convert_to_1_1_request_header(outgoing_request);
00250   } else if (outgoing_ver == HTTPVersion(0, 9)) {
00251     
00252     
00253     convert_to_0_9_request_header(outgoing_request);
00254   } else {
00255     Debug("http_trans", "[HttpTransactHeaders::convert_request]" "Unsupported Version - passing through");
00256   }
00257 }
00258 
00259 
00260 
00261 void
00262 HttpTransactHeaders::convert_response(HTTPVersion outgoing_ver, HTTPHdr *outgoing_response)
00263 {
00264   if (outgoing_ver == HTTPVersion(1, 0)) {
00265     convert_to_1_0_response_header(outgoing_response);
00266   } else if (outgoing_ver == HTTPVersion(1, 1)) {
00267     convert_to_1_1_response_header(outgoing_response);
00268   } else if (outgoing_ver == HTTPVersion(0, 9)) {
00269     
00270     
00271     convert_to_0_9_response_header(outgoing_response);
00272   } else {
00273     Debug("http_trans", "[HttpTransactHeaders::convert_response]" "Unsupported Version - passing through");
00274   }
00275 }
00276 
00277 
00278 
00279 
00280 void
00281 HttpTransactHeaders::convert_to_0_9_request_header(HTTPHdr *outgoing_request)
00282 {
00283   
00284   ink_assert(outgoing_request->method_get_wksidx() == HTTP_WKSIDX_GET);
00285   ink_assert(outgoing_request->url_get()->valid());
00286 
00287   outgoing_request->version_set(HTTPVersion(0, 9));
00288 
00289   
00290   outgoing_request->fields_clear();
00291 }
00292 
00293 
00294 
00295 
00296 void
00297 HttpTransactHeaders::convert_to_1_0_request_header(HTTPHdr *outgoing_request)
00298 {
00299   
00300   ink_assert(outgoing_request->url_get()->valid());
00301 
00302   
00303   outgoing_request->version_set(HTTPVersion(1, 0));
00304 
00305   
00306   
00307 
00308   if (outgoing_request->presence(MIME_PRESENCE_CACHE_CONTROL) && !outgoing_request->is_pragma_no_cache_set()) {
00309     outgoing_request->value_append(MIME_FIELD_PRAGMA, MIME_LEN_PRAGMA, "no-cache", 8, true);
00310   }
00311   
00312   
00313   
00314   
00315 }
00316 
00317 
00318 
00319 
00320 void
00321 HttpTransactHeaders::convert_to_1_1_request_header(HTTPHdr *outgoing_request)
00322 {
00323 
00324   
00325   ink_assert(outgoing_request->url_get()->valid());
00326   ink_assert(outgoing_request->version_get() == HTTPVersion(1, 1));
00327 
00328   if (outgoing_request->get_cooked_pragma_no_cache() &&
00329       !(outgoing_request->get_cooked_cc_mask() & MIME_COOKED_MASK_CC_NO_CACHE)) {
00330     outgoing_request->value_append(MIME_FIELD_CACHE_CONTROL, MIME_LEN_CACHE_CONTROL, "no-cache", 8, true);
00331   }
00332   
00333   
00334   
00335   
00336 }
00337 
00338 
00339 
00340 
00341 void
00342 HttpTransactHeaders::convert_to_0_9_response_header(HTTPHdr * )
00343 {
00344   
00345 
00346   
00347   
00348   
00349   
00350   
00351 }
00352 
00353 
00354 
00355 
00356 void
00357 HttpTransactHeaders::convert_to_1_0_response_header(HTTPHdr *outgoing_response)
00358 {
00359 
00360 
00361 
00362 
00363   
00364   outgoing_response->version_set(HTTPVersion(1, 0));
00365 
00366   
00367 
00368   
00369 }
00370 
00371 
00372 
00373 
00374 void
00375 HttpTransactHeaders::convert_to_1_1_response_header(HTTPHdr *outgoing_response)
00376 {
00377   
00378   ink_assert(outgoing_response->status_get());
00379 
00380   
00381 
00382   outgoing_response->version_set(HTTPVersion(1, 1));
00383 }
00384 
00385 
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00397 ink_time_t
00398 HttpTransactHeaders::calculate_document_age(ink_time_t request_time,
00399                                             ink_time_t response_time,
00400                                             HTTPHdr *base_response, ink_time_t base_response_date, ink_time_t now)
00401 {
00402   ink_time_t age_value = base_response->get_age();
00403   ink_time_t date_value = 0;
00404   ink_time_t apparent_age = 0;
00405   ink_time_t corrected_received_age = 0;
00406   ink_time_t response_delay = 0;
00407   ink_time_t corrected_initial_age = 0;
00408   ink_time_t current_age = 0;
00409   ink_time_t resident_time = 0;
00410   ink_time_t now_value = 0;
00411 
00412   ink_time_t tmp_value = 0;
00413 
00414   tmp_value = base_response_date;
00415   date_value = (tmp_value > 0) ? tmp_value : 0;
00416 
00417   
00418   
00419   
00420   now_value = max(now, response_time);
00421 
00422   ink_assert(response_time >= 0);
00423   ink_assert(request_time >= 0);
00424   ink_assert(response_time >= request_time);
00425   ink_assert(now_value >= response_time);
00426 
00427   if (date_value > 0) {
00428     apparent_age = max((time_t) 0, (response_time - date_value));
00429   }
00430   if (age_value < 0) {
00431     current_age = -1; 
00432   } else {
00433     corrected_received_age = max(apparent_age, age_value);
00434     response_delay = response_time - request_time;
00435     corrected_initial_age = corrected_received_age + response_delay;
00436     resident_time = now_value - response_time;
00437     current_age = corrected_initial_age + resident_time;
00438   }
00439 
00440   Debug("http_age", "[calculate_document_age] age_value:              %" PRId64, (int64_t)age_value);
00441   Debug("http_age", "[calculate_document_age] date_value:             %" PRId64, (int64_t)date_value);
00442   Debug("http_age", "[calculate_document_age] response_time:          %" PRId64, (int64_t)response_time);
00443   Debug("http_age", "[calculate_document_age] now:                    %" PRId64, (int64_t)now);
00444   Debug("http_age", "[calculate_document_age] now (fixed):            %" PRId64, (int64_t)now_value);
00445   Debug("http_age", "[calculate_document_age] apparent_age:           %" PRId64, (int64_t)apparent_age);
00446   Debug("http_age", "[calculate_document_age] corrected_received_age: %" PRId64, (int64_t)corrected_received_age);
00447   Debug("http_age", "[calculate_document_age] response_delay:         %" PRId64, (int64_t)response_delay);
00448   Debug("http_age", "[calculate_document_age] corrected_initial_age:  %" PRId64, (int64_t)corrected_initial_age);
00449   Debug("http_age", "[calculate_document_age] resident_time:          %" PRId64, (int64_t)resident_time);
00450   Debug("http_age", "[calculate_document_age] current_age:            %" PRId64, (int64_t)current_age);
00451 
00452   return current_age;
00453 }
00454 
00455 
00456 bool
00457 HttpTransactHeaders::does_server_allow_response_to_be_stored(HTTPHdr *resp)
00458 {
00459   uint32_t cc_mask = (MIME_COOKED_MASK_CC_NO_CACHE | MIME_COOKED_MASK_CC_NO_STORE | MIME_COOKED_MASK_CC_PRIVATE);
00460 
00461   if ((resp->get_cooked_cc_mask() & cc_mask) || (resp->get_cooked_pragma_no_cache()))
00462     return false;
00463   else
00464     return true;
00465 }
00466 
00467 
00468 bool
00469 HttpTransactHeaders::downgrade_request(bool *origin_server_keep_alive, HTTPHdr *outgoing_request)
00470 {
00471   
00472   
00473   if (*origin_server_keep_alive) {
00474 
00475     *origin_server_keep_alive = false;
00476     
00477 
00478   }
00479 
00480   if (outgoing_request->version_get() == HTTPVersion(1, 1)) {
00481 
00482     
00483     convert_to_1_0_request_header(outgoing_request);
00484 
00485     
00486   } else if (outgoing_request->version_get() == HTTPVersion(1, 0) &&
00487              outgoing_request->method_get_wksidx() == HTTP_WKSIDX_GET) {
00488 
00489     
00490     convert_to_0_9_request_header(outgoing_request);
00491 
00492   } else {
00493     return false;
00494   }
00495 
00496   return true;
00497 }
00498 
00499 void
00500 HttpTransactHeaders::generate_and_set_squid_codes(HTTPHdr *header,
00501                                                  char *via_string,
00502                                                  HttpTransact::SquidLogInfo *squid_codes)
00503 {
00504   SquidLogCode log_code;
00505   SquidHierarchyCode hier_code;
00506   SquidHitMissCode hit_miss_code;
00507 
00508 
00509   
00510 
00511   if ((via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_HIT_CONDITIONAL) ||
00512       (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_MISS_CONDITIONAL) ||
00513       (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_HIT_SERVED)) {
00514     
00515     
00516     hit_miss_code = SQUID_HIT_RESERVED;
00517   } else {
00518     int reason_len;
00519     const char *reason = header->reason_get(&reason_len);
00520     
00521     if (reason != NULL && reason_len >= 24 && reason[0] == '!' && reason[1] == SQUID_HIT_RESERVED)
00522       hit_miss_code = SQUID_HIT_RESERVED;
00523     
00524     else if (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_MISS_EXPIRED) {
00525       hit_miss_code = SQUID_MISS_PRE_EXPIRED;
00526     } else if (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_MISS_CONFIG) {
00527       hit_miss_code = SQUID_MISS_NONE;
00528     } else if (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_MISS_CLIENT) {
00529       hit_miss_code = SQUID_MISS_PRAGMA_NOCACHE;
00530     } else if (via_string[VIA_DETAIL_CACHE_LOOKUP] == VIA_DETAIL_MISS_METHOD) {
00531       hit_miss_code = SQUID_MISS_HTTP_NON_CACHE;
00532     } else if (via_string[VIA_CLIENT_REQUEST] == VIA_CLIENT_ERROR) {
00533       hit_miss_code = SQUID_MISS_ERROR;
00534     } else if (via_string[VIA_CLIENT_REQUEST] == VIA_CLIENT_NO_CACHE) {
00535       hit_miss_code = SQUID_MISS_PRAGMA_NOCACHE;
00536     } else {
00537       hit_miss_code = SQUID_MISS_NONE;
00538     }
00539   }
00540 
00541 
00542   
00543 
00544   if (via_string[VIA_CLIENT_REQUEST] == VIA_CLIENT_NO_CACHE) {
00545     log_code = SQUID_LOG_TCP_CLIENT_REFRESH;
00546   }
00547 
00548   else {
00549     if (via_string[VIA_CLIENT_REQUEST] == VIA_CLIENT_IMS) {
00550       if ((via_string[VIA_CACHE_RESULT] == VIA_IN_CACHE_FRESH) ||
00551           (via_string[VIA_CACHE_RESULT] == VIA_IN_RAM_CACHE_FRESH)) {
00552         log_code = SQUID_LOG_TCP_IMS_HIT;
00553       } else {
00554         if (via_string[VIA_SERVER_RESULT] == VIA_SERVER_NOT_MODIFIED) {
00555           log_code = SQUID_LOG_TCP_REFRESH_HIT;
00556         } else {
00557           log_code = SQUID_LOG_TCP_IMS_MISS;
00558         }
00559       }
00560     }
00561 
00562     else {
00563       if (via_string[VIA_CACHE_RESULT] == VIA_IN_CACHE_STALE) {
00564         if (via_string[VIA_SERVER_RESULT] == VIA_SERVER_NOT_MODIFIED) {
00565           log_code = SQUID_LOG_TCP_REFRESH_HIT;
00566         } else {
00567           if (via_string[VIA_SERVER_RESULT] == VIA_SERVER_ERROR) {
00568             log_code = SQUID_LOG_TCP_REF_FAIL_HIT;
00569           } else {
00570             log_code = SQUID_LOG_TCP_REFRESH_MISS;
00571           }
00572         }
00573       } else {
00574         if (via_string[VIA_CACHE_RESULT] == VIA_IN_CACHE_FRESH) {
00575           log_code = SQUID_LOG_TCP_HIT;
00576         } else if (via_string[VIA_CACHE_RESULT] == VIA_IN_RAM_CACHE_FRESH) {
00577           log_code = SQUID_LOG_TCP_MEM_HIT;
00578         } else {
00579           log_code = SQUID_LOG_TCP_MISS;
00580         }
00581       }
00582     }
00583   }
00584 
00585 
00586   
00587 
00588   if ((via_string[VIA_CACHE_RESULT] == VIA_IN_CACHE_FRESH) || (via_string[VIA_CACHE_RESULT] == VIA_IN_RAM_CACHE_FRESH)) {
00589     hier_code = SQUID_HIER_NONE;
00590   } else if (via_string[VIA_DETAIL_ICP_CONNECT] == VIA_DETAIL_ICP_SUCCESS) {
00591     hier_code = SQUID_HIER_SIBLING_HIT;
00592   } else if (via_string[VIA_DETAIL_PP_CONNECT] == VIA_DETAIL_PP_SUCCESS) {
00593     hier_code = SQUID_HIER_PARENT_HIT;
00594   } else if (via_string[VIA_DETAIL_CACHE_TYPE] == VIA_DETAIL_PARENT) {
00595     hier_code = SQUID_HIER_DEFAULT_PARENT;
00596   } else if (via_string[VIA_DETAIL_TUNNEL] == VIA_DETAIL_TUNNEL_NO_FORWARD) {
00597     hier_code = SQUID_HIER_NONE;
00598   } else {
00599     hier_code = SQUID_HIER_DIRECT;
00600   }
00601 
00602   
00603   switch (via_string[VIA_ERROR_TYPE]) {
00604   case VIA_ERROR_AUTHORIZATION:
00605     
00606     
00607     log_code = SQUID_LOG_ERR_PROXY_DENIED;
00608     break;
00609   case VIA_ERROR_CONNECTION:
00610     if (log_code == SQUID_LOG_TCP_MISS) {
00611       log_code = SQUID_LOG_ERR_CONNECT_FAIL;
00612     }
00613     break;
00614   case VIA_ERROR_DNS_FAILURE:
00615     log_code = SQUID_LOG_ERR_DNS_FAIL;
00616     hier_code = SQUID_HIER_NONE;
00617     break;
00618   case VIA_ERROR_FORBIDDEN:
00619     log_code = SQUID_LOG_ERR_PROXY_DENIED;
00620     break;
00621   case VIA_ERROR_HEADER_SYNTAX:
00622     log_code = SQUID_LOG_ERR_INVALID_REQ;
00623     hier_code = SQUID_HIER_NONE;
00624     break;
00625   case VIA_ERROR_SERVER:
00626     if (log_code == SQUID_LOG_TCP_MISS || log_code == SQUID_LOG_TCP_IMS_MISS) {
00627       log_code = SQUID_LOG_ERR_CONNECT_FAIL;
00628     }
00629     break;
00630   case VIA_ERROR_TIMEOUT:
00631     if (log_code == SQUID_LOG_TCP_MISS || log_code == SQUID_LOG_TCP_IMS_MISS) {
00632       log_code = SQUID_LOG_ERR_READ_TIMEOUT;
00633     }
00634     if (hier_code == SQUID_HIER_SIBLING_HIT) {
00635       hier_code = SQUID_HIER_TIMEOUT_SIBLING_HIT;
00636     } else if (hier_code == SQUID_HIER_PARENT_HIT) {
00637       hier_code = SQUID_HIER_TIMEOUT_PARENT_HIT;
00638     } else {
00639       hier_code = SQUID_HIER_TIMEOUT_DIRECT;
00640     }
00641     break;
00642   case VIA_ERROR_CACHE_READ:
00643     log_code = SQUID_LOG_TCP_SWAPFAIL;
00644     hier_code = SQUID_HIER_NONE;
00645     break;
00646   default:
00647     break;
00648   }
00649 
00650   Debug("http_trans",
00651         "[Squid code generation] Hit/Miss: %d, Log: %d, Hier: %d",
00652         hit_miss_code, log_code, hier_code);
00653   squid_codes->log_code = log_code;
00654   squid_codes->hier_code = hier_code;
00655   squid_codes->hit_miss_code = hit_miss_code;
00656 }
00657 
00658 #include "HttpDebugNames.h"
00659 
00660 void
00661 HttpTransactHeaders::insert_warning_header(HttpConfigParams *http_config_param, HTTPHdr *header, HTTPWarningCode code,
00662                                            const char *warn_text, int warn_text_len)
00663 {
00664   int bufsize, len;
00665 
00666   
00667   
00668   bufsize = http_config_param->proxy_response_via_string_len + 23;
00669   if (warn_text != NULL)
00670     bufsize += warn_text_len;
00671   else
00672     warn_text_len = 0; 
00673 
00674   char *warning_text = (char *)alloca(bufsize);
00675 
00676   len = snprintf(warning_text, bufsize, "%3d %s %.*s", code, http_config_param->proxy_response_via_string, warn_text_len, warn_text);
00677   header->value_set(MIME_FIELD_WARNING, MIME_LEN_WARNING, warning_text, len);
00678 }
00679 
00680 
00681 void
00682 HttpTransactHeaders::insert_time_and_age_headers_in_response(ink_time_t request_sent_time,
00683                                                              ink_time_t response_received_time,
00684                                                              ink_time_t now, HTTPHdr *base, HTTPHdr *outgoing)
00685 {
00686   ink_time_t date = base->get_date();
00687   ink_time_t current_age = calculate_document_age(request_sent_time, response_received_time, base, date, now);
00688 
00689   outgoing->set_age(current_age); 
00690 
00691   
00692   
00693   if (date <= 0)
00694     outgoing->set_date(now);
00695 }
00696 
00697 
00698 void
00699 HttpTransactHeaders::insert_server_header_in_response(const char *server_tag, int server_tag_size, HTTPHdr *h)
00700 {
00701   if (likely(server_tag && server_tag_size > 0 && h)) {
00702     h->set_server(server_tag, server_tag_size);
00703   }
00704 }
00705 
00706 
00707 
00708 
00709 
00710 
00711 
00712 
00713 
00714 
00715 
00716 
00717 
00718 
00719 
00720 
00721 
00722 
00723 
00724 
00725 
00726 
00727 
00728 
00729 
00730 
00731 
00732 
00733 
00734 
00735 
00736 
00737 
00738 
00739 
00740 
00741 
00742 
00743 
00744 
00745 
00746 
00747 
00748 
00749 
00750 
00751 void
00752 HttpTransactHeaders::insert_via_header_in_request(HttpTransact::State *s, HTTPHdr *header)
00753 {
00754   char new_via_string[1024]; 
00755   char *via_string = new_via_string;
00756 
00757   if ((s->http_config_param->proxy_hostname_len + s->http_config_param->proxy_request_via_string_len) > 512) {
00758     header->value_append(MIME_FIELD_VIA, MIME_LEN_VIA, "TrafficServer", 13, true);
00759     return;
00760   }
00761 
00762   char *incoming_via = s->via_string;
00763   int scheme = s->orig_scheme;
00764   ink_assert(scheme >= 0);
00765 
00766   int scheme_len = hdrtoken_index_to_length(scheme);
00767   int32_t hversion = header->version_get().m_version;
00768 
00769   memcpy(via_string, hdrtoken_index_to_wks(scheme), scheme_len);
00770   via_string += scheme_len;
00771 
00772   
00773   if ((HTTP_MAJOR(hversion) == 1) && HTTP_MINOR(hversion) == 1) {
00774     memcpy(via_string, "/1.1 ", 5);
00775     via_string += 5;
00776   } else {
00777     *via_string++ = '/';
00778     *via_string++ = '0' + HTTP_MAJOR(hversion);
00779     *via_string++ = '.';
00780     *via_string++ = '0' + HTTP_MINOR(hversion);
00781     *via_string++ = ' ';
00782   }
00783   via_string += nstrcpy(via_string, s->http_config_param->proxy_hostname);
00784 
00785   *via_string++ = '[';
00786   
00787 
00788 
00789 
00790   memcpy(via_string, Machine::instance()->ip_hex_string, Machine::instance()->ip_hex_string_len);
00791   via_string += Machine::instance()->ip_hex_string_len;
00792   *via_string++ = ']';
00793   *via_string++ = ' ';
00794   *via_string++ = '(';
00795 
00796   memcpy(via_string, s->http_config_param->proxy_request_via_string, s->http_config_param->proxy_request_via_string_len);
00797   via_string += s->http_config_param->proxy_request_via_string_len;
00798 
00799   if (s->txn_conf->insert_request_via_string > 1) {
00800     *via_string++ = ' ';
00801     *via_string++ = '[';
00802 
00803     
00804     if (s->txn_conf->insert_request_via_string > 2) { 
00805       via_string += nstrcpy(via_string, incoming_via);
00806     } else {
00807       memcpy(via_string, incoming_via + VIA_CLIENT, VIA_SERVER - VIA_CLIENT);
00808       via_string += VIA_SERVER - VIA_CLIENT;
00809     }
00810     *via_string++ = ']';
00811   }
00812 
00813   *via_string++ = ')';
00814   *via_string = 0;
00815 
00816   ink_assert((size_t)(via_string - new_via_string) < (sizeof(new_via_string) - 1));
00817   header->value_append(MIME_FIELD_VIA, MIME_LEN_VIA, new_via_string, via_string - new_via_string, true);
00818 }
00819 
00820 void
00821 HttpTransactHeaders::insert_hsts_header_in_response(HttpTransact::State *s, HTTPHdr *header)
00822 {
00823   char new_hsts_string[64];
00824   char *hsts_string = new_hsts_string;
00825   const char include_subdomains[] = "; includeSubDomains";
00826 
00827   
00828   int length = snprintf(new_hsts_string, sizeof(new_hsts_string), "max-age=%" PRId64, s->txn_conf->proxy_response_hsts_max_age);
00829 
00830   
00831   if (s->txn_conf->proxy_response_hsts_include_subdomains) {
00832     hsts_string += length;
00833     memcpy(hsts_string, include_subdomains, sizeof(include_subdomains));
00834     length += sizeof(include_subdomains);
00835   }
00836 
00837   header->value_set(MIME_FIELD_STRICT_TRANSPORT_SECURITY, MIME_LEN_STRICT_TRANSPORT_SECURITY, new_hsts_string, length);
00838 }
00839 
00840 void
00841 HttpTransactHeaders::insert_via_header_in_response(HttpTransact::State *s, HTTPHdr *header)
00842 {
00843   char new_via_string[1024]; 
00844   char *via_string = new_via_string;
00845 
00846   if ((s->http_config_param->proxy_hostname_len + s->http_config_param->proxy_response_via_string_len) > 512) {
00847     header->value_append(MIME_FIELD_VIA, MIME_LEN_VIA, "TrafficServer", 13, true);
00848     return;
00849   }
00850 
00851   char *incoming_via =  s->via_string;
00852   int scheme = s->next_hop_scheme;
00853 
00854   ink_assert(scheme >= 0);
00855   int scheme_len = hdrtoken_index_to_length(scheme);
00856   int32_t hversion = header->version_get().m_version;
00857 
00858   memcpy(via_string, hdrtoken_index_to_wks(scheme), scheme_len);
00859   via_string += scheme_len;
00860 
00861   
00862   if ((HTTP_MAJOR(hversion) == 1) && HTTP_MINOR(hversion) == 1) {
00863     memcpy(via_string, "/1.1 ", 5);
00864     via_string += 5;
00865   } else {
00866     *via_string++ = '/';
00867     *via_string++ = '0' + HTTP_MAJOR(hversion);
00868     *via_string++ = '.';
00869     *via_string++ = '0' + HTTP_MINOR(hversion);
00870     *via_string++ = ' ';
00871   }
00872   via_string += nstrcpy(via_string, s->http_config_param->proxy_hostname);
00873   *via_string++ = ' ';
00874   *via_string++ = '(';
00875 
00876   memcpy(via_string, s->http_config_param->proxy_response_via_string, s->http_config_param->proxy_response_via_string_len);
00877   via_string += s->http_config_param->proxy_response_via_string_len;
00878 
00879   if (s->txn_conf->insert_response_via_string > 1) {
00880     *via_string++ = ' ';
00881     *via_string++ = '[';
00882 
00883     
00884     if (s->txn_conf->insert_response_via_string > 2) { 
00885       via_string += nstrcpy(via_string, incoming_via);
00886     } else {
00887       memcpy(via_string, incoming_via + VIA_CACHE, VIA_PROXY - VIA_CACHE);
00888       via_string += VIA_PROXY - VIA_CACHE;
00889     }
00890     *via_string++ = ']';
00891   }
00892 
00893   *via_string++ = ')';
00894   *via_string = 0;
00895 
00896   ink_assert((size_t)(via_string - new_via_string) < (sizeof(new_via_string) - 1));
00897   header->value_append(MIME_FIELD_VIA, MIME_LEN_VIA, new_via_string, via_string - new_via_string, true);
00898 }
00899 
00900 
00901 
00902 
00903 
00904 
00905 
00906 
00907 void
00908 HttpTransactHeaders::insert_basic_realm_in_proxy_authenticate(const char *realm, HTTPHdr *header, bool bRevPrxy)
00909 {
00910   char new_basic_realm[128];
00911   char *basic_realm;
00912 
00913   basic_realm = new_basic_realm;
00914   basic_realm += nstrcpy(basic_realm, "Basic realm=\"");
00915   basic_realm += nstrcpy(basic_realm, (char *) realm);
00916   *basic_realm++ = '"';
00917   *basic_realm = 0;
00918 
00919   MIMEField *auth;
00920   if (false == bRevPrxy) {
00921     auth = header->field_create(MIME_FIELD_PROXY_AUTHENTICATE, MIME_LEN_PROXY_AUTHENTICATE);
00922   } else {
00923     auth = header->field_create(MIME_FIELD_WWW_AUTHENTICATE, MIME_LEN_WWW_AUTHENTICATE);
00924   }
00925 
00926   header->field_value_set(auth, new_basic_realm, strlen(new_basic_realm));
00927   header->field_attach(auth);
00928 }
00929 
00930 
00931 void
00932 HttpTransactHeaders::remove_conditional_headers(HTTPHdr *outgoing)
00933 {
00934   if (outgoing->presence(MIME_PRESENCE_IF_MODIFIED_SINCE | MIME_PRESENCE_IF_UNMODIFIED_SINCE |
00935                          MIME_PRESENCE_IF_MATCH | MIME_PRESENCE_IF_NONE_MATCH)) {
00936 
00937     outgoing->field_delete(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE);
00938     outgoing->field_delete(MIME_FIELD_IF_UNMODIFIED_SINCE, MIME_LEN_IF_UNMODIFIED_SINCE);
00939     outgoing->field_delete(MIME_FIELD_IF_MATCH, MIME_LEN_IF_MATCH);
00940     outgoing->field_delete(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH);
00941   }
00942   
00943 }
00944 
00945 void
00946 HttpTransactHeaders::remove_100_continue_headers(HttpTransact::State *s, HTTPHdr *outgoing)
00947 {
00948   int len = 0;
00949   const char *expect = s->hdr_info.client_request.value_get(MIME_FIELD_EXPECT, MIME_LEN_EXPECT, &len);
00950 
00951   if ((len == HTTP_LEN_100_CONTINUE) && (strncasecmp(expect, HTTP_VALUE_100_CONTINUE, HTTP_LEN_100_CONTINUE) == 0)) {
00952     outgoing->field_delete(MIME_FIELD_EXPECT, MIME_LEN_EXPECT);
00953   }
00954 }
00955 
00956 
00957 
00958 
00959 
00960 void
00961 HttpTransactHeaders::remove_host_name_from_url(HTTPHdr *outgoing_request)
00962 {
00963   URL *outgoing_url = outgoing_request->url_get();
00964   outgoing_url->nuke_proxy_stuff();
00965 }
00966 
00967 
00968 void
00969 HttpTransactHeaders::add_global_user_agent_header_to_request(OverridableHttpConfigParams *http_txn_conf, HTTPHdr *header)
00970 {
00971   if (http_txn_conf->global_user_agent_header) {
00972     MIMEField *ua_field;
00973 
00974     Debug("http_trans", "Adding User-Agent: %s", http_txn_conf->global_user_agent_header);
00975     if ((ua_field = header->field_find(MIME_FIELD_USER_AGENT, MIME_LEN_USER_AGENT)) == NULL) {
00976       if (likely((ua_field = header->field_create(MIME_FIELD_USER_AGENT, MIME_LEN_USER_AGENT)) != NULL))
00977         header->field_attach(ua_field);
00978     }
00979     
00980     if (likely(ua_field))
00981       header->field_value_set(ua_field, http_txn_conf->global_user_agent_header,
00982                               http_txn_conf->global_user_agent_header_size);
00983   }
00984 }
00985 
00986 
00987 void
00988 HttpTransactHeaders::add_server_header_to_response(OverridableHttpConfigParams *http_txn_conf, HTTPHdr *header)
00989 {
00990   if (http_txn_conf->proxy_response_server_enabled && http_txn_conf->proxy_response_server_string) {
00991     MIMEField *ua_field;
00992     bool do_add = true;
00993 
00994     if ((ua_field = header->field_find(MIME_FIELD_SERVER, MIME_LEN_SERVER)) == NULL) {
00995       if (likely((ua_field = header->field_create(MIME_FIELD_SERVER, MIME_LEN_SERVER)) != NULL))
00996         header->field_attach(ua_field);
00997     } else {
00998       
00999       do_add = (1 == http_txn_conf->proxy_response_server_enabled);
01000     }
01001 
01002     
01003     if (do_add && likely(ua_field)) {
01004       Debug("http_trans", "Adding Server: %s", http_txn_conf->proxy_response_server_string);
01005       header->field_value_set(ua_field, http_txn_conf->proxy_response_server_string, http_txn_conf->proxy_response_server_string_len);
01006     }
01007   }
01008 }
01009 
01010 
01011 void
01012 HttpTransactHeaders::remove_privacy_headers_from_request(HttpConfigParams *http_config_param,
01013                                                          OverridableHttpConfigParams *http_txn_conf, HTTPHdr *header)
01014 {
01015   if (!header)
01016     return;
01017 
01018   
01019   if (http_txn_conf->anonymize_remove_from) {
01020     Debug("anon", "removing 'From' headers");
01021     header->field_delete(MIME_FIELD_FROM, MIME_LEN_FROM);
01022   }
01023   
01024   if (http_txn_conf->anonymize_remove_referer) {
01025     Debug("anon", "removing 'Referer' headers");
01026     header->field_delete(MIME_FIELD_REFERER, MIME_LEN_REFERER);
01027   }
01028   
01029   if (http_txn_conf->anonymize_remove_user_agent) {
01030     Debug("anon", "removing 'User-agent' headers");
01031     header->field_delete(MIME_FIELD_USER_AGENT, MIME_LEN_USER_AGENT);
01032   }
01033   
01034   if (http_txn_conf->anonymize_remove_cookie) {
01035     Debug("anon", "removing 'Cookie' headers");
01036     header->field_delete(MIME_FIELD_COOKIE, MIME_LEN_COOKIE);
01037   }
01038   
01039   if (http_txn_conf->anonymize_remove_client_ip) {
01040     Debug("anon", "removing 'Client-ip' headers");
01041     header->field_delete(MIME_FIELD_CLIENT_IP, MIME_LEN_CLIENT_IP);
01042   }
01043 
01044   
01045 
01046 
01047   
01048   
01049   if (http_config_param->anonymize_other_header_list) {
01050     Str *field;
01051     StrList anon_list(false);
01052     const char *anon_string;
01053 
01054     anon_string = http_config_param->anonymize_other_header_list;
01055     Debug("anon", "removing other headers (%s)", anon_string);
01056     HttpCompat::parse_comma_list(&anon_list, anon_string);
01057     for (field = anon_list.head; field != NULL; field = field->next) {
01058       Debug("anon", "removing '%s' headers", field->str);
01059       header->field_delete(field->str, field->len);
01060     }
01061   }
01062 }