📄 client_side.c
字号:
{ clientHttpRequest *http = data; StoreEntry *entry = http->entry; int done; http->out.size += size; debug(33, 5) ("clientWriteComplete: FD %d, sz %d, err %d, off %d, len %d\n", fd, size, errflag, (int) http->out.offset, entry ? objectLen(entry) : 0); if (size > 0) { kb_incr(&Counter.client_http.kbytes_out, size); if (isTcpHit(http->log_type)) kb_incr(&Counter.client_http.hit_kbytes_out, size); } if (errflag) { /* * just close the socket, httpRequestFree will abort if needed */ comm_close(fd); } else if (NULL == entry) { comm_close(fd); /* yuk */ } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) { debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd); /* We're finished case */ if (http->entry->mem_obj->reply->content_length < 0) { debug(33, 5) ("clientWriteComplete: closing, content_length < 0\n"); comm_close(fd); } else if (!done) { debug(33, 5) ("clientWriteComplete: closing, !done\n"); comm_close(fd); } else if (clientGotNotEnough(http)) { debug(33, 5) ("clientWriteComplete: client didn't get all it expected\n"); comm_close(fd); } else if (http->request->flags.proxy_keepalive) { debug(33, 5) ("clientWriteComplete: FD %d Keeping Alive\n", fd); clientKeepaliveNextRequest(http); } else { comm_close(fd); } } else { /* More data will be coming from primary server; register with * storage manager. */ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) debug(33, 0) ("clientWriteComplete 2: ENTRY_ABORTED\n"); storeClientCopy(entry, http->out.offset, http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, http); }}/* * client issued a request with an only-if-cached cache-control directive; * we did not find a cached object that can be returned without * contacting other servers; * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068] */static voidclientProcessOnlyIfCachedMiss(clientHttpRequest * http){ char *url = http->uri; request_t *r = http->request; ErrorState *err = NULL; debug(33, 4) ("clientProcessOnlyIfCachedMiss: '%s %s'\n", RequestMethodStr[r->method], url); http->al.http.code = HTTP_GATEWAY_TIMEOUT; err = errorCon(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT); err->request = requestLink(r); err->src_addr = http->conn->peer.sin_addr; if (http->entry) { storeUnregister(http->entry, http); storeUnlockObject(http->entry); } http->entry = clientCreateStoreEntry(http, r->method, null_request_flags); errorAppendEntry(http->entry, err);}static log_typeclientProcessRequest2(clientHttpRequest * http){ request_t *r = http->request; StoreEntry *e; e = http->entry = storeGetPublic(http->uri, r->method); if (r->method == METHOD_HEAD && e == NULL) { /* We can generate a HEAD reply from a cached GET object */ e = http->entry = storeGetPublic(http->uri, METHOD_GET); }#if USE_CACHE_DIGESTS http->lookup_type = e ? "HIT" : "MISS";#endif if (NULL == e) { /* this object isn't in the cache */ debug(33, 3) ("clientProcessRequest2: storeGet() MISS\n"); return LOG_TCP_MISS; } if (Config.onoff.offline) { debug(33, 3) ("clientProcessRequest2: offline HIT\n"); http->entry = e; return LOG_TCP_HIT; } if (!storeEntryValidToSend(e)) { debug(33, 3) ("clientProcessRequest2: !storeEntryValidToSend MISS\n"); http->entry = NULL; return LOG_TCP_MISS; } if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { /* Special entries are always hits, no matter what the client says */ debug(33, 3) ("clientProcessRequest2: ENTRY_SPECIAL HIT\n"); http->entry = e; return LOG_TCP_HIT; }#if HTTP_VIOLATIONS if (r->flags.nocache_hack) { /* if nocache_hack is set, nocache should always be clear, right? */ assert(!r->flags.nocache); ipcacheReleaseInvalid(r->host); /* continue! */ } if (e->store_status == STORE_PENDING) { if (r->flags.nocache || r->flags.nocache_hack) { debug(33, 3) ("Clearing no-cache for STORE_PENDING request\n\t%s\n", storeUrl(e)); r->flags.nocache = 0; r->flags.nocache_hack = 0; } }#endif if (r->flags.nocache) { debug(33, 3) ("clientProcessRequest2: no-cache REFRESH MISS\n"); http->entry = NULL; ipcacheReleaseInvalid(r->host); return LOG_TCP_CLIENT_REFRESH_MISS; } if (r->range && httpHdrRangeWillBeComplex(r->range)) { /* * Some clients break if we return "200 OK" for a Range * request. We would have to return "200 OK" for a _complex_ * Range request that is also a HIT. Thus, let's prevent HITs * on complex Range requests */ debug(33, 3) ("clientProcessRequest2: complex range MISS\n"); http->entry = NULL; return LOG_TCP_MISS; } debug(33, 3) ("clientProcessRequest2: default HIT\n"); http->entry = e; return LOG_TCP_HIT;}static voidclientProcessRequest(clientHttpRequest * http){ char *url = http->uri; request_t *r = http->request; int fd = http->conn->fd; HttpReply *rep; debug(33, 4) ("clientProcessRequest: %s '%s'\n", RequestMethodStr[r->method], url); if (r->method == METHOD_CONNECT) { http->log_type = LOG_TCP_MISS; sslStart(fd, url, r, &http->out.size); return; } else if (r->method == METHOD_PURGE) { clientPurgeRequest(http); return; } else if (r->method == METHOD_TRACE) { if (r->max_forwards == 0) { http->entry = clientCreateStoreEntry(http, r->method, null_request_flags); storeReleaseRequest(http->entry); storeBuffer(http->entry); rep = httpReplyCreate(); httpReplySetHeaders(rep, 1.0, HTTP_OK, NULL, "text/plain", httpRequestPrefixLen(r), 0, squid_curtime); httpReplySwapOut(rep, http->entry); httpReplyDestroy(rep); httpRequestSwapOut(r, http->entry); storeComplete(http->entry); return; } /* yes, continue */ http->log_type = LOG_TCP_MISS; } else if (pumpMethod(r->method)) { http->log_type = LOG_TCP_MISS; /* XXX oof, POST can be cached! */ pumpInit(fd, r, http->uri); } else { http->log_type = clientProcessRequest2(http); } debug(33, 4) ("clientProcessRequest: %s for '%s'\n", log_tags[http->log_type], http->uri); http->out.offset = 0; if (NULL != http->entry) { storeLockObject(http->entry); storeCreateMemObject(http->entry, http->uri, http->log_uri); storeClientListAdd(http->entry, http);#if DELAY_POOLS delaySetStoreClient(http->entry, http, delayClient(r));#endif http->entry->refcount++; storeClientCopy(http->entry, http->out.offset, http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), clientCacheHit, http); } else { /* MISS CASE */ http->log_type = LOG_TCP_MISS; clientProcessMiss(http); }}/* * Prepare to fetch the object as it's a cache miss of some kind. */static voidclientProcessMiss(clientHttpRequest * http){ char *url = http->uri; request_t *r = http->request; ErrorState *err = NULL; debug(33, 4) ("clientProcessMiss: '%s %s'\n", RequestMethodStr[r->method], url); /* * We might have a left-over StoreEntry from a failed cache hit * or IMS request. */ if (http->entry) { if (EBIT_TEST(http->entry->flags, ENTRY_SPECIAL)) debug(33, 0) ("clientProcessMiss: miss on a special object (%s).\n", url); storeUnregister(http->entry, http); storeUnlockObject(http->entry); http->entry = NULL; } if (clientOnlyIfCached(http)) { clientProcessOnlyIfCachedMiss(http); return; } /* * Deny loops when running in accelerator/transproxy mode. */ if (http->flags.accel && r->flags.loopdetect) { http->al.http.code = HTTP_FORBIDDEN; err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN); err->request = requestLink(r); err->src_addr = http->conn->peer.sin_addr; http->entry = clientCreateStoreEntry(http, r->method, null_request_flags); errorAppendEntry(http->entry, err); return; } assert(http->out.offset == 0); http->entry = clientCreateStoreEntry(http, r->method, r->flags); http->entry->refcount++; if (http->redirect.status) { HttpReply *rep = httpReplyCreate(); storeReleaseRequest(http->entry); httpRedirectReply(rep, http->redirect.status, http->redirect.location); httpReplySwapOut(rep, http->entry); httpReplyDestroy(rep); storeComplete(http->entry); return; } if (http->flags.internal) r->protocol = PROTO_INTERNAL; fwdStart(http->conn->fd, http->entry, r, http->conn->peer.sin_addr, http->conn->me.sin_addr);}static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri){ clientHttpRequest *http = xcalloc(1, sizeof(clientHttpRequest)); cbdataAdd(http, cbdataXfree, 0); http->conn = conn; http->start = current_time; http->req_sz = conn->in.offset; http->uri = xstrdup(uri); http->log_uri = xstrndup(uri, MAX_URL); http->range_iter.boundary = StringNull; dlinkAdd(http, &http->active, &ClientActiveRequests); return http;}/* * parseHttpRequest() * * Returns * NULL on error or incomplete request * a clientHttpRequest structure on success */static clientHttpRequest *parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status, char **prefix_p, size_t * req_line_sz_p){ char *inbuf = NULL; char *mstr = NULL; char *url = NULL; char *req_hdr = NULL; float http_ver; char *token = NULL; char *t = NULL; char *end; int free_request = 0; size_t header_sz; /* size of headers, not including first line */ size_t prefix_sz; /* size of whole request (req-line + headers) */ size_t url_sz; size_t req_sz; method_t method; clientHttpRequest *http = NULL;#if IPF_TRANSPARENT struct natlookup natLookup; static int natfd = -1;#endif if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) { debug(33, 5) ("Incomplete request, waiting for end of headers\n"); *status = 0; *prefix_p = NULL; *method_p = METHOD_NONE; return NULL; } assert(req_sz <= conn->in.offset); /* Use memcpy, not strdup! */ inbuf = xmalloc(req_sz + 1); xmemcpy(inbuf, conn->in.buf, req_sz); *(inbuf + req_sz) = '\0'; /* pre-set these values to make aborting simpler */ *prefix_p = inbuf; *method_p = METHOD_NONE; *status = -1; /* Barf on NULL characters in the headers */ if (strlen(inbuf) != req_sz) { debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n"); return parseHttpRequestAbort(conn, "error:invalid-request"); } /* Look for request method */ if ((mstr = strtok(inbuf, "\t ")) == NULL) { debug(33, 1) ("parseHttpRequest: Can't get request method\n"); return parseHttpRequestAbort(conn, "error:invalid-request-method"); } method = urlParseMethod(mstr); if (method == METHOD_NONE) { debug(33, 1) ("parseHttpRequest: Unsupported method '%s'\n", mstr); return parseHttpRequestAbort(conn, "error:unsupported-request-method"); } debug(33, 5) ("parseHttpRequest: Method is '%s'\n", mstr); *method_p = method; /* look for URL+HTTP/x.x */ if ((url = strtok(NULL, "\n")) == NULL) { debug(33, 1) ("parseHttpRequest: Missing URL\n"); return parseHttpRequestAbort(conn, "error:missing-url"); } while (xisspace(*url)) url++; t = url + strlen(url); assert(*t == '\0'); token = NULL; while (t > url) { t--; if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) { token = t + 1; break; } } while (t > url && xisspace(*t)) *(t--) = '\0'; debug(33, 5) ("parseHttpRequest: URI is '%s'\n", url); if (token == NULL) { debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n");#if RELAXED_HTTP_PARSER http_ver = (float) 0.9; /* wild guess */#else return parseHttpRequestAbort(conn, "error:missing-http-ident");#endif } else { http_ver = (float) atof(token + 5); } /* * Process headers after request line */ req_hdr = strtok(NULL, null_string); header_sz = req_sz - (req_hdr - inbuf); if (0 == header_sz) { debug(33, 3) ("parseHttpRequest: header_sz == 0\n"); *status = 0; return NULL; } assert(header_sz > 0); debug(33, 3) ("parseHttpRequest: req_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -