⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client_side.c

📁 -
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif    request->cache_control = httpHeaderGetCc(req_hdr);    if (request->method == METHOD_TRACE) {	request->max_forwards = httpHeaderGetInt(req_hdr, HDR_MAX_FORWARDS);    }    if (clientCachable(http))	request->flags.cachable = 1;    if (clientHierarchical(http))	request->flags.hierarchical = 1;    debug(33, 5) ("clientInterpretRequestHeaders: REQ_NOCACHE = %s\n",	request->flags.nocache ? "SET" : "NOT SET");    debug(33, 5) ("clientInterpretRequestHeaders: REQ_CACHABLE = %s\n",	request->flags.cachable ? "SET" : "NOT SET");    debug(33, 5) ("clientInterpretRequestHeaders: REQ_HIERARCHICAL = %s\n",	request->flags.hierarchical ? "SET" : "NOT SET");}/* * clientSetKeepaliveFlag() sets request->flags.proxy_keepalive. * This is the client-side persistent connection flag.  We need * to set this relatively early in the request processing * to handle hacks for broken servers and clients. */static voidclientSetKeepaliveFlag(clientHttpRequest * http){    request_t *request = http->request;    const HttpHeader *req_hdr = &request->header;    debug(33, 3) ("clientSetKeepaliveFlag: http_ver = %3.1f\n",	request->http_ver);    debug(33, 3) ("clientSetKeepaliveFlag: method = %s\n",	RequestMethodStr[request->method]);    if (httpMsgIsPersistent(request->http_ver, req_hdr))	request->flags.proxy_keepalive = 1;}static intclientCheckContentLength(request_t * r){    /* We only require a content-length for "upload" methods */    if (!pumpMethod(r->method))	return 1;    if (httpHeaderGetInt(&r->header, HDR_CONTENT_LENGTH) < 0)	return 0;    return 1;}static intclientCachable(clientHttpRequest * http){    const char *url = http->uri;    request_t *req = http->request;    method_t method = req->method;    aclCheck_t ch;    memset(&ch, '\0', sizeof(ch));    /*     * Hopefully, nobody really wants 'no_cache' by client's IP     * address, but if they do, this should work if they use IP     * addresses in their ACLs, or if the client's address is in     * the FQDN cache.     *     * This may not work yet for 'dst' and 'dst_domain' ACLs.     */    ch.src_addr = http->conn->peer.sin_addr;    ch.my_addr = http->conn->me.sin_addr;    ch.request = http->request;    /*     * aclCheckFast returns 1 for ALLOW and 0 for DENY.  The default     * is ALLOW, so we require 'no_cache DENY foo' in squid.conf     * to indicate uncachable objects.     */    if (!aclCheckFast(Config.accessList.noCache, &ch))	return 0;    if (req->protocol == PROTO_HTTP)	return httpCachable(method);    /* FTP is always cachable */    if (req->protocol == PROTO_GOPHER)	return gopherCachable(url);    if (req->protocol == PROTO_WAIS)	return 0;    if (method == METHOD_CONNECT)	return 0;    if (method == METHOD_TRACE)	return 0;    if (req->protocol == PROTO_CACHEOBJ)	return 0;    return 1;}/* Return true if we can query our neighbors for this object */static intclientHierarchical(clientHttpRequest * http){    const char *url = http->uri;    request_t *request = http->request;    method_t method = request->method;    const wordlist *p = NULL;    /* IMS needs a private key, so we can use the hierarchy for IMS only     * if our neighbors support private keys */    if (request->flags.ims && !neighbors_do_private_keys)	return 0;    if (request->flags.auth)	return 0;    if (method == METHOD_TRACE)	return 1;    if (method != METHOD_GET)	return 0;    /* scan hierarchy_stoplist */    for (p = Config.hierarchy_stoplist; p; p = p->next)	if (strstr(url, p->key))	    return 0;    if (request->flags.loopdetect)	return 0;    if (request->protocol == PROTO_HTTP)	return httpCachable(method);    if (request->protocol == PROTO_GOPHER)	return gopherCachable(url);    if (request->protocol == PROTO_WAIS)	return 0;    if (request->protocol == PROTO_CACHEOBJ)	return 0;    return 1;}intisTcpHit(log_type code){    /* this should be a bitmap for better optimization */    if (code == LOG_TCP_HIT)	return 1;    if (code == LOG_TCP_IMS_HIT)	return 1;    if (code == LOG_TCP_REFRESH_FAIL_HIT)	return 1;    if (code == LOG_TCP_REFRESH_HIT)	return 1;    if (code == LOG_TCP_NEGATIVE_HIT)	return 1;    if (code == LOG_TCP_MEM_HIT)	return 1;    if (code == LOG_TCP_OFFLINE_HIT)	return 1;    return 0;}/* * returns true if If-Range specs match reply, false otherwise */static intclientIfRangeMatch(clientHttpRequest * http, HttpReply * rep){    const TimeOrTag spec = httpHeaderGetTimeOrTag(&http->request->header, HDR_IF_RANGE);    /* check for parsing falure */    if (!spec.valid)	return 0;    /* got an ETag? */    if (spec.tag.str) {	ETag rep_tag = httpHeaderGetETag(&rep->header, HDR_ETAG);	debug(33, 3) ("clientIfRangeMatch: ETags: %s and %s\n",	    spec.tag.str, rep_tag.str ? rep_tag.str : "<none>");	if (!rep_tag.str)	    return 0;		/* entity has no etag to compare with! */	if (spec.tag.weak || rep_tag.weak) {	    debug(33, 1) ("clientIfRangeMatch: Weak ETags are not allowed in If-Range: %s ? %s\n",		spec.tag.str, rep_tag.str);	    return 0;		/* must use strong validator for sub-range requests */	}	return etagIsEqual(&rep_tag, &spec.tag);    }    /* got modification time? */    if (spec.time >= 0) {	return http->entry->lastmod <= spec.time;    }    assert(0);			/* should not happen */    return 0;}/* adds appropriate Range headers if needed */static voidclientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep){    HttpHeader *hdr = rep ? &rep->header : 0;    const char *range_err = NULL;    assert(http->request->range);    /* check if we still want to do ranges */    if (!rep)	range_err = "no [parse-able] reply";    else if (rep->sline.status != HTTP_OK)	range_err = "wrong status code";    else if (httpHeaderHas(hdr, HDR_CONTENT_RANGE))	range_err = "origin server does ranges";    else if (rep->content_length < 0)	range_err = "unknown length";    else if (rep->content_length != http->entry->mem_obj->reply->content_length)	range_err = "INCONSISTENT length";	/* a bug? */    else if (httpHeaderHas(&http->request->header, HDR_IF_RANGE) && !clientIfRangeMatch(http, rep))	range_err = "If-Range match failed";    else if (!httpHdrRangeCanonize(http->request->range, rep->content_length))	range_err = "canonization failed";    else if (httpHdrRangeIsComplex(http->request->range))	range_err = "too complex range header";    /* get rid of our range specs on error */    if (range_err) {	debug(33, 2) ("clientBuildRangeHeader: will not do ranges: %s.\n", range_err);	httpHdrRangeDestroy(http->request->range);	http->request->range = NULL;    } else {	const int spec_count = http->request->range->specs.count;	debug(33, 2) ("clientBuildRangeHeader: range spec count: %d clen: %d\n",	    spec_count, rep->content_length);	assert(spec_count > 0);	/* ETags should not be returned with Partial Content replies? */	httpHeaderDelById(hdr, HDR_ETAG);	/* append appropriate header(s) */	if (spec_count == 1) {	    HttpHdrRangePos pos = HttpHdrRangeInitPos;	    const HttpHdrRangeSpec *spec = httpHdrRangeGetSpec(http->request->range, &pos);	    assert(spec);	    /* append Content-Range */	    httpHeaderAddContRange(hdr, *spec, rep->content_length);	    /* set new Content-Length to the actual number of OCTETs	     * transmitted in the message-body */	    httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);	    httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, spec->length);	    debug(33, 2) ("clientBuildRangeHeader: actual content length: %d\n", spec->length);	} else {	    /* multipart! */	    /* generate boundary string */	    http->range_iter.boundary = httpHdrRangeBoundaryStr(http);	    /* delete old Content-Type, add ours */	    httpHeaderDelById(hdr, HDR_CONTENT_TYPE);	    httpHeaderPutStrf(hdr, HDR_CONTENT_TYPE,		"multipart/byteranges; boundary=\"%s\"",		strBuf(http->range_iter.boundary));	    /* no need for Content-Length in multipart responses */	    /* but we must delete the original one if we cannot (yet)	     * calculate the actual length */	    httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);	}    }}/* filters out unwanted entries from original reply header * adds extra entries if we have more info than origin server * adds Squid specific entries */static voidclientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep){    HttpHeader *hdr = &rep->header;    int is_hit = isTcpHit(http->log_type);    request_t *request = http->request;#if DONT_FILTER_THESE    /* but you might want to if you run Squid as an HTTP accelerator */    /* httpHeaderDelById(hdr, HDR_ACCEPT_RANGES); */    httpHeaderDelById(hdr, HDR_ETAG);#endif    httpHeaderDelById(hdr, HDR_PROXY_CONNECTION);    /* here: Keep-Alive is a field-name, not a connection directive! */    httpHeaderDelByName(hdr, "Keep-Alive");    /* remove Set-Cookie if a hit */    if (is_hit)	httpHeaderDelById(hdr, HDR_SET_COOKIE);    /* handle Connection header */    if (httpHeaderHas(hdr, HDR_CONNECTION)) {	/* anything that matches Connection list member will be deleted */	String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION);	const HttpHeaderEntry *e;	HttpHeaderPos pos = HttpHeaderInitPos;	/*	 * think: on-average-best nesting of the two loops (hdrEntry	 * and strListItem) @?@	 */	/*	 * maybe we should delete standard stuff ("keep-alive","close")	 * from strConnection first?	 */	while ((e = httpHeaderGetEntry(hdr, &pos))) {	    if (strListIsMember(&strConnection, strBuf(e->name), ','))		httpHeaderDelAt(hdr, pos);	}	httpHeaderDelById(hdr, HDR_CONNECTION);	stringClean(&strConnection);    }    /* Handle Ranges */    if (request->range)	clientBuildRangeHeader(http, rep);    /*     * Add Age header, not that our header must replace Age headers     * from other caches if any     */    if (http->entry->timestamp > 0) {	httpHeaderDelById(hdr, HDR_AGE);	/*	 * we do not follow HTTP/1.1 precisely here becuase we rely	 * on Date header when computing entry->timestamp; we should	 * be using _request_ time if Date header is not available	 * or if it is out of sync	 */	httpHeaderPutInt(hdr, HDR_AGE,	    http->entry->timestamp <= squid_curtime ?	    squid_curtime - http->entry->timestamp : 0);    }    /* Append X-Cache */    httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",	is_hit ? "HIT" : "MISS", getMyHostname());#if USE_CACHE_DIGESTS    /* Append X-Cache-Lookup: -- temporary hack, to be removed @?@ @?@ */    httpHeaderPutStrf(hdr, HDR_X_CACHE_LOOKUP, "%s from %s:%d",	http->lookup_type ? http->lookup_type : "NONE",	getMyHostname(), Config.Port.http->i);#endif    /*     * Clear keepalive for NON-HEAD requests with invalid content length     */    if (request->method != METHOD_HEAD)	if (http->entry->mem_obj->reply->content_length < 0)	    request->flags.proxy_keepalive = 0;    /* Signal keep-alive if needed */    httpHeaderPutStr(hdr,	http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION,	request->flags.proxy_keepalive ? "keep-alive" : "close");#if ADD_X_REQUEST_URI    /*     * Knowing the URI of the request is useful when debugging persistent     * connections in a client; we cannot guarantee the order of http headers,     * but X-Request-URI is likely to be the very last header to ease use from a     * debugger [hdr->entries.count-1].     */    httpHeaderPutStr(hdr, HDR_X_REQUEST_URI,	http->entry->mem_obj->url ? http->entry->mem_obj->url : http->uri);#endif}static HttpReply *clientBuildReply(clientHttpRequest * http, const char *buf, size_t size){    HttpReply *rep = httpReplyCreate();    if (httpReplyParse(rep, buf)) {	/* enforce 1.0 reply version */	rep->sline.version = 1.0;	/* do header conversions */	clientBuildReplyHeader(http, rep);	/* if we do ranges, change status to "Partial Content" */	if (http->request->range)	    httpStatusLineSet(&rep->sline, rep->sline.version, HTTP_PARTIAL_CONTENT, NULL);    } else {	/* parsing failure, get rid of the invalid reply */	httpReplyDestroy(rep);	rep = NULL;	/* if we were going to do ranges, backoff */	if (http->request->range)	    clientBuildRangeHeader(http, rep);	/* will fail and destroy request->range */    }    return rep;}/* * clientCacheHit should only be called until the HTTP reply headers * have been parsed.  Normally this should be a single call, but * it might take more than one.  As soon as we have the headers, * we hand off to clientSendMoreData, clientProcessExpired, or * clientProcessMiss. */static voidclientCacheHit(void *data, char *buf, ssize_t size){    clientHttpRequest *http = data;    StoreEntry *e = http->entry;    MemObject *mem;    request_t *r = http->request;    debug(33, 3) ("clientCacheHit: %s, %d bytes\n", http->uri, (int) size);    if (http->entry == NULL) {	memFree(buf, MEM_CLIENT_SOCK_BUF);	debug(33, 3) ("clientCacheHit: request aborted\n");	return;    } else if (size < 0) {	/* swap in failure */	memFree(buf, MEM_CLIENT_SOCK_BUF);	debug(33, 3) ("clientCacheHit: swapin failure for %s\n", http->uri);	http->log_type = LOG_TCP_SWAPFAIL_MISS;	if ((e = http->entry)) {	    http->entry = NULL;	    storeUnregister(e, http);	    storeUnlockObject(e);	}	clientProcessMiss(http);	return;    }    assert(size > 0);    mem = e->mem_obj;    assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));    if (mem->reply->sline.status == 0) {	/*	 * we don't have full reply headers yet; either wait for more or	 * punt to clientProcessMiss.	 */	if (e->mem_status == IN_MEMORY || e->store_status == STORE_OK) {	    memFree(buf, MEM_CLIENT_SOCK_BUF);	    clientProcessMiss(http);	} else if (size == CLIENT_SOCK_SZ && http->out.offset == 0) {	    memFree(buf, MEM_CLIENT_SOCK_BUF);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -