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

📄 client_side.c

📁 -
💻 C
📖 第 1 页 / 共 5 页
字号:
	    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 + -