static void peerDigestSwapInMask(void *data, char *buf, ssize_t size) { DigestFetchState *fetch = data; PeerDigest *pd; /* NOTE! buf points to the middle of pd->cd->mask! */ if (peerDigestFetchedEnough(fetch, NULL, size, "peerDigestSwapInMask")) return; pd = fetch->pd; assert(pd->cd && pd->cd->mask); fetch->offset += size; fetch->mask_offset += size; if (fetch->mask_offset >= pd->cd->mask_size) { debug(72, 2) ("peerDigestSwapInMask: Done! Got %d, expected %d\n", fetch->mask_offset, pd->cd->mask_size); assert(fetch->mask_offset == pd->cd->mask_size); assert(peerDigestFetchedEnough(fetch, NULL, 0, "peerDigestSwapInMask")); } else { const size_t buf_sz = pd->cd->mask_size - fetch->mask_offset; assert(buf_sz > 0); storeClientCopy(fetch->entry, fetch->offset, fetch->offset, buf_sz, pd->cd->mask + fetch->mask_offset, peerDigestSwapInMask, fetch); } }
/* fetch headers from disk, pass on to SwapInCBlock */ static void peerDigestSwapInHeaders(void *data, char *buf, ssize_t size) { DigestFetchState *fetch = data; size_t hdr_size; if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestSwapInHeaders")) return; assert(!fetch->offset); if ((hdr_size = headersEnd(buf, size))) { assert(fetch->entry->mem_obj->reply); if (!fetch->entry->mem_obj->reply->sline.status) httpReplyParse(fetch->entry->mem_obj->reply, buf, hdr_size); if (fetch->entry->mem_obj->reply->sline.status != HTTP_OK) { debug(72, 1) ("peerDigestSwapInHeaders: %s status %d got cached!\n", strBuf(fetch->pd->host), fetch->entry->mem_obj->reply->sline.status); peerDigestFetchAbort(fetch, buf, "internal status error"); return; } fetch->offset += hdr_size; storeClientCopy(fetch->entry, size, fetch->offset, SM_PAGE_SIZE, buf, peerDigestSwapInCBlock, fetch); } else { /* need more data, do we have space? */ if (size >= SM_PAGE_SIZE) peerDigestFetchAbort(fetch, buf, "stored header too big"); else storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf, peerDigestSwapInHeaders, fetch); } }
static void peerDigestSwapInMask(void *data, mem_node_ref nr, ssize_t size) { const char *buf = nr.node->data + nr.offset; DigestFetchState *fetch = data; PeerDigest *pd; assert(size <= nr.node->len - nr.offset); if (peerDigestFetchedEnough(fetch, size, "peerDigestSwapInMask")) { stmemNodeUnref(&nr); return; } pd = fetch->pd; assert(pd->cd && pd->cd->mask); /* Copy data into the peer digest mask */ if (size > 0) { assert(size + fetch->mask_offset < pd->cd->mask_size); memcpy(pd->cd->mask + fetch->mask_offset, buf, size); } stmemNodeUnref(&nr); fetch->offset += size; fetch->mask_offset += size; if (fetch->mask_offset >= pd->cd->mask_size) { debug(72, 2) ("peerDigestSwapInMask: Done! Got %" PRINTF_OFF_T ", expected %d\n", fetch->mask_offset, pd->cd->mask_size); assert(fetch->mask_offset == pd->cd->mask_size); assert(peerDigestFetchedEnough(fetch, 0, "peerDigestSwapInMask")); } else { const size_t buf_sz = pd->cd->mask_size - fetch->mask_offset; assert(buf_sz > 0); storeClientRef(fetch->sc, fetch->entry, fetch->offset, fetch->offset, buf_sz, peerDigestSwapInMask, fetch); } }
static void peerDigestSwapInCBlock(void *data, mem_node_ref nr, ssize_t size) { const char *buf = nr.node->data + nr.offset; DigestFetchState *fetch = data; if (peerDigestFetchedEnough(fetch, size, "peerDigestSwapInCBlock")) goto finish; fetch->offset += size; memcpy(fetch->buf + fetch->buf_used, buf, size); fetch->buf_used += size; if (fetch->buf_used >= StoreDigestCBlockSize) { PeerDigest *pd = fetch->pd; HttpReply *rep = fetch->entry->mem_obj->reply; assert(pd && rep); if (peerDigestSetCBlock(pd, fetch->buf)) { /* XXX: soon we will have variable header size */ fetch->offset -= fetch->buf_used - StoreDigestCBlockSize; /* switch to CD buffer and fetch digest guts */ memFree(fetch->buf, MEM_4K_BUF); fetch->buf = NULL; fetch->buf_used = 0; assert(pd->cd->mask); storeClientRef(fetch->sc, fetch->entry, fetch->offset, fetch->offset, pd->cd->mask_size, peerDigestSwapInMask, fetch); } else { peerDigestFetchAbort(fetch, "invalid digest cblock"); } } else { /* need more data, do we have space? */ if (fetch->buf_used >= SM_PAGE_SIZE) peerDigestFetchAbort(fetch, "digest cblock too big"); else storeClientRef(fetch->sc, fetch->entry, fetch->offset, fetch->offset, SM_PAGE_SIZE - fetch->buf_used, peerDigestSwapInCBlock, fetch); } finish: stmemNodeUnref(&nr); }
static void peerDigestSwapInCBlock(void *data, char *buf, ssize_t size) { DigestFetchState *fetch = data; if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestSwapInCBlock")) return; if (size >= StoreDigestCBlockSize) { PeerDigest *pd = fetch->pd; HttpReply *rep = fetch->entry->mem_obj->reply; const int seen = fetch->offset + size; assert(pd && rep); if (peerDigestSetCBlock(pd, buf)) { /* XXX: soon we will have variable header size */ fetch->offset += StoreDigestCBlockSize; /* switch to CD buffer and fetch digest guts */ memFree(buf, MEM_4K_BUF); buf = NULL; assert(pd->cd->mask); storeClientCopy(fetch->entry, seen, fetch->offset, pd->cd->mask_size, pd->cd->mask, peerDigestSwapInMask, fetch); } else { peerDigestFetchAbort(fetch, buf, "invalid digest cblock"); } } else { /* need more data, do we have space? */ if (size >= SM_PAGE_SIZE) peerDigestFetchAbort(fetch, buf, "digest cblock too big"); else storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf, peerDigestSwapInCBlock, fetch); } }
/* fetch headers from disk, pass on to SwapInCBlock */ static void peerDigestSwapInHeaders(void *data, mem_node_ref nr, ssize_t size) { DigestFetchState *fetch = data; assert(size <= nr.node->len - nr.offset); if (peerDigestFetchedEnough(fetch, size, "peerDigestSwapInHeaders")) goto finish; assert(!fetch->offset); assert(fetch->entry->mem_obj->reply); if (fetch->entry->mem_obj->reply->sline.status != HTTP_OK) { debug(72, 1) ("peerDigestSwapInHeaders: %s status %d got cached!\n", strBuf(fetch->pd->host), fetch->entry->mem_obj->reply->sline.status); peerDigestFetchAbort(fetch, "internal status error"); goto finish; } fetch->offset = fetch->entry->mem_obj->reply->hdr_sz; fetch->buf = memAllocate(MEM_4K_BUF); storeClientRef(fetch->sc, fetch->entry, fetch->offset, fetch->offset, SM_PAGE_SIZE, peerDigestSwapInCBlock, fetch); finish: stmemNodeUnref(&nr); }
/* 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); } }
/* 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); }