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 }