int errorMapStart(const errormap * map, request_t * client_req, HttpReply * reply, const char *aclname, ERRMAPCB * callback, void *callback_data) { char squid_error[100]; int len = 0; const char *errorUrl; ErrorMapState *state; const char *tmp; http_status status; request_t *req; HttpHeaderPos hdrpos; HttpHeaderEntry *hdr; if (!client_req || !reply) return 0; status = reply->sline.status; tmp = httpHeaderGetStr(&reply->header, HDR_X_SQUID_ERROR); squid_error[0] = '\0'; if (tmp) { xstrncpy(squid_error, tmp, sizeof(squid_error)); len = strcspn(squid_error, " "); } squid_error[len] = '\0'; errorUrl = getErrorMap(map, status, squid_error, aclname); if (!errorUrl) return 0; req = urlParse(urlMethodGetKnownByCode(METHOD_GET), (char *) errorUrl); if (!req) { debug(0, 0) ("errorMapStart: Invalid error URL '%s'\n", errorUrl); return 0; } req->urlgroup = xstrdup("error"); state = cbdataAlloc(ErrorMapState); state->req = requestLink(req); state->e = storeCreateEntry(errorUrl, req->flags, req->method); state->sc = storeClientRegister(state->e, state); state->callback = callback; state->callback_data = callback_data; cbdataLock(callback_data); hdrpos = HttpHeaderInitPos; while ((hdr = httpHeaderGetEntry(&client_req->header, &hdrpos)) != NULL) { if (CBIT_TEST(client_headers, hdr->id)) httpHeaderAddClone(&req->header, hdr); } hdrpos = HttpHeaderInitPos; while ((hdr = httpHeaderGetEntry(&reply->header, &hdrpos)) != NULL) { if (CBIT_TEST(server_headers, hdr->id)) httpHeaderAddClone(&req->header, hdr); } httpHeaderPutInt(&req->header, HDR_X_ERROR_STATUS, (int) reply->sline.status); httpHeaderPutStr(&req->header, HDR_X_REQUEST_URI, urlCanonical(client_req)); fwdStart(-1, state->e, req); storeClientRef(state->sc, state->e, 0, 0, SM_PAGE_SIZE, errorMapFetchHeaders, state); return 1; }
/* allocates and initializes an error response */ HttpReply * errorBuildReply(ErrorState * err) { HttpReply *rep = httpReplyCreate(); const char *name = errorPageName(err->page_id); /* no LMT for error pages; error pages expire immediately */ if (strchr(name, ':')) { /* Redirection */ httpReplySetHeaders(rep, HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, -1, -1); if (err->request) { char *quoted_url = rfc1738_escape_part(urlCanonical(err->request)); httpHeaderPutStrf(&rep->header, HDR_LOCATION, name, quoted_url); } httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%d %s", err->http_status, "Access Denied"); } else { MemBuf content = errorBuildContent(err); httpReplySetHeaders(rep, err->http_status, NULL, "text/html", content.size, -1, -1); /* * include some information for downstream caches. Implicit * replaceable content. This isn't quite sufficient. xerrno is not * necessarily meaningful to another system, so we really should * expand it. Additionally, we should identify ourselves. Someone * might want to know. Someone _will_ want to know OTOH, the first * X-CACHE-MISS entry should tell us who. */ httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%s %d", name, err->xerrno); httpBodySet(&rep->body, &content); /* do not memBufClean() the content, it was absorbed by httpBody */ } return rep; }
static void asyncPrefetchTs(const char *url) { debug(207, 1) ("start asyncPrefetchTs async prefetch: '%s'\n", url); request_t *request = NULL; StoreEntry *entry = NULL; request = modifyRequestUrlstoreUrl(url); request->flags.cachable = CACHE; if (storeGetPublicByRequest(request) != NULL) { debug(207, 3) ("this entry has already exist,give up async prefetch: '%s'\n", request->store_url); return; } entry = storeCreateEntry(urlCanonical(request), request->flags, request->method); if (request->store_url) storeEntrySetStoreUrl(entry, request->store_url); if(Config.onoff.collapsed_forwarding) { EBIT_SET(entry->flags, KEY_EARLY_PUBLIC); storeSetPublicKey(entry); } fwdStart(-1, entry, request); requestUnlink(request); }
static inline void modify_request(clientHttpRequest * http) { debug(97, 3)("modify_request: start, uri=[%s]\n", http->uri); request_t* old_request = http->request; request_t* new_request = urlParse(old_request->method, http->uri); safe_free(http->uri); if (new_request) { safe_free(http->uri); http->uri = xstrdup(urlCanonical(new_request)); if(!http->log_uri) http->log_uri = xstrdup(urlCanonicalClean(old_request)); new_request->http_ver = old_request->http_ver; httpHeaderAppend(&new_request->header, &old_request->header); new_request->client_addr = old_request->client_addr; new_request->client_port = old_request->client_port; #if FOLLOW_X_FORWARDED_FOR new_request->indirect_client_addr = old_request->indirect_client_addr; #endif /* FOLLOW_X_FORWARDED_FOR */ new_request->my_addr = old_request->my_addr; new_request->my_port = old_request->my_port; new_request->flags = old_request->flags; new_request->flags.redirected = 1; if (old_request->auth_user_request) { new_request->auth_user_request = old_request->auth_user_request; authenticateAuthUserRequestLock(new_request->auth_user_request); } if (old_request->body_reader) { new_request->body_reader = old_request->body_reader; new_request->body_reader_data = old_request->body_reader_data; old_request->body_reader = NULL; old_request->body_reader_data = NULL; } new_request->content_length = old_request->content_length; if (strBuf(old_request->extacl_log)) new_request->extacl_log = stringDup(&old_request->extacl_log); if (old_request->extacl_user) new_request->extacl_user = xstrdup(old_request->extacl_user); if (old_request->extacl_passwd) new_request->extacl_passwd = xstrdup(old_request->extacl_passwd); if(old_request->cc_request_private_data) { new_request->cc_request_private_data = old_request->cc_request_private_data; old_request->cc_request_private_data = NULL; } requestUnlink(old_request); http->request = requestLink(new_request); } }
static request_t * modifyRequestUrlstoreUrl(const char *url) { request_t *new_request = NULL; new_request = urlParse(METHOD_GET, (char*)url); char *new_storeurl = xstrdup((const char *)url); char* str = strchr(new_storeurl, '?'); if (str) { debug(207, 3)("modify_request_url_storeurl rid_question: storeurl=[%s] have question\n", new_storeurl); *str = '\0'; } new_request->store_url = xstrdup((const char *)new_storeurl); debug(207, 3)("after modifyRequestUrlstoreUrl url=%s,storeurl=%s,uri=%s\n",urlCanonical(new_request),new_request->store_url,strBuf(new_request->urlpath)); return requestLink(new_request); }
/* packs debug info, canonical request-line and headers, appends <crlf> terminator */ void httpRequestPackDebug(request_t * req, Packer * p) { assert(req && p); /* Client info */ packerPrintf(p, "Client: %s ", inet_ntoa(req->client_addr)); packerPrintf(p, "http_port: %s:%d", inet_ntoa(req->my_addr), req->my_port); if (req->auth_user_request && authenticateUserRequestUsername(req->auth_user_request)) packerPrintf(p, "user: %s", authenticateUserRequestUsername(req->auth_user_request)); packerPrintf(p, "\n"); /* pack request-line */ packerPrintf(p, "%s %s HTTP/%d.%d\r\n", RequestMethodStr[req->method], urlCanonical(req), req->http_ver.major, req->http_ver.minor); /* headers */ httpHeaderPackInto(&req->header, p); /* trailer */ packerAppend(p, "\r\n", 2); }
peer * carpSelectParent(request_t * request) { #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> ((sizeof(u_long)*8)-(n)))) const char *c; peer *p = NULL; peer *tp; unsigned long url_hash = 0; unsigned long combined_hash; unsigned long high_score = 0; const char *url = urlCanonical(request); /* calculate url hash */ debug(39, 2) ("carpSelectParent: CARP Calculating hash for %s\n", url); for (c = url; *c != 0; c++) url_hash += ROTATE_LEFT(url_hash, 19) + *c; /* select peer */ for (tp = Config.peers; tp; tp = tp->next) { if (0.0 == tp->carp.load_factor) continue; if (tp->tcp_up != PEER_TCP_MAGIC_COUNT) continue; assert(tp->type == PEER_PARENT); combined_hash = (url_hash ^ tp->carp.hash); combined_hash += combined_hash * 0x62531965; combined_hash = ROTATE_LEFT(combined_hash, 21); combined_hash = combined_hash * tp->carp.load_multiplier; debug(39, 3) ("carpSelectParent: %s combined_hash %d\n", tp->host, combined_hash); if ((combined_hash > high_score) && neighborUp(tp)) { p = tp; high_score = combined_hash; } } if (p) debug(39, 3) ("carpSelectParent: selected CARP %s\n", p->host); return p; }
static const char * errorConvert(char token, ErrorState * err) { request_t *r = err->request; static MemBuf mb = MemBufNULL; const char *p = NULL; /* takes priority over mb if set */ int do_quote = 1; memBufReset(&mb); switch (token) { case 'a': if (r && r->auth_user_request) p = authenticateUserRequestUsername(r->auth_user_request); if (!p) p = "-"; break; case 'B': p = r ? ftpUrlWith2f(r) : "[no URL]"; break; case 'c': p = errorPageName(err->type); break; case 'e': memBufPrintf(&mb, "%d", err->xerrno); break; case 'E': if (err->xerrno) memBufPrintf(&mb, "(%d) %s", err->xerrno, strerror(err->xerrno)); else memBufPrintf(&mb, "[No Error]"); break; case 'f': /* FTP REQUEST LINE */ if (err->ftp.request) p = err->ftp.request; else p = "nothing"; break; case 'F': /* FTP REPLY LINE */ if (err->ftp.request) p = err->ftp.reply; else p = "nothing"; break; case 'g': /* FTP SERVER MESSAGE */ wordlistCat(err->ftp.server_msg, &mb); break; case 'h': memBufPrintf(&mb, "%s", getMyHostname()); break; case 'H': if (r) { if (r->hier.host) p = r->hier.host; else p = r->host; } else p = "[unknown host]"; break; case 'i': memBufPrintf(&mb, "%s", inet_ntoa(err->src_addr)); break; case 'I': if (r && r->hier.host) { memBufPrintf(&mb, "%s", r->hier.host); } else p = "[unknown]"; break; case 'L': if (Config.errHtmlText) { memBufPrintf(&mb, "%s", Config.errHtmlText); do_quote = 0; } else p = "[not available]"; break; case 'm': p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]"; break; case 'M': p = r ? RequestMethods[r->method].str : "[unknown method]"; break; case 'o': p = external_acl_message; if (!p) p = "[not available]"; break; case 'p': if (r) { memBufPrintf(&mb, "%d", (int) r->port); } else { p = "[unknown port]"; } break; case 'P': p = r ? ProtocolStr[r->protocol] : "[unkown protocol]"; break; case 'R': if (NULL != r) { Packer p; memBufPrintf(&mb, "%s %s HTTP/%d.%d\n", RequestMethods[r->method].str, strLen(r->urlpath) ? strBuf(r->urlpath) : "/", r->http_ver.major, r->http_ver.minor); packerToMemInit(&p, &mb); httpHeaderPackInto(&r->header, &p); packerClean(&p); } else if (err->request_hdrs) { p = err->request_hdrs; } else { p = "[no request]"; } break; case 's': p = visible_appname_string; break; case 'S': /* signature may contain %-escapes, recursion */ if (err->page_id != ERR_SQUID_SIGNATURE) { const int saved_id = err->page_id; MemBuf sign_mb; err->page_id = ERR_SQUID_SIGNATURE; sign_mb = errorBuildContent(err); memBufPrintf(&mb, "%s", sign_mb.buf); memBufClean(&sign_mb); err->page_id = saved_id; do_quote = 0; } else { /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */ p = "[%S]"; } break; case 't': memBufPrintf(&mb, "%s", mkhttpdlogtime(&squid_curtime)); break; case 'T': memBufPrintf(&mb, "%s", mkrfc1123(squid_curtime)); break; case 'U': p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]"; break; case 'u': p = r ? urlCanonical(r) : err->url ? err->url : "[no URL]"; break; case 'w': if (Config.adminEmail) memBufPrintf(&mb, "%s", Config.adminEmail); else p = "[unknown]"; break; case 'z': if (err->dnsserver_msg) p = err->dnsserver_msg; else p = "[unknown]"; break; case '%': p = "%"; break; default: memBufPrintf(&mb, "%%%c", token); do_quote = 0; break; } if (!p) p = mb.buf; /* do not use mb after this assignment! */ assert(p); debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p); if (do_quote) p = html_quote(p); return p; }
/* return 1 if the entry must be revalidated within delta seconds * 0 otherwise * * note: request maybe null (e.g. for cache digests build) */ static int refreshCheck(const StoreEntry * entry, request_t * request, time_t delta) { const refresh_t *R; const char *uri = NULL; time_t age = 0; time_t check_time = squid_curtime; int staleness; stale_flags sf; if (entry->mem_obj) uri = entry->mem_obj->url; else if (request) uri = urlCanonical(request); debug(22, 3) ("refreshCheck: '%s'\n", uri ? uri : "<none>"); if (delta > 0) check_time += delta; if (check_time > entry->timestamp) age = check_time - entry->timestamp; R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."); if (NULL == R) R = &DefaultRefresh; memset(&sf, '\0', sizeof(sf)); staleness = refreshStaleness(entry, check_time, age, R, &sf); debug(22, 3) ("Staleness = %d\n", staleness); debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n", R->pattern, (int) R->min, (int) (100.0 * R->pct), (int) R->max); debug(22, 3) ("refreshCheck: age = %d\n", (int) age); debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time)); debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp)); if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) { debug(22, 3) ("refreshCheck: YES: Must revalidate stale response\n"); return STALE_MUST_REVALIDATE; } /* request-specific checks */ if (request) { HttpHdrCc *cc = request->cache_control; #if HTTP_VIOLATIONS if (!request->flags.nocache_hack) { (void) 0; } else if (R->flags.ignore_reload) { /* The clients no-cache header is ignored */ debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n"); } else if (R->flags.reload_into_ims || Config.onoff.reload_into_ims) { /* The clients no-cache header is changed into a IMS query */ debug(22, 3) ("refreshCheck: YES: reload-into-ims\n"); return STALE_RELOAD_INTO_IMS; } else { /* The clients no-cache header is not overridden on this request */ debug(22, 3) ("refreshCheck: YES: client reload\n"); request->flags.nocache = 1; return STALE_FORCED_RELOAD; } #endif if (NULL != cc) { if (cc->max_age > -1) { #if HTTP_VIOLATIONS if (R->flags.ignore_reload && cc->max_age == 0) { } else #endif if (age > cc->max_age) { debug(22, 3) ("refreshCheck: YES: age > client-max-age\n"); return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; } } if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness >= 0) { if (cc->max_stale < 0) { /* max-stale directive without a value */ debug(22, 3) ("refreshCheck: NO: max-stale wildcard\n"); return FRESH_REQUEST_MAX_STALE_ALL; } else if (staleness < cc->max_stale) { debug(22, 3) ("refreshCheck: NO: staleness < max-stale\n"); return FRESH_REQUEST_MAX_STALE_VALUE; } } } } if (staleness < 0) { if (sf.expires) return FRESH_EXPIRES; assert(!sf.max); if (sf.lmfactor) return FRESH_LMFACTOR_RULE; assert(sf.min); return FRESH_MIN_RULE; } /* * At this point the response is stale, unless one of * the override options kicks in. */ if (delta < 0 && staleness + delta < 0) { return STALE_WITHIN_DELTA; } if (sf.expires) { #if HTTP_VIOLATIONS if (R->flags.override_expire && age < R->min) { debug(22, 3) ("refreshCheck: NO: age < min && override-expire\n"); return FRESH_OVERRIDE_EXPIRES; } #endif return STALE_EXPIRES; } if (sf.max) return STALE_MAX_RULE; if (sf.lmfactor) { #if HTTP_VIOLATIONS if (R->flags.override_lastmod && age < R->min) { debug(22, 3) ("refreshCheck: NO: age < min && override-lastmod\n"); return FRESH_OVERRIDE_LASTMOD; } #endif return STALE_LMFACTOR_RULE; } return STALE_DEFAULT; }