/* free fetch state structures * must be called only when fetch cbdata is valid */ static void peerDigestFetchFinish(DigestFetchState * fetch, int err) { assert(fetch->entry && fetch->request); if (fetch->old_entry) { debug(72, 2) ("peerDigestFetchFinish: deleting old entry\n"); storeUnregister(fetch->old_entry, fetch); storeReleaseRequest(fetch->old_entry); storeUnlockObject(fetch->old_entry); fetch->old_entry = NULL; } /* update global stats */ kb_incr(&Counter.cd.kbytes_sent, (size_t) fetch->sent.bytes); kb_incr(&Counter.cd.kbytes_recv, (size_t) fetch->recv.bytes); Counter.cd.msgs_sent += fetch->sent.msg; Counter.cd.msgs_recv += fetch->recv.msg; /* unlock everything */ storeUnregister(fetch->entry, fetch); storeUnlockObject(fetch->entry); requestUnlink(fetch->request); fetch->entry = NULL; fetch->request = NULL; assert(fetch->pd == NULL); cbdataUnlock(fetch); cbdataFree(fetch); }
static void peerCountMcastPeersDone(void *data) { ps_state *psstate = data; peer *p = psstate->callback_data; StoreEntry *fake = psstate->entry; if (cbdataValid(p)) { p->mcast.flags.counting = 0; p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members, (double) psstate->ping.n_recv, ++p->mcast.n_times_counted, 10); debug(15, 1) ("Group %s: %d replies, %4.1f average, RTT %d\n", p->host, psstate->ping.n_recv, p->mcast.avg_n_members, p->stats.rtt); p->mcast.n_replies_expected = (int) p->mcast.avg_n_members; } cbdataUnlock(p); EBIT_SET(fake->flags, ENTRY_ABORTED); requestUnlink(fake->mem_obj->request); fake->mem_obj->request = NULL; storeReleaseRequest(fake); storeUnlockObject(fake); requestUnlink(psstate->request); cbdataFree(psstate); }
void storeRecycle(StoreEntry * e) { if (e->swap_dirn >= 0 && !storeEntryLocked(e)) { SwapDir *SD = INDEXSD(e->swap_dirn); /* Expire the object */ storeExpireNow(e); storeReleaseRequest(e); /* Make the cache_dir forget about it */ SD->obj.recycle(SD, e); } /* Finally make the store layer forget about this object */ storeRelease(e); }
/* * 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); }
/* wait for full http headers to be received then parse them */ static void peerDigestFetchReply(void *data, char *buf, ssize_t size) { DigestFetchState *fetch = data; PeerDigest *pd = fetch->pd; size_t hdr_size; assert(pd && buf); assert(!fetch->offset); if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestFetchReply")) return; if ((hdr_size = headersEnd(buf, size))) { http_status status; HttpReply *reply = fetch->entry->mem_obj->reply; assert(reply); httpReplyParse(reply, buf, hdr_size); status = reply->sline.status; debug(72, 3) ("peerDigestFetchReply: %s status: %d, expires: %d (%+d)\n", strBuf(pd->host), status, reply->expires, reply->expires - squid_curtime); /* this "if" is based on clientHandleIMSReply() */ if (status == HTTP_NOT_MODIFIED) { request_t *r = NULL; /* our old entry is fine */ assert(fetch->old_entry); if (!fetch->old_entry->mem_obj->request) fetch->old_entry->mem_obj->request = r = requestLink(fetch->entry->mem_obj->request); assert(fetch->old_entry->mem_obj->request); httpReplyUpdateOnNotModified(fetch->old_entry->mem_obj->reply, reply); storeTimestampsSet(fetch->old_entry); /* get rid of 304 reply */ storeUnregister(fetch->entry, fetch); storeUnlockObject(fetch->entry); fetch->entry = fetch->old_entry; fetch->old_entry = NULL; /* preserve request -- we need its size to update counters */ /* requestUnlink(r); */ /* fetch->entry->mem_obj->request = NULL; */ } else if (status == HTTP_OK) { /* get rid of old entry if any */ if (fetch->old_entry) { debug(72, 3) ("peerDigestFetchReply: got new digest, releasing old one\n"); storeUnregister(fetch->old_entry, fetch); storeReleaseRequest(fetch->old_entry); storeUnlockObject(fetch->old_entry); fetch->old_entry = NULL; } } else { /* some kind of a bug */ peerDigestFetchAbort(fetch, buf, httpStatusLineReason(&reply->sline)); return; } /* must have a ready-to-use store entry if we got here */ /* can we stay with the old in-memory digest? */ if (status == HTTP_NOT_MODIFIED && fetch->pd->cd) peerDigestFetchStop(fetch, buf, "Not modified"); else storeClientCopy(fetch->entry, /* have to swap in */ 0, 0, SM_PAGE_SIZE, buf, peerDigestSwapInHeaders, fetch); } else { /* need more data, do we have space? */ if (size >= SM_PAGE_SIZE) peerDigestFetchAbort(fetch, buf, "reply header too big"); else storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf, peerDigestFetchReply, fetch); } }
static int process_miss_in_error_page(clientHttpRequest* http ,int *ret) { debug(115, 4)("mod_customized_server_side_error_page process_miss_in_error_page\n"); int fd = http->conn->fd; if(fd_table[fd].cc_run_state[mod->slot]>0) { mod_config* cfg = cc_get_mod_param(fd,mod); if(squid_curtime < cfg->error_page_expires ) { ErrorState* err = NULL; /**********************************/ err_type page_id; int status = cfg->ResponseStatus; // add by xueye.zhao // 2013-4-18 if (is_http_move_status(status)) { HttpReply *rep = httpReplyCreate(); http->entry = clientCreateStoreEntry(http, http->request->method, http->request->flags); http->log_type = LOG_TCP_HIT; storeReleaseRequest(http->entry); httpRedirectReply(rep, cfg->ResponseStatus, cfg->location); httpReplySwapOut(rep, http->entry); storeComplete(http->entry); *ret = 1; return *ret; } //end add switch(status) { case HTTP_BAD_REQUEST: case HTTP_LENGTH_REQUIRED: case HTTP_EXPECTATION_FAILED: page_id = ERR_INVALID_REQ; break; case HTTP_UNAUTHORIZED: case HTTP_FORBIDDEN: case HTTP_METHOD_NOT_ALLOWED: case HTTP_NOT_ACCEPTABLE: case HTTP_PROXY_AUTHENTICATION_REQUIRED: case HTTP_REQUEST_TIMEOUT: case HTTP_CONFLICT: case HTTP_GONE: case HTTP_PRECONDITION_FAILED: case HTTP_UNSUPPORTED_MEDIA_TYPE: case HTTP_UNPROCESSABLE_ENTITY: case HTTP_LOCKED: case HTTP_FAILED_DEPENDENCY: page_id = ERR_ACCESS_DENIED; break; case HTTP_NOT_FOUND : page_id = ERR_FTP_NOT_FOUND; break; case HTTP_REQUEST_ENTITY_TOO_LARGE: case HTTP_REQUEST_URI_TOO_LONG: page_id = ERR_TOO_BIG; break; case HTTP_INTERNAL_SERVER_ERROR: page_id= ERR_SOCKET_FAILURE; break; case HTTP_NOT_IMPLEMENTED: page_id = ERR_UNSUP_REQ; break; case HTTP_BAD_GATEWAY: case HTTP_GATEWAY_TIMEOUT: page_id = ERR_CONNECT_FAIL; break; case HTTP_SERVICE_UNAVAILABLE: page_id = ERR_FTP_UNAVAILABLE; break; default: page_id = ERR_HTTP_SPECIAL; } /**********************************/ debug(115, 5)("mod_customized_server_side_error_page: cc_error_page running, don't back source server\n"); http->al.http.code = HTTP_FORBIDDEN; err = errorCon(page_id, cfg->ResponseStatus,http->request); // err->request = requestLink(http->request); err->src_addr = http->conn->peer.sin_addr; http->log_type = LOG_TCP_DENIED; http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); errorAppendEntry(http->entry, err); *ret =1; } } return *ret; }
/*handle errorEntry here*/ static int repl_send_start(clientHttpRequest *http, int *ret) { debug(115, 4)("mod_customized_server_side_error_page repl_send_start\n"); int fd= http->conn->fd; mod_config* cfg = cc_get_mod_param(fd,mod); //mod_config *cfg = ((mod_config*)(param->param)); if(fd_table[fd].cc_run_state[mod->slot]>0) { error_page_private_data* pd = (error_page_private_data*) cc_get_mod_private_data(REQUEST_PRIVATE_DATA,http,mod); if(pd->OfflineTimeToLive > 0&& pd->recusive_time<2 && pd->recusive_time > 0 && cfg->customized_error_text.buf != NULL/* && pd->ResponseStatus <400 */) { debug(115,4)("customized_server_side_error_page: repl_send_start the recusive_time is: %d\n",pd->recusive_time); ErrorState *err; err_type page_id; int status = pd->ResponseStatus; switch(status) { case HTTP_BAD_REQUEST: case HTTP_LENGTH_REQUIRED: case HTTP_EXPECTATION_FAILED: page_id = ERR_INVALID_REQ; break; case HTTP_UNAUTHORIZED: case HTTP_FORBIDDEN: case HTTP_METHOD_NOT_ALLOWED: case HTTP_NOT_ACCEPTABLE: case HTTP_PROXY_AUTHENTICATION_REQUIRED: case HTTP_REQUEST_TIMEOUT: case HTTP_CONFLICT: case HTTP_GONE: case HTTP_PRECONDITION_FAILED: case HTTP_UNSUPPORTED_MEDIA_TYPE: case HTTP_UNPROCESSABLE_ENTITY: case HTTP_LOCKED: case HTTP_FAILED_DEPENDENCY: page_id = ERR_ACCESS_DENIED; break; case HTTP_NOT_FOUND : page_id = ERR_FTP_NOT_FOUND; break; case HTTP_REQUEST_ENTITY_TOO_LARGE: case HTTP_REQUEST_URI_TOO_LONG: page_id = ERR_TOO_BIG; break; case HTTP_INTERNAL_SERVER_ERROR: page_id= ERR_SOCKET_FAILURE; break; case HTTP_NOT_IMPLEMENTED: page_id = ERR_UNSUP_REQ; break; case HTTP_BAD_GATEWAY: case HTTP_GATEWAY_TIMEOUT: page_id = ERR_CONNECT_FAIL; break; case HTTP_SERVICE_UNAVAILABLE: page_id = ERR_FTP_UNAVAILABLE; break; default: page_id = ERR_HTTP_SPECIAL; } // err = errorCon(page_id, err = errorCon(page_id,pd->ResponseStatus,http->request); /********************may be leak here**********************************/ assert(err!=NULL); if(squid_curtime > cfg->error_page_expires) cfg->error_page_expires = squid_curtime + pd->OfflineTimeToLive; //err->request = requestLink(http->request); storeClientUnregister(http->sc,http->entry,http); http->sc = NULL; storeUnlockObject(http->entry); http->log_type = LOG_TCP_HIT; http->entry = clientCreateStoreEntry(http,http->request->method,null_request_flags); debug(115,4)("mod_customized_server_side_error_page repl_send_start: before errorAppendEntry, the err->page_id is: %d, the err->http_status is: %d , the err->type is: %d \n",err->page_id, err->http_status,err->type); errorAppendEntry(http->entry,err); /********************may be leak here**********************************/ *ret = 1; } // add by xueye.zhao // 2013-4-18 else if (pd->OfflineTimeToLive > 0&& pd->recusive_time<2 && pd->recusive_time > 0) { if(squid_curtime > cfg->error_page_expires) cfg->error_page_expires = squid_curtime + pd->OfflineTimeToLive; HttpReply *rep = httpReplyCreate(); http->entry = clientCreateStoreEntry(http, http->request->method, http->request->flags); http->log_type = LOG_TCP_MISS; storeReleaseRequest(http->entry); httpRedirectReply(rep, cfg->ResponseStatus, cfg->location); httpReplySwapOut(rep, http->entry); storeComplete(http->entry); *ret = 1; return *ret; } // end add } return *ret; }
/* wait for full http headers to be received */ static void peerDigestFetchReply(void *data, mem_node_ref nr, ssize_t size) { const char *buf = nr.node->data + nr.offset; DigestFetchState *fetch = data; PeerDigest *pd = fetch->pd; http_status status; HttpReply *reply; assert(pd && buf); assert(!fetch->offset); assert(size <= nr.node->len - nr.offset); if (peerDigestFetchedEnough(fetch, size, "peerDigestFetchReply")) goto finish; reply = fetch->entry->mem_obj->reply; assert(reply); status = reply->sline.status; debug(72, 3) ("peerDigestFetchReply: %s status: %d, expires: %ld (%+d)\n", strBuf(pd->host), status, (long int) reply->expires, (int) (reply->expires - squid_curtime)); /* this "if" is based on clientHandleIMSReply() */ if (status == HTTP_NOT_MODIFIED) { request_t *r = NULL; /* our old entry is fine */ assert(fetch->old_entry); if (!fetch->old_entry->mem_obj->request) fetch->old_entry->mem_obj->request = r = requestLink(fetch->entry->mem_obj->request); assert(fetch->old_entry->mem_obj->request); httpReplyUpdateOnNotModified(fetch->old_entry->mem_obj->reply, reply); storeTimestampsSet(fetch->old_entry); /* get rid of 304 reply */ storeClientUnregister(fetch->sc, fetch->entry, fetch); storeUnlockObject(fetch->entry); /* And prepare to swap in old entry if needed */ fetch->entry = fetch->old_entry; fetch->old_entry = NULL; fetch->sc = fetch->old_sc; fetch->old_sc = NULL; /* preserve request -- we need its size to update counters */ /* requestUnlink(r); */ /* fetch->entry->mem_obj->request = NULL; */ } else if (status == HTTP_OK) { /* get rid of old entry if any */ if (fetch->old_entry) { debug(72, 3) ("peerDigestFetchReply: got new digest, releasing old one\n"); storeClientUnregister(fetch->old_sc, fetch->old_entry, fetch); storeReleaseRequest(fetch->old_entry); storeUnlockObject(fetch->old_entry); fetch->old_entry = NULL; } } else { /* some kind of a bug */ peerDigestFetchAbort(fetch, httpStatusLineReason(&reply->sline)); goto finish; } /* must have a ready-to-use store entry if we got here */ /* can we stay with the old in-memory digest? */ if (status == HTTP_NOT_MODIFIED && fetch->pd->cd) peerDigestFetchStop(fetch, "Not modified"); else storeClientRef(fetch->sc, fetch->entry, /* have to swap in */ 0, 0, SM_PAGE_SIZE, peerDigestSwapInHeaders, fetch); finish: stmemNodeUnref(&nr); }