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); }
static void asnCacheStart(int as) { LOCAL_ARRAY(char, asres, 4096); StoreEntry *e; request_t *req; ASState *asState; method_t *method_get; method_get = urlMethodGetKnownByCode(METHOD_GET); asState = cbdataAlloc(ASState); debug(53, 3) ("asnCacheStart: AS %d\n", as); snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as); asState->as_number = as; req = urlParse(method_get, asres); assert(NULL != req); asState->request = requestLink(req); if ((e = storeGetPublic(asres, method_get)) == NULL) { e = storeCreateEntry(asres, null_request_flags, method_get); asState->sc = storeClientRegister(e, asState); fwdStart(-1, e, asState->request); } else { storeLockObject(e); asState->sc = storeClientRegister(e, asState); } asState->entry = e; asState->seen = 0; asState->offset = 0; storeClientRef(asState->sc, e, asState->seen, asState->offset, SM_PAGE_SIZE, asHandleReply, asState); }
/* add client with fd to client list */ store_client * storeClientRegister(StoreEntry * e, void *owner) { MemObject *mem = e->mem_obj; store_client *sc; assert(mem); e->refcount++; mem->nclients++; sc = cbdataAlloc(store_client); sc->callback_data = NULL; sc->seen_offset = 0; sc->copy_offset = 0; sc->flags.disk_io_pending = 0; sc->entry = e; storeLockObject(sc->entry); sc->type = storeClientType(e); #if STORE_CLIENT_LIST_DEBUG assert(!storeClientListSearch(mem, owner)); sc->owner = owner; #endif dlinkAdd(sc, &sc->node, &mem->clients); #if DELAY_POOLS sc->delay_id = 0; #endif return sc; }
void peerSelect(request_t * request, StoreEntry * entry, PSC * callback, void *callback_data) { ps_state *psstate; if (entry) debug(44, 3) ("peerSelect: %s\n", storeUrl(entry)); else debug(44, 3) ("peerSelect: %s\n", RequestMethods[request->method].str); psstate = cbdataAlloc(ps_state); psstate->request = requestLink(request); psstate->entry = entry; psstate->callback = callback; psstate->callback_data = callback_data; psstate->direct = DIRECT_UNKNOWN; #if USE_CACHE_DIGESTS request->hier.peer_select_start = current_time; #endif if (psstate->entry) storeLockObject(psstate->entry); cbdataLock(callback_data); peerSelectFoo(psstate); }
void refreshCheckSubmit(StoreEntry * entry, REFRESHCHECK * callback, void *callback_data) { MemBuf buf; const char *key; refresh_check_helper *def = Config.Program.refresh_check; refreshCheckState *state; dlink_node *node; refreshCheckState *oldstate = NULL; if (!def) { callback(callback_data, 0, NULL); return; } key = makeRefreshCheckRequest(entry, def->format); if (!key) { callback(callback_data, 0, NULL); return; } debug(84, 2) ("refreshCheckSubmit: for '%s'\n", key); /* Check for a pending lookup to hook into */ for (node = def->queue.head; node; node = node->next) { refreshCheckState *oldstatetmp = node->data; if (entry == oldstatetmp->entry) { oldstate = oldstatetmp; break; } } state = cbdataAlloc(refreshCheckState); state->def = def; cbdataLock(state->def); state->entry = entry; storeLockObject(entry); state->callback = callback; state->callback_data = callback_data; cbdataLock(state->callback_data); if (oldstate) { /* Hook into pending lookup */ state->queue = oldstate->queue; oldstate->queue = state; } else { /* No pending lookup found. Sumbit to helper */ /* Check for queue overload */ if (refreshCheckOverload(def)) { debug(84, 1) ("refreshCheckSubmit: queue overload\n"); cbdataFree(state); callback(callback_data, 0, "Overload"); return; } /* Send it off to the helper */ memBufDefInit(&buf); memBufPrintf(&buf, "%s\n", key); helperSubmit(def->helper, buf.buf, refreshCheckHandleReply, state); dlinkAdd(state, &state->list, &def->queue); memBufClean(&buf); } }
static void icapProcessHttpReplyHeader(IcapStateData * icap, const char *buf, int size) { if (NULL == icap->httpState) { icap->httpState = cbdataAlloc(HttpStateData); icap->httpState->request = requestLink(icap->request); icap->httpState->orig_request = requestLink(icap->request); icap->httpState->entry = icap->respmod.entry; storeLockObject(icap->httpState->entry); /* lock it */ } httpProcessReplyHeader(icap->httpState, buf, size); if (2 == icap->httpState->reply_hdr_state) EBIT_CLR(icap->httpState->entry->flags, ENTRY_FWD_HDR_WAIT); }
/* * Function: errorAppendEntry * * Arguments: err - This object is destroyed after use in this function. * * Abstract: This function generates a error page from the info contained * by 'err' and then stores the text in the specified store * entry. This function should only be called by ``server * side routines'' which need to communicate errors to the * client side. It should also be called from client_side.c * because we now support persistent connections, and * cannot assume that we can immediately write to the socket * for an error. */ void errorAppendEntry(StoreEntry * entry, ErrorState * err) { HttpReply *rep; MemObject *mem = entry->mem_obj; assert(mem != NULL); assert(mem->inmem_hi == 0); if (entry->store_status != STORE_PENDING) { /* * If the entry is not STORE_PENDING, then no clients * care about it, and we don't need to generate an * error message */ assert(EBIT_TEST(entry->flags, ENTRY_ABORTED)); assert(mem->nclients == 0); errorStateFree(err); return; } if (err->page_id == TCP_RESET) { if (err->request) { debug(4, 2) ("RSTing this reply\n"); err->request->flags.reset_tcp = 1; } } storeLockObject(entry); storeBuffer(entry); rep = errorBuildReply(err); /* Add authentication header */ /* TODO: alter errorstate to be accel on|off aware. The 0 on the next line * depends on authenticate behaviour: all schemes to date send no extra data * on 407/401 responses, and do not check the accel state on 401/407 responses */ authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1); httpReplySwapOut(rep, entry); httpReplyAbsorb(mem->reply, rep); EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); storeBufferFlush(entry); storeComplete(entry); storeNegativeCache(entry); storeReleaseRequest(entry); storeUnlockObject(entry); errorStateFree(err); }
void whoisStart(FwdState * fwd) { WhoisState *p; int fd = fwd->server_fd; char *buf; size_t l; CBDATA_INIT_TYPE(WhoisState); p = cbdataAlloc(WhoisState); p->request = fwd->request; p->entry = fwd->entry; p->fwd = fwd; storeLockObject(p->entry); comm_add_close_handler(fd, whoisClose, p); l = strLen(p->request->urlpath) + 3; buf = xmalloc(l); snprintf(buf, l, "%s\r\n", strBuf(p->request->urlpath) + 1); comm_write(fd, buf, strlen(buf), NULL, p, xfree); commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, 0); commSetTimeout(fd, Config.Timeout.read, whoisTimeout, p); }
static StoreEntry * heap_purgeNext(RemovalPurgeWalker * walker) { HeapPurgeData *heap_walker = walker->_data; RemovalPolicy *policy = walker->_policy; HeapPolicyData *heap = policy->_data; StoreEntry *entry; heap_key age; try_again: if (!heap_nodes(heap->heap) > 0) return NULL; /* done */ age = heap_peepminkey(heap->heap); entry = heap_extractmin(heap->heap); if (storeEntryLocked(entry)) { storeLockObject(entry); linklistPush(&heap_walker->locked_entries, entry); goto try_again; } heap_walker->min_age = age; SET_POLICY_NODE(entry, NULL); return entry; }
/* 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); }
void cachemgrStart(int fd, request_t * request, StoreEntry * entry) { cachemgrStateData *mgr = NULL; ErrorState *err = NULL; action_table *a; debug(16, 3) ("cachemgrStart: '%s'\n", storeUrl(entry)); if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) { err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND, request); err->url = xstrdup(storeUrl(entry)); errorAppendEntry(entry, err); entry->expires = squid_curtime; return; } mgr->entry = entry; storeLockObject(entry); entry->expires = squid_curtime; debug(16, 5) ("CACHEMGR: %s requesting '%s'\n", fd_table[fd].ipaddr, mgr->action); /* get additional info from request headers */ cachemgrParseHeaders(mgr, request); /* Check password */ if (cachemgrCheckPassword(mgr) != 0) { /* build error message */ ErrorState *err; HttpReply *rep; err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request); /* warn if user specified incorrect password */ if (mgr->passwd) debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n", mgr->user_name ? mgr->user_name : "<unknown>", fd_table[fd].ipaddr, mgr->action); else debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n", mgr->user_name ? mgr->user_name : "<unknown>", fd_table[fd].ipaddr, mgr->action); rep = errorBuildReply(err); errorStateFree(err); /* * add Authenticate header, use 'action' as a realm because * password depends on action */ httpHeaderPutAuth(&rep->header, "Basic", mgr->action); /* store the reply */ httpReplySwapOut(rep, entry); entry->expires = squid_curtime; storeComplete(entry); cachemgrStateFree(mgr); return; } debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n", mgr->user_name ? mgr->user_name : "<unknown>", fd_table[fd].ipaddr, mgr->action); /* retrieve object requested */ a = cachemgrFindAction(mgr->action); assert(a != NULL); storeBuffer(entry); { HttpReply *rep = entry->mem_obj->reply; /* prove there are no previous reply headers around */ assert(0 == rep->sline.status); httpReplySetHeaders(rep, HTTP_OK, NULL, "text/plain", -1, -1, squid_curtime); httpReplySwapOut(rep, entry); } a->handler(entry); storeBufferFlush(entry); if (a->flags.atomic) storeComplete(entry); cachemgrStateFree(mgr); }
IcapStateData * icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry, http_state_flags http_flags) { IcapStateData *icap = NULL; CNCB *theCallback = NULL; icap_service *service = NULL; debug(81, 3) ("icapRespModStart: type=%d\n", (int) type); assert(type >= 0 && type < ICAP_SERVICE_MAX); service = icapService(type, request); if (!service) { debug(81, 3) ("icapRespModStart: no service found\n"); return NULL; /* no service found */ } if (service->unreachable) { if (service->bypass) { debug(81, 5) ("icapRespModStart: BYPASS because service unreachable: %s\n", service->uri); return NULL; } else { debug(81, 5) ("icapRespModStart: ERROR because service unreachable: %s\n", service->uri); return (IcapStateData *) - 1; } } switch (type) { /* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change * this switch, because callbacks isn't keep */ case ICAP_SERVICE_RESPMOD_PRECACHE: theCallback = icapConnectOver; break; default: fatalf("icapRespModStart: unsupported service type '%s'\n", icap_service_type_str[type]); break; } icap = icapAllocate(); if (!icap) { debug(81, 3) ("icapRespModStart: icapAllocate() failed\n"); return NULL; } icap->request = requestLink(request); icap->respmod.entry = entry; if (entry) storeLockObject(entry); icap->http_flags = http_flags; memBufDefInit(&icap->respmod.buffer); memBufDefInit(&icap->chunk_buf); icap->current_service = service; icap->preview_size = service->preview; /* * Don't create socket to the icap server now, but only for the first * packet receive from the http server. This will resolve all timeout * between the web server and icap server. */ debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n"); icap->flags.connect_requested = 0; /* * make a copy the HTTP response that we send to the ICAP server in * case it turns out to be a 204 */ #ifdef SUPPORT_ICAP_204 icap->flags.copy_response = 1; #elif ICAP_PREVIEW if(preview_size < 0 || !Config.icapcfg.preview_enable) icap->flags.copy_response = 0; else icap->flags.copy_response = 1; #else icap->flags.copy_response = 0; #endif statCounter.icap.all.requests++; debug(81, 3) ("icapRespModStart: returning %p\n", icap); return icap; }
void storeUpdate(StoreEntry * entry, request_t * request) { StoreUpdateState *state; request_flags flags = null_request_flags; const char *vary; if (!request) request = entry->mem_obj->request; if (EBIT_TEST(entry->flags, KEY_PRIVATE)) return; /* Nothing to do here... */ if (!Config.onoff.update_headers) return; /* Disabled */ CBDATA_INIT_TYPE_FREECB(StoreUpdateState, free_StoreUpdateState); if (entry->mem_obj) entry->mem_obj->refresh_timestamp = 0; state = cbdataAlloc(StoreUpdateState); state->oldentry = entry; storeLockObject(state->oldentry); flags.cachable = 1; state->newentry = storeCreateEntry(storeUrl(entry), flags, entry->mem_obj->method); storeRegisterAbort(state->newentry, storeUpdateAbort, state); state->sc = storeClientRegister(state->oldentry, state); state->offset = entry->mem_obj->reply->hdr_sz; storeBuffer(state->newentry); httpReplySwapOut(httpReplyClone(entry->mem_obj->reply), state->newentry); state->newentry->timestamp = entry->timestamp; state->newentry->lastref = entry->lastref; state->newentry->expires = entry->expires; state->newentry->lastmod = entry->lastmod; state->newentry->refcount = entry->refcount; if (request) { state->newentry->mem_obj->request = requestLink(request); vary = httpMakeVaryMark(request, state->newentry->mem_obj->reply); if (vary) { state->newentry->mem_obj->vary_headers = xstrdup(vary); if (strBuf(request->vary_encoding)) state->newentry->mem_obj->vary_encoding = xstrdup(strBuf(request->vary_encoding)); } } else { if (entry->mem_obj->vary_headers) state->newentry->mem_obj->vary_headers = xstrdup(entry->mem_obj->vary_headers); if (entry->mem_obj->vary_encoding) state->newentry->mem_obj->vary_encoding = xstrdup(entry->mem_obj->vary_encoding); } storeSetPublicKey(state->newentry); storeBufferFlush(state->newentry); if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* * the above storeBufferFlush() call could ABORT this entry, * in that case, there's nothing for us to do. */ debug(20, 1) ("storeUpdate: Aborted on write\n"); return; } storeClientCopy(state->sc, state->oldentry, state->offset, state->offset, sizeof(state->buf), state->buf, storeUpdateCopy, state); return; }