📄 http.c
字号:
httpReplyParse(reply, httpState->reply_hdr); /* httpState->eof); */ storeTimestampsSet(entry); /* Check if object is cacheable or not based on reply code */ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status); if (neighbors_do_private_keys) httpMaybeRemovePublic(entry, reply->sline.status); switch (httpCachableReply(httpState)) { case 1: httpMakePublic(entry); break; case 0: httpMakePrivate(entry); break; case -1: httpCacheNegatively(entry); break; default: assert(0); break; } if (reply->cache_control) { if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE)) EBIT_SET(entry->flags, ENTRY_REVALIDATE); else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE)) EBIT_SET(entry->flags, ENTRY_REVALIDATE); } if (httpState->flags.keepalive) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; if (reply->keep_alive) if (httpState->peer) httpState->peer->stats.n_keepalives_recv++; ctx_exit(ctx); if (reply->date > -1 && !httpState->peer) { int skew = abs(reply->date - squid_curtime); if (skew > 86400) debug(11, 3) ("%s's clock is skewed by %d seconds!\n", httpState->request->host, skew); } }}static inthttpPconnTransferDone(HttpStateData * httpState){ /* return 1 if we got the last of the data on a persistent connection */ MemObject *mem = httpState->entry->mem_obj; HttpReply *reply = mem->reply; debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd); /* * If we didn't send a keep-alive request header, then this * can not be a persistent connection. */ if (!httpState->flags.keepalive) return 0; /* * What does the reply have to say about keep-alive? */ /* * XXX BUG? * If the origin server (HTTP/1.0) does not send a keep-alive * header, but keeps the connection open anyway, what happens? * We'll return here and http.c waits for an EOF before changing * store_status to STORE_OK. Combine this with ENTRY_FWD_HDR_WAIT * and an error status code, and we might have to wait until * the server times out the socket. */ if (!reply->keep_alive) return 0; debug(11, 5) ("httpPconnTransferDone: content_length=%d\n", reply->content_length); /* * Deal with gross HTTP stuff * - If we haven't seen the end of the reply headers, we can't * be persistent. * - For HEAD requests we're done. * - For "200 OK" check the content-length in the next block. * - For "204 No Content" (even with content-length) we're done. * - For "304 Not Modified" (even with content-length) we're done. * - 1XX replies never have a body; we're done. * - For all other replies, check content length in next block. */ if (httpState->reply_hdr_state < 2) return 0; else if (httpState->request->method == METHOD_HEAD) return 1; else if (reply->sline.status == HTTP_OK) (void) 0; /* common case, continue */ else if (reply->sline.status == HTTP_NO_CONTENT) return 1; else if (reply->sline.status == HTTP_NOT_MODIFIED) return 1; else if (reply->sline.status < HTTP_OK) return 1; /* * If there is no content-length, then we can't be * persistent. If there is a content length, then we must * wait until we've seen the end of the body. */ if (reply->content_length < 0) return 0; else if (mem->inmem_hi < reply->content_length + reply->hdr_sz) return 0; else return 1;}/* This will be called when data is ready to be read from fd. Read until * error or connection closed. *//* XXX this function is too long! */static voidhttpReadReply(int fd, void *data){ HttpStateData *httpState = data; LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF); StoreEntry *entry = httpState->entry; const request_t *request = httpState->request; int len; int bin; int clen; size_t read_sz;#if DELAY_POOLS delay_id delay_id; /* special "if" only for http (for nodelay proxy conns) */ if (delayIsNoDelay(fd)) delay_id = 0; else delay_id = delayMostBytesAllowed(entry->mem_obj);#endif if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; } /* check if we want to defer reading */ errno = 0; read_sz = SQUID_TCP_SO_RCVBUF;#if DELAY_POOLS read_sz = delayBytesWanted(delay_id, 1, read_sz);#endif Counter.syscalls.sock.reads++; len = read(fd, buf, read_sz); debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_READ);#if DELAY_POOLS delayBytesIn(delay_id, len);#endif kb_incr(&Counter.server.all.kbytes_in, len); kb_incr(&Counter.server.http.kbytes_in, len); commSetTimeout(fd, Config.Timeout.read, NULL, NULL); IOStats.Http.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen >>= 1; IOStats.Http.read_hist[bin]++; } if (!httpState->reply_hdr && len > 0) { /* Skip whitespace */ while (len > 0 && xisspace(*buf)) xmemmove(buf, buf + 1, len--); if (len == 0) { /* Continue to read... */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); return; } } if (len < 0) { debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n", fd, xstrerror()); if (ignoreErrno(errno)) { commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); } else if (entry->mem_obj->inmem_hi == 0) { ErrorState *err; err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; fwdFail(httpState->fwd, err); comm_close(fd); } else { comm_close(fd); } } else if (len == 0 && entry->mem_obj->inmem_hi == 0) { ErrorState *err; err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE); err->xerrno = errno; fwdFail(httpState->fwd, err); httpState->eof = 1; comm_close(fd); } else if (len == 0) { /* Connection closed; retrieval done. */ httpState->eof = 1; if (httpState->reply_hdr_state < 2) /* * Yes Henrik, there is a point to doing this. When we * called httpProcessReplyHeader() before, we didn't find * the end of headers, but now we are definately at EOF, so * we want to process the reply headers. */ httpProcessReplyHeader(httpState, buf, len); fwdComplete(httpState->fwd); comm_close(fd); } else { if (httpState->reply_hdr_state < 2) { httpProcessReplyHeader(httpState, buf, len); if (httpState->reply_hdr_state == 2) { http_status s = entry->mem_obj->reply->sline.status; /* * If its not a reply that we will re-forward, then * allow the client to get it. */ if (!fwdReforwardableStatus(s)) EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); } } storeAppend(entry, buf, len); if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* * the above storeAppend() call could ABORT this entry, * in that case, the server FD should already be closed. * there's nothing for us to do. */ (void) 0; } else if (httpPconnTransferDone(httpState)) { /* yes we have to clear all these! */ commSetDefer(fd, NULL, NULL); commSetTimeout(fd, -1, NULL, NULL); commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);#if DELAY_POOLS delayClearNoDelay(fd);#endif comm_remove_close_handler(fd, httpStateFree, httpState); fwdUnregister(fd, httpState->fwd); pconnPush(fd, request->host, request->port); fwdComplete(httpState->fwd); httpState->fd = -1; httpStateFree(fd, httpState); } else { /* Wait for EOF condition */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); } }}/* This will be called when request write is complete. Schedule read of * reply. */static voidhttpSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data){ HttpStateData *httpState = data; StoreEntry *entry = httpState->entry; ErrorState *err; debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n", fd, size, errflag); if (size > 0) { fd_bytes(fd, size, FD_WRITE); kb_incr(&Counter.server.all.kbytes_out, size); kb_incr(&Counter.server.http.kbytes_out, size); } if (errflag == COMM_ERR_CLOSING) return; if (errflag) { err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; err->request = requestLink(httpState->orig_request); errorAppendEntry(entry, err); comm_close(fd); return; } else { /* Schedule read reply. */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); /* * Set the read timeout here because it hasn't been set yet. * We only set the read timeout after the request has been * fully written to the server-side. If we start the timeout * after connection establishment, then we are likely to hit * the timeout for POST/PUT requests that have very large * request bodies. */ commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState); commSetDefer(fd, fwdCheckDeferRead, entry); }}/* * build request headers and append them to a given MemBuf * used by httpBuildRequestPrefix() * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing */voidhttpBuildRequestHeader(request_t * request, request_t * orig_request, StoreEntry * entry, HttpHeader * hdr_out, int cfd, http_state_flags flags){ /* building buffer for complex strings */#define BBUF_SZ (MAX_URL+32) LOCAL_ARRAY(char, bbuf, BBUF_SZ); String strConnection = StringNull; const HttpHeader *hdr_in = &orig_request->header; int we_do_ranges; const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; httpHeaderInit(hdr_out, hoRequest); /* append our IMS header */ if (entry && entry->lastmod > -1 && request->method == METHOD_GET) httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, entry->lastmod); /* decide if we want to do Ranges ourselves * (and fetch the whole object now) * We want to handle Ranges ourselves iff * - we can actually parse client Range specs * - the specs are expected to be simple enough (e.g. no out-of-order ranges) * - reply will be cachable * (If the reply will be uncachable we have to throw it away after * serving this request, so it is better to forward ranges to * the server and fetch only the requested content) */ we_do_ranges = orig_request->range && orig_request->flags.cachable && !httpHdrRangeWillBeComplex(orig_request->range) && (Config.rangeOffsetLimit == -1 || httpHdrRangeFirstOffset(orig_request->range) <= Config.rangeOffsetLimit); debug(11, 8) ("httpBuildRequestHeader: range specs: %p, cachable: %d; we_do_ranges: %d\n", orig_request->range, orig_request->flags.cachable, we_do_ranges); strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION); while ((e = httpHeaderGetEntry(hdr_in, &pos))) { debug(11, 5) ("httpBuildRequestHeader: %s: %s\n", strBuf(e->name), strBuf(e->value)); if (!httpRequestHdrAllowed(e, &strConnection))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -