void httpReplySetHeaders(HttpReply * reply, http_version_t ver, http_status status, const char *reason, const char *ctype, squid_off_t clen, time_t lmt, time_t expires) { HttpHeader *hdr; assert(reply); httpStatusLineSet(&reply->sline, ver, status, reason); hdr = &reply->header; httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string); httpHeaderPutStr(hdr, HDR_MIME_VERSION, "1.0"); httpHeaderPutTime(hdr, HDR_DATE, squid_curtime); if (ctype) { httpHeaderPutStr(hdr, HDR_CONTENT_TYPE, ctype); stringInit(&reply->content_type, ctype); } else reply->content_type = StringNull; if (clen >= 0) httpHeaderPutSize(hdr, HDR_CONTENT_LENGTH, clen); if (expires >= 0) httpHeaderPutTime(hdr, HDR_EXPIRES, expires); if (lmt > 0) /* this used to be lmt != 0 @?@ */ httpHeaderPutTime(hdr, HDR_LAST_MODIFIED, lmt); reply->date = squid_curtime; reply->content_length = clen; reply->expires = expires; reply->last_modified = lmt; }
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; }
void httpRedirectReply(HttpReply * reply, http_status status, const char *loc) { HttpHeader *hdr; http_version_t ver; assert(reply); httpBuildVersion(&ver, 1, 0); httpStatusLineSet(&reply->sline, ver, status, httpStatusString(status)); hdr = &reply->header; httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string); httpHeaderPutTime(hdr, HDR_DATE, squid_curtime); httpHeaderPutSize(hdr, HDR_CONTENT_LENGTH, 0); httpHeaderPutStr(hdr, HDR_LOCATION, loc); reply->date = squid_curtime; reply->content_length = 0; }
/* create MIME Header for Gopher Data */ static void gopherMimeCreate(GopherStateData * gopherState) { StoreEntry *e = gopherState->entry; HttpReply *reply = e->mem_obj->reply; http_version_t version; const char *mime_type = NULL; const char *mime_enc = NULL; switch (gopherState->type_id) { case GOPHER_DIRECTORY: case GOPHER_INDEX: case GOPHER_HTML: case GOPHER_WWW: case GOPHER_CSO: mime_type = "text/html"; break; case GOPHER_GIF: case GOPHER_IMAGE: case GOPHER_PLUS_IMAGE: mime_type = "image/gif"; break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: mime_type = "audio/basic"; break; case GOPHER_PLUS_MOVIE: mime_type = "video/mpeg"; break; case GOPHER_MACBINHEX: mime_type = "application/macbinary"; break; case GOPHER_DOSBIN: case GOPHER_UUENCODED: case GOPHER_BIN: case GOPHER_FILE: default: /* Rightnow We have no idea what it is. */ mime_type = mimeGetContentType(gopherState->request); mime_enc = mimeGetContentEncoding(gopherState->request); break; } storeBuffer(e); httpReplyReset(reply); EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT); httpBuildVersion(&version, 1, 0); httpReplySetHeaders(reply, version, HTTP_OK, "Gatewaying", mime_type, -1, -1, -1); if (mime_enc) httpHeaderPutStr(&reply->header, HDR_CONTENT_ENCODING, mime_enc); httpReplySwapOut(reply, e); reply->hdr_sz = e->mem_obj->inmem_hi; storeTimestampsSet(e); if (EBIT_TEST(e->flags, ENTRY_CACHABLE)) { storeSetPublicKey(e); } else { storeRelease(e); } }
void urnStart(request_t * r, StoreEntry * e) { LOCAL_ARRAY(char, urlres, 4096); request_t *urlres_r = NULL; const char *t; char *host; UrnState *urnState; StoreEntry *urlres_e; ErrorState *err; debug(52, 3) ("urnStart: '%s'\n", storeUrl(e)); CBDATA_INIT_TYPE(UrnState); urnState = cbdataAlloc(UrnState); urnState->entry = e; urnState->request = requestLink(r); storeLockObject(urnState->entry); if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) { char *new_path = xstrdup(strBuf(r->urlpath) + 5); urnState->flags.force_menu = 1; stringReset(&r->urlpath, new_path); xfree(new_path); } if ((t = strChr(r->urlpath, ':')) != NULL) { strSet(r->urlpath, t, '\0'); host = xstrdup(strBuf(r->urlpath)); strSet(r->urlpath, t, ':'); } else { host = xstrdup(strBuf(r->urlpath)); } snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath)); safe_free(host); urlres_r = urlParse(METHOD_GET, urlres); if (urlres_r == NULL) { debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); err->url = xstrdup(urlres); errorAppendEntry(e, err); return; } httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain"); if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) { urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET); urnState->sc = storeClientListAdd(urlres_e, urnState); fwdStart(-1, urlres_e, urlres_r); } else { storeLockObject(urlres_e); urnState->sc = storeClientListAdd(urlres_e, urnState); } urnState->urlres_e = urlres_e; urnState->urlres_r = requestLink(urlres_r); storeClientCopy(urnState->sc, urlres_e, 0, 0, 4096, memAllocate(MEM_4K_BUF), urnHandleReply, urnState); }
/* used by httpHeaderPutStrf */ static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs) { MemBuf mb; memBufDefInit(&mb); memBufVPrintf(&mb, fmt, vargs); httpHeaderPutStr(hdr, id, mb.buf); memBufClean(&mb); }
static void peerMonitorRequest(void *data) { PeerMonitor *pm = data; char *url; request_t *req; if (!cbdataValid(pm->peer)) { cbdataFree(pm); return; } url = pm->peer->monitor.url; if (!url) { cbdataFree(pm); return; } req = urlParse(METHOD_GET, url); if (!req) { debug(DBG, 1) ("peerMonitorRequest: Failed to parse URL '%s' for cache_peer %s\n", url, pm->peer->name); cbdataFree(pm); return; } pm->last_probe = squid_curtime; pm->running.timeout_set = 1; eventAdd(pm->name, peerMonitorTimeout, pm, (double) (pm->peer->monitor.timeout ? pm->peer->monitor.timeout : pm->peer->monitor.interval), 0); httpHeaderPutStr(&req->header, HDR_ACCEPT, "*/*"); httpHeaderPutStr(&req->header, HDR_USER_AGENT, full_appname_string); if (pm->peer->login) xstrncpy(req->login, pm->peer->login, MAX_LOGIN_SZ); pm->running.req = requestLink(req); pm->running.e = storeCreateEntry(url, req->flags, req->method); pm->running.sc = storeClientRegister(pm->running.e, pm); pm->running.buf = memAllocate(MEM_4K_BUF); fwdStartPeer(pm->peer, pm->running.e, pm->running.req); storeClientCopy(pm->running.sc, pm->running.e, 0, 0, 4096, pm->running.buf, peerMonitorFetchReplyHeaders, pm); return; }
/* ask store for a digest */ static void peerDigestRequest(PeerDigest * pd) { peer *p = pd->peer; StoreEntry *e, *old_e; char *url; const cache_key *key; request_t *req; DigestFetchState *fetch = NULL; pd->req_result = NULL; pd->flags.requested = 1; /* compute future request components */ if (p->digest_url) url = xstrdup(p->digest_url); else url = internalRemoteUri(p->host, p->http_port, "/squid-internal-periodic/", StoreDigestFileName); key = storeKeyPublic(url, METHOD_GET); debug(72, 2) ("peerDigestRequest: %s key: %s\n", url, storeKeyText(key)); req = urlParse(METHOD_GET, url); assert(req); /* add custom headers */ assert(!req->header.len); httpHeaderPutStr(&req->header, HDR_ACCEPT, StoreDigestMimeStr); httpHeaderPutStr(&req->header, HDR_ACCEPT, "text/html"); if (p->login) xstrncpy(req->login, p->login, MAX_LOGIN_SZ); /* create fetch state structure */ fetch = memAllocate(MEM_DIGEST_FETCH_STATE); cbdataAdd(fetch, memFree, MEM_DIGEST_FETCH_STATE); fetch->request = requestLink(req); fetch->pd = pd; fetch->offset = 0; /* update timestamps */ fetch->start_time = squid_curtime; pd->times.requested = squid_curtime; pd_last_req_time = squid_curtime; req->flags.cachable = 1; /* the rest is based on clientProcessExpired() */ req->flags.refresh = 1; old_e = fetch->old_entry = storeGet(key); if (old_e) { debug(72, 5) ("peerDigestRequest: found old entry\n"); storeLockObject(old_e); storeCreateMemObject(old_e, url, url); storeClientListAdd(old_e, fetch); } e = fetch->entry = storeCreateEntry(url, url, req->flags, req->method); assert(EBIT_TEST(e->flags, KEY_PRIVATE)); storeClientListAdd(e, fetch); /* set lastmod to trigger IMS request if possible */ if (old_e) e->lastmod = old_e->lastmod; /* push towards peer cache */ debug(72, 3) ("peerDigestRequest: forwarding to fwdStart...\n"); fwdStart(-1, e, req); cbdataLock(fetch); cbdataLock(fetch->pd); storeClientCopy(e, 0, 0, 4096, memAllocate(MEM_4K_BUF), peerDigestFetchReply, fetch); }
static void urnHandleReply(void *data, char *buf, ssize_t size) { UrnState *urnState = data; StoreEntry *e = urnState->entry; StoreEntry *urlres_e = urnState->urlres_e; char *s = NULL; size_t k; HttpReply *rep; url_entry *urls; url_entry *u; url_entry *min_u; MemBuf mb; ErrorState *err; int i; int urlcnt = 0; http_version_t version; debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size); if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) { memFree(buf, MEM_4K_BUF); return; } if (size == 0) { memFree(buf, MEM_4K_BUF); return; } else if (size < 0) { memFree(buf, MEM_4K_BUF); return; } if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) { storeClientCopy(urnState->sc, urlres_e, size, 0, SM_PAGE_SIZE, buf, urnHandleReply, urnState); return; } /* we know its STORE_OK */ k = headersEnd(buf, size); if (0 == k) { debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n", storeUrl(e)); return; } s = buf + k; assert(urlres_e->mem_obj->reply); httpReplyParse(urlres_e->mem_obj->reply, buf, k); debug(52, 3) ("mem->reply exists, code=%d.\n", urlres_e->mem_obj->reply->sline.status); if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) { debug(52, 3) ("urnHandleReply: failed.\n"); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); err->request = requestLink(urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } while (xisspace(*s)) s++; urls = urnParseReply(s, urnState->request->method); for (i = 0; NULL != urls[i].url; i++) urlcnt++; debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i); if (urls == NULL) { /* unkown URN error */ debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e)); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); err->request = requestLink(urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } min_u = urnFindMinRtt(urls, urnState->request->method, NULL); qsort(urls, urlcnt, sizeof(*urls), url_entry_sort); storeBuffer(e); memBufDefInit(&mb); memBufPrintf(&mb, "<TITLE>Select URL for %s</TITLE>\n" "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n" "<H2>Select URL for %s</H2>\n" "<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e)); for (i = 0; i < urlcnt; i++) { u = &urls[i]; debug(52, 3) ("URL {%s}\n", u->url); memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url); if (urls[i].rtt > 0) memBufPrintf(&mb, "<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt); else memBufPrintf(&mb, "<TD align=\"right\">Unknown</TD>"); memBufPrintf(&mb, "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " "); } memBufPrintf(&mb, "</TABLE>" "<HR noshade size=\"1px\">\n" "<ADDRESS>\n" "Generated by %s@%s\n" "</ADDRESS>\n", full_appname_string, getMyHostname()); rep = e->mem_obj->reply; httpReplyReset(rep); httpBuildVersion(&version, 1, 0); httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", mb.size, 0, squid_curtime); if (urnState->flags.force_menu) { debug(51, 3) ("urnHandleReply: forcing menu\n"); } else if (min_u) { httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url); } httpBodySet(&rep->body, &mb); httpReplySwapOut(rep, e); storeComplete(e); memFree(buf, MEM_4K_BUF); for (i = 0; i < urlcnt; i++) { safe_free(urls[i].url); safe_free(urls[i].host); } safe_free(urls); /* mb was absorbed in httpBodySet call, so we must not clean it */ storeUnregister(urnState->sc, urlres_e, urnState); storeUnlockObject(urlres_e); storeUnlockObject(urnState->entry); requestUnlink(urnState->request); requestUnlink(urnState->urlres_r); cbdataFree(urnState); }