📄 client_side.c
字号:
clientProcessMiss(http); } else { debug(33, 3) ("clientCacheHit: waiting for HTTP reply headers\n"); storeClientCopy(e, http->out.offset + size, http->out.offset, CLIENT_SOCK_SZ, buf, clientCacheHit, http); } return; } /* * Got the headers, now grok them */ assert(http->log_type == LOG_TCP_HIT); if (checkNegativeHit(e)) { http->log_type = LOG_TCP_NEGATIVE_HIT; clientSendMoreData(data, buf, size); } else if (r->method == METHOD_HEAD) { /* * RFC 2068 seems to indicate there is no "conditional HEAD" * request. We cannot validate a cached object for a HEAD * request, nor can we return 304. */ if (e->mem_status == IN_MEMORY) http->log_type = LOG_TCP_MEM_HIT; clientSendMoreData(data, buf, size); } else if (refreshCheckHTTP(e, r) && !http->flags.internal) { debug(33, 5) ("clientCacheHit: in refreshCheck() block\n"); /* * We hold a stale copy; it needs to be validated */ /* * The 'need_validation' flag is used to prevent forwarding * loops between siblings. If our copy of the object is stale, * then we should probably only use parents for the validation * request. Otherwise two siblings could generate a loop if * both have a stale version of the object. */ r->flags.need_validation = 1; if (e->lastmod < 0) { /* * Previous reply didn't have a Last-Modified header, * we cannot revalidate it. */ http->log_type = LOG_TCP_MISS; clientProcessMiss(http); } else if (r->flags.nocache) { /* * This did not match a refresh pattern that overrides no-cache * we should honour the client no-cache header. */ http->log_type = LOG_TCP_CLIENT_REFRESH_MISS; clientProcessMiss(http); } else if (r->protocol == PROTO_HTTP) { /* * Object needs to be revalidated * XXX This could apply to FTP as well, if Last-Modified is known. */ http->log_type = LOG_TCP_REFRESH_MISS; clientProcessExpired(http); } else { /* * We don't know how to re-validate other protocols. Handle * them as if the object has expired. */ http->log_type = LOG_TCP_MISS; clientProcessMiss(http); } memFree(buf, MEM_CLIENT_SOCK_BUF); } else if (r->flags.ims) { /* * Handle If-Modified-Since requests from the client */ if (mem->reply->sline.status != HTTP_OK) { debug(33, 4) ("clientCacheHit: Reply code %d != 200\n", mem->reply->sline.status); memFree(buf, MEM_CLIENT_SOCK_BUF); http->log_type = LOG_TCP_MISS; clientProcessMiss(http); } else if (modifiedSince(e, http->request)) { http->log_type = LOG_TCP_IMS_HIT; clientSendMoreData(data, buf, size); } else { MemBuf mb = httpPacked304Reply(e->mem_obj->reply); http->log_type = LOG_TCP_IMS_HIT; memFree(buf, MEM_CLIENT_SOCK_BUF); storeUnregister(e, http); storeUnlockObject(e); e = clientCreateStoreEntry(http, http->request->method, null_request_flags); http->entry = e; httpReplyParse(e->mem_obj->reply, mb.buf); storeAppend(e, mb.buf, mb.size); memBufClean(&mb); storeComplete(e); } } else { /* * plain ol' cache hit */ if (e->mem_status == IN_MEMORY) http->log_type = LOG_TCP_MEM_HIT; else if (Config.onoff.offline) http->log_type = LOG_TCP_OFFLINE_HIT; clientSendMoreData(data, buf, size); }}/* extracts a "range" from *buf and appends them to mb, updating all offsets and such */static voidclientPackRange(clientHttpRequest * http, HttpHdrRangeIter * i, const char **buf, ssize_t * size, MemBuf * mb){ const size_t copy_sz = i->debt_size <= *size ? i->debt_size : *size; off_t body_off = http->out.offset - i->prefix_size; assert(*size > 0); assert(i->spec); /* intersection of "have" and "need" ranges must not be empty */ assert(body_off < i->spec->offset + i->spec->length); assert(body_off + *size > i->spec->offset); /* put boundary and headers at the beginning of range in a multi-range */ if (http->request->range->specs.count > 1 && i->debt_size == i->spec->length) { HttpReply *rep = http->entry->mem_obj ? /* original reply */ http->entry->mem_obj->reply : NULL; HttpHeader hdr; Packer p; assert(rep); /* put boundary */ debug(33, 5) ("clientPackRange: appending boundary: %s\n", strBuf(i->boundary)); /* rfc2046 requires to _prepend_ boundary with <crlf>! */ memBufPrintf(mb, "\r\n--%s\r\n", strBuf(i->boundary)); httpHeaderInit(&hdr, hoReply); if (httpHeaderHas(&rep->header, HDR_CONTENT_TYPE)) httpHeaderPutStr(&hdr, HDR_CONTENT_TYPE, httpHeaderGetStr(&rep->header, HDR_CONTENT_TYPE)); httpHeaderAddContRange(&hdr, *i->spec, rep->content_length); packerToMemInit(&p, mb); httpHeaderPackInto(&hdr, &p); packerClean(&p); httpHeaderClean(&hdr); /* append <crlf> (we packed a header, not a reply */ memBufPrintf(mb, crlf); } /* append */ debug(33, 3) ("clientPackRange: appending %d bytes\n", copy_sz); memBufAppend(mb, *buf, copy_sz); /* update offsets */ *size -= copy_sz; i->debt_size -= copy_sz; body_off += copy_sz; *buf += copy_sz; http->out.offset = body_off + i->prefix_size; /* sync */ /* paranoid check */ assert(*size >= 0 && i->debt_size >= 0);}/* returns true if there is still data available to pack more ranges * increments iterator "i" * used by clientPackMoreRanges */static intclientCanPackMoreRanges(const clientHttpRequest * http, HttpHdrRangeIter * i, ssize_t size){ /* first update "i" if needed */ if (!i->debt_size) { if ((i->spec = httpHdrRangeGetSpec(http->request->range, &i->pos))) i->debt_size = i->spec->length; } assert(!i->debt_size == !i->spec); /* paranoid sync condition */ /* continue condition: need_more_data && have_more_data */ return i->spec && size > 0;}/* extracts "ranges" from buf and appends them to mb, updating all offsets and such *//* returns true if we need more data */static intclientPackMoreRanges(clientHttpRequest * http, const char *buf, ssize_t size, MemBuf * mb){ HttpHdrRangeIter *i = &http->range_iter; /* offset in range specs does not count the prefix of an http msg */ off_t body_off = http->out.offset - i->prefix_size; assert(size >= 0); /* check: reply was parsed and range iterator was initialized */ assert(i->prefix_size > 0); /* filter out data according to range specs */ while (clientCanPackMoreRanges(http, i, size)) { off_t start; /* offset of still missing data */ assert(i->spec); start = i->spec->offset + i->spec->length - i->debt_size; debug(33, 2) ("clientPackMoreRanges: in: offset: %d size: %d\n", (int) body_off, size); debug(33, 2) ("clientPackMoreRanges: out: start: %d spec[%d]: [%d, %d), len: %d debt: %d\n", (int) start, (int) i->pos, i->spec->offset, (int) (i->spec->offset + i->spec->length), i->spec->length, i->debt_size); assert(body_off <= start); /* we did not miss it */ /* skip up to start */ if (body_off + size > start) { const size_t skip_size = start - body_off; body_off = start; size -= skip_size; buf += skip_size; } else { /* has not reached start yet */ body_off += size; size = 0; buf = NULL; } /* put next chunk if any */ if (size) { http->out.offset = body_off + i->prefix_size; /* sync */ clientPackRange(http, i, &buf, &size, mb); body_off = http->out.offset - i->prefix_size; /* sync */ } } assert(!i->debt_size == !i->spec); /* paranoid sync condition */ debug(33, 2) ("clientPackMoreRanges: buf exhausted: in: offset: %d size: %d need_more: %d\n", (int) body_off, size, i->debt_size); if (i->debt_size) { debug(33, 2) ("clientPackMoreRanges: need more: spec[%d]: [%d, %d), len: %d\n", (int) i->pos, i->spec->offset, (int) (i->spec->offset + i->spec->length), i->spec->length); /* skip the data we do not need if possible */ if (i->debt_size == i->spec->length) /* at the start of the cur. spec */ body_off = i->spec->offset; else assert(body_off == i->spec->offset + i->spec->length - i->debt_size); } else if (http->request->range->specs.count > 1) { /* put terminating boundary for multiparts */ memBufPrintf(mb, "\r\n--%s--\r\n", strBuf(i->boundary)); } http->out.offset = body_off + i->prefix_size; /* sync */ return i->debt_size > 0;}/* * accepts chunk of a http message in buf, parses prefix, filters headers and * such, writes processed message to the client's socket */static voidclientSendMoreData(void *data, char *buf, ssize_t size){ clientHttpRequest *http = data; StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; int fd = conn->fd; HttpReply *rep = NULL; const char *body_buf = buf; ssize_t body_size = size; MemBuf mb; ssize_t check_size = 0; debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); assert(size <= CLIENT_SOCK_SZ); assert(http->request != NULL); dlinkDelete(&http->active, &ClientActiveRequests); dlinkAdd(http, &http->active, &ClientActiveRequests); debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", fd, storeUrl(entry), (int) http->out.offset); if (conn->chr != http) { /* there is another object in progress, defer this one */ debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* call clientWriteComplete so the client socket gets closed */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (size < 0) { /* call clientWriteComplete so the client socket gets closed */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (size == 0) { /* call clientWriteComplete so the client socket gets closed */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } if (http->out.offset == 0) { if (Config.onoff.log_mime_hdrs) { size_t k; if ((k = headersEnd(buf, size))) { safe_free(http->al.headers.reply); http->al.headers.reply = xcalloc(k + 1, 1); xstrncpy(http->al.headers.reply, buf, k); } } rep = clientBuildReply(http, buf, size); if (rep) { body_size = size - rep->hdr_sz; assert(body_size >= 0); body_buf = buf + rep->hdr_sz; http->range_iter.prefix_size = rep->hdr_sz; debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n", body_size, rep->hdr_sz); } else if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) { /* wait for more to arrive */ storeClientCopy(entry, http->out.offset + size, http->out.offset, CLIENT_SOCK_SZ, buf, clientSendMoreData, http); return; } /* reset range iterator */ http->range_iter.pos = HttpHdrRangeInitPos; } if (http->request->method == METHOD_HEAD) { if (rep) { /* do not forward body for HEAD replies */ body_size = 0; http->flags.done_copying = 1; } else { /* * If we are here, then store_status == STORE_OK and it * seems we have a HEAD repsponse which is missing the * empty end-of-headers line (home.mira.net, phttpd/0.99.72 * does this). Because clientBuildReply() fails we just * call this reply a body, set the done_copying flag and * continue... */ http->flags.done_copying = 1; } } /* write headers and/or body if any */ assert(rep || (body_buf && body_size)); /* init mb; put status line and headers if any */ if (rep) { mb = httpReplyPack(rep); http->out.offset += rep->hdr_sz; check_size += rep->hdr_sz; httpReplyDestroy(rep); rep = NULL; } else { memBufDefInit(&mb); } /* append body if any */ if (http->request->range) { /* Only GET requests should have ranges */ assert(http->request->method == METHOD_GET); /* clientPackMoreRanges() updates http->out.offset */ /* force the end of the transfer if we are done */ if (!clientPackMoreRanges(http, body_buf, body_size, &mb)) http->flags.done_copying = 1; } else if (body_buf && body_size) { http->out.offset += body_size; check_size += body_size; memBufAppend(&mb, body_buf, body_size); } if (!http->request->range && http->request->method == METHOD_GET) assert(check_size == size); /* write */ comm_write_mbuf(fd, mb, clientWriteComplete, http); /* if we don't do it, who will? */ memFree(buf, MEM_CLIENT_SOCK_BUF);}static voidclientKeepaliveNextRequest(clientHttpRequest * http){ ConnStateData *conn = http->conn; StoreEntry *entry; debug(33, 3) ("clientKeepaliveNextRequest: FD %d\n", conn->fd); conn->defer.until = 0; /* Kick it to read a new request */ httpRequestFree(http); if ((http = conn->chr) == NULL) { debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next req\n", conn->fd); fd_note(conn->fd, "Reading next request"); /* * Set the timeout BEFORE calling clientReadRequest(). */ commSetTimeout(conn->fd, 15, requestTimeout, conn); clientReadRequest(conn->fd, conn); /* Read next request */ /* * Note, the FD may be closed at this point. */ } else if ((entry = http->entry) == NULL) { /* * this request is in progress, maybe doing an ACL or a redirect, * execution will resume after the operation completes. */ } else { debug(33, 1) ("clientKeepaliveNextRequest: FD %d Sending next\n", conn->fd); assert(entry); if (0 == storeClientCopyPending(entry, http)) { if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTED\n"); storeClientCopy(entry, http->out.offset, http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, http); } }}static voidclientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -