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

📄 client_side.c

📁 -
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * $Id: client_side.c,v 1.440.2.8 1999/05/10 16:00:40 wessels Exp $ * * DEBUG: section 33    Client-side Routines * AUTHOR: Duane Wessels * * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * *  Squid is the result of efforts by numerous individuals from the *  Internet community.  Development is led by Duane Wessels of the *  National Laboratory for Applied Network Research and funded by the *  National Science Foundation.  Squid is Copyrighted (C) 1998 by *  Duane Wessels and the University of California San Diego.  Please *  see the COPYRIGHT file for full details.  Squid incorporates *  software developed and/or copyrighted by other sources.  Please see *  the CREDITS file for full details. * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. *   *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. *   *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */#include "squid.h"#if IPF_TRANSPARENT#if HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#include <netinet/tcp.h>#include <net/if.h>#include <ip_compat.h>#include <ip_fil.h>#include <ip_nat.h>#endif#if LINGERING_CLOSE#define comm_close comm_lingering_close#endifstatic const char *const crlf = "\r\n";#define REQUEST_BUF_SIZE 4096#define FAILURE_MODE_TIME 300/* Local functions */static CWCB clientWriteComplete;static PF clientReadRequest;static PF connStateFree;static PF requestTimeout;static int clientCheckTransferDone(clientHttpRequest *);static int clientGotNotEnough(clientHttpRequest *);static void checkFailureRatio(err_type, hier_code);static void clientProcessMiss(clientHttpRequest *);static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *);static RH clientRedirectDone;static STCB clientHandleIMSReply;static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request);static int checkAccelOnly(clientHttpRequest *);#if USE_IDENTstatic IDCB clientIdentDone;#endifstatic int clientOnlyIfCached(clientHttpRequest * http);static STCB clientSendMoreData;static STCB clientCacheHit;static void clientSetKeepaliveFlag(clientHttpRequest *);static void clientInterpretRequestHeaders(clientHttpRequest *);static void clientProcessRequest(clientHttpRequest *);static void clientProcessExpired(void *data);static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);static int clientCachable(clientHttpRequest * http);static int clientHierarchical(clientHttpRequest * http);static int clientCheckContentLength(request_t * r);static int httpAcceptDefer(void);static log_type clientProcessRequest2(clientHttpRequest * http);static intcheckAccelOnly(clientHttpRequest * http){    /* return TRUE if someone makes a proxy request to us and     * we are in httpd-accel only mode */    if (!Config2.Accel.on)	return 0;    if (Config.onoff.accel_with_proxy)	return 0;    if (http->request->protocol == PROTO_CACHEOBJ)	return 0;    if (http->flags.accel)	return 0;    return 1;}#if USE_IDENTvoidclientIdentDone(const char *ident, void *data){    ConnStateData *conn = data;    if (ident)	xstrncpy(conn->ident, ident, sizeof(conn->ident));    else	xstrncpy(conn->ident, "-", sizeof(conn->ident));}#endifvoidclientAccessCheck(void *data){    clientHttpRequest *http = data;    ConnStateData *conn = http->conn;    const char *browser;    if (checkAccelOnly(http)) {	clientAccessCheckDone(0, http);	return;    }    browser = httpHeaderGetStr(&http->request->header, HDR_USER_AGENT);    http->acl_checklist = aclChecklistCreate(Config.accessList.http,	http->request,	conn->peer.sin_addr,	conn->me.sin_addr,	browser,	conn->ident);#if USE_IDENT    /*     * hack for ident ACL. It needs to get full addresses, and a     * place to store the ident result on persistent connections...     */    http->acl_checklist->conn = conn;    cbdataLock(http->acl_checklist->conn);#endif    aclNBCheck(http->acl_checklist, clientAccessCheckDone, http);}/* * returns true if client specified that the object must come from the cache * witout contacting origin server */static intclientOnlyIfCached(clientHttpRequest * http){    const request_t *r = http->request;    assert(r);    return r->cache_control &&	EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);}StoreEntry *clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags){    StoreEntry *e;    /*     * For erroneous requests, we might not have a h->request,     * so make a fake one.     */    if (h->request == NULL)	h->request = requestLink(requestCreate(m, PROTO_NONE, NULL));    e = storeCreateEntry(h->uri, h->log_uri, flags, m);    storeClientListAdd(e, h);#if DELAY_POOLS    delaySetStoreClient(e, h, delayClient(h->request));#endif    storeClientCopy(e, 0, 0, CLIENT_SOCK_SZ,	memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, h);    return e;}voidclientAccessCheckDone(int answer, void *data){    clientHttpRequest *http = data;    int page_id = -1;    http_status status;    ErrorState *err = NULL;    debug(33, 5) ("clientAccessCheckDone: '%s' answer=%d\n", http->uri, answer);    http->acl_checklist = NULL;    if (answer == ACCESS_ALLOWED) {	safe_free(http->uri);	http->uri = xstrdup(urlCanonical(http->request));	assert(http->redirect_state == REDIRECT_NONE);	http->redirect_state = REDIRECT_PENDING;	redirectStart(http, clientRedirectDone, http);    } else {	debug(33, 5) ("Access Denied: %s\n", http->uri);	debug(33, 5) ("AclMatchedName = %s\n",	    AclMatchedName ? AclMatchedName : "<null>");	/*	 * NOTE: get page_id here, based on AclMatchedName because	 * if USE_DELAY_POOLS is enabled, then AclMatchedName gets	 * clobbered in the clientCreateStoreEntry() call	 * just below.  Pedro Ribeiro <pribeiro@isel.pt>	 */	page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName);	http->log_type = LOG_TCP_DENIED;	http->entry = clientCreateStoreEntry(http, http->request->method,	    null_request_flags);	if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) {	    if (!http->flags.accel) {		/* Proxy authorisation needed */		status = HTTP_PROXY_AUTHENTICATION_REQUIRED;	    } else {		/* WWW authorisation needed */		status = HTTP_UNAUTHORIZED;	    }	    if (page_id <= 0)		page_id = ERR_CACHE_ACCESS_DENIED;	} else {	    status = HTTP_FORBIDDEN;	    if (page_id <= 0)		page_id = ERR_ACCESS_DENIED;	}	err = errorCon(page_id, status);	err->request = requestLink(http->request);	err->src_addr = http->conn->peer.sin_addr;	errorAppendEntry(http->entry, err);    }}static voidclientRedirectDone(void *data, char *result){    clientHttpRequest *http = data;    request_t *new_request = NULL;    request_t *old_request = http->request;    debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri,	result ? result : "NULL");    assert(http->redirect_state == REDIRECT_PENDING);    http->redirect_state = REDIRECT_DONE;    if (result) {	http_status status = atoi(result);	if (status == 301 || status == 302) {	    char *t = result;	    if ((t = strchr(result, ':')) != NULL) {		http->redirect.status = status;		http->redirect.location = xstrdup(t + 1);	    } else {		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);	    }	}	if (strcmp(result, http->uri))	    new_request = urlParse(old_request->method, result);    }    if (new_request) {	safe_free(http->uri);	http->uri = xstrdup(urlCanonical(new_request));	new_request->http_ver = old_request->http_ver;	httpHeaderAppend(&new_request->header, &old_request->header);	new_request->client_addr = old_request->client_addr;	new_request->my_addr = old_request->my_addr;	new_request->flags.redirected = 1;	if (old_request->body) {	    new_request->body = xmalloc(old_request->body_sz);	    xmemcpy(new_request->body, old_request->body, old_request->body_sz);	    new_request->body_sz = old_request->body_sz;	}	requestUnlink(old_request);	http->request = requestLink(new_request);    }    clientInterpretRequestHeaders(http);    fd_note(http->conn->fd, http->uri);    clientProcessRequest(http);}static voidclientProcessExpired(void *data){    clientHttpRequest *http = data;    char *url = http->uri;    StoreEntry *entry = NULL;    debug(33, 3) ("clientProcessExpired: '%s'\n", http->uri);    assert(http->entry->lastmod >= 0);    /*     * check if we are allowed to contact other servers     * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return      *      a stale entry *if* it matches client requirements     */    if (clientOnlyIfCached(http)) {	clientProcessOnlyIfCachedMiss(http);	return;    }    http->request->flags.refresh = 1;    http->old_entry = http->entry;    /*     * Assert that 'http' is already a client of old_entry.  If      * it is not, then the beginning of the object data might get     * freed from memory before we need to access it.     */    assert(storeClientListSearch(http->old_entry->mem_obj, http));    entry = storeCreateEntry(url,	http->log_uri,	http->request->flags,	http->request->method);    /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */    storeClientListAdd(entry, http);#if DELAY_POOLS    /* delay_id is already set on original store client */    delaySetStoreClient(entry, http, delayClient(http->request));#endif    entry->lastmod = http->old_entry->lastmod;    debug(33, 5) ("clientProcessExpired: lastmod %d\n", (int) entry->lastmod);    entry->refcount++;		/* EXPIRED CASE */    http->entry = entry;    http->out.offset = 0;    fwdStart(http->conn->fd, http->entry, http->request,	http->conn->peer.sin_addr, http->conn->me.sin_addr);    /* Register with storage manager to receive updates when data comes in. */    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))	debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED object\n");    storeClientCopy(entry,	http->out.offset,	http->out.offset,	CLIENT_SOCK_SZ,	memAllocate(MEM_CLIENT_SOCK_BUF),	clientHandleIMSReply,	http);}static intclientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, request_t * request){    const http_status status = new_entry->mem_obj->reply->sline.status;    if (0 == status) {	debug(33, 5) ("clientGetsOldEntry: YES, broken HTTP reply\n");	return 1;    }    /* If the reply is a failure then send the old object as a last     * resort */    if (status >= 500 && status < 600) {	debug(33, 2) ("clientGetsOldEntry: YES, failure reply=%d\n", status);	return 1;    }    /* If the reply is anything but "Not Modified" then     * we must forward it to the client */    if (HTTP_NOT_MODIFIED != status) {	debug(33, 5) ("clientGetsOldEntry: NO, reply=%d\n", status);	return 0;    }    /* If the client did not send IMS in the request, then it     * must get the old object, not this "Not Modified" reply */    if (!request->flags.ims) {	debug(33, 5) ("clientGetsOldEntry: YES, no client IMS\n");	return 1;    }    /* If the client IMS time is prior to the entry LASTMOD time we     * need to send the old object */    if (modifiedSince(old_entry, request)) {	debug(33, 5) ("clientGetsOldEntry: YES, modified since %d\n",	    (int) request->ims);	return 1;    }    debug(33, 5) ("clientGetsOldEntry: NO, new one is fine\n");    return 0;}static voidclientHandleIMSReply(void *data, char *buf, ssize_t size){    clientHttpRequest *http = data;    StoreEntry *entry = http->entry;    MemObject *mem;    const char *url = storeUrl(entry);    int unlink_request = 0;    StoreEntry *oldentry;    int recopy = 1;    http_status status;    debug(33, 3) ("clientHandleIMSReply: %s, %d bytes\n", url, (int) size);    if (entry == NULL) {	memFree(buf, MEM_CLIENT_SOCK_BUF);	return;    }    if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {	memFree(buf, MEM_CLIENT_SOCK_BUF);	return;    }    mem = entry->mem_obj;    status = mem->reply->sline.status;    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {	debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url);	/* We have an existing entry, but failed to validate it */	/* Its okay to send the old one anyway */	http->log_type = LOG_TCP_REFRESH_FAIL_HIT;	storeUnregister(entry, http);	storeUnlockObject(entry);	entry = http->entry = http->old_entry;	entry->refcount++;    } else if (STORE_PENDING == entry->store_status && 0 == status) {

⌨️ 快捷键说明

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