# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: henrik@henriknordstrom.net-20080406003849-\ # 00au6rconzwzcbdv # target_branch: file:///data/bzr/squid3/branches/SQUID_3_0/ # testament_sha1: beea03b1b1acfed3b0a9f4df661b66b86fe9d102 # timestamp: 2008-04-06 02:39:24 +0200 # source_branch: http://www.henriknordstrom.net/bzr/squid3/hno\ # /largeresp-3.0 # base_revision_id: amosjeffries@squid-cache.org-20080405025842-\ # kfyafifqcq0retgb # # Begin patch === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2007-11-26 20:09:54 +0000 +++ src/HttpReply.cc 2008-03-30 14:29:57 +0000 @@ -496,3 +496,17 @@ return expectBody; } + +HttpReply * +HttpReply::clone() const +{ + HttpReply *rep = new HttpReply(); + rep->header.append(&header); + rep->hdrCacheInit(); + rep->hdr_sz = hdr_sz; + rep->http_ver = http_ver; + rep->pstate = pstate; + rep->protocol = protocol; + rep->sline = sline; + return rep; +} === modified file 'src/HttpReply.h' --- src/HttpReply.h 2007-08-13 23:20:50 +0000 +++ src/HttpReply.h 2008-03-30 14:29:57 +0000 @@ -122,6 +122,11 @@ void packHeadersInto(Packer * p) const; + /// Clone this reply. + /// Could be done as a copy-contructor but we do not want to + /// accidently copy a HttpReply.. + HttpReply *clone() const; + private: /* initialize */ void init(); === modified file 'src/MemBuf.h' --- src/MemBuf.h 2006-08-21 06:50:40 +0000 +++ src/MemBuf.h 2008-04-06 00:35:11 +0000 @@ -1,7 +1,7 @@ /* - * $Id: MemBuf.h,v 1.8 2006/08/21 00:50:41 robertc Exp $ + * $Id: MemBuf.h,v 1.9 2007/12/21 23:48:04 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -60,6 +60,7 @@ // these space-related methods assume no growth and allow 0-termination char *space() { return buf + size; } // space to add data + char *space(mb_size_t required) { if (size + required > capacity) grow(size + required); return buf + size; } // space to add data mb_size_t spaceSize() const; bool hasSpace() const { return size+1 < capacity; } === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2008-03-14 04:45:16 +0000 +++ src/client_side_reply.cc 2008-03-30 14:29:57 +0000 @@ -352,68 +352,47 @@ sendClientOldEntry(); } - // we have a partial reply from the origin - else if (STORE_PENDING == http->storeEntry()->store_status && 0 == status) { - // header is too large, send old entry - - if (reqsize >= HTTP_REQBUF_SZ) { - debugs(88, 3, "handleIMSReply: response from origin is too large '" << http->storeEntry()->url() << "', sending old entry to client" ); - http->logType = LOG_TCP_REFRESH_FAIL; - sendClientOldEntry(); - } - - // everything looks fine, we're just waiting for more data - else { - debugs(88, 3, "handleIMSReply: incomplete headers for '" << http->storeEntry()->url() << "', waiting for more data" ); - reqofs = reqsize; - waitForMoreData(); - } - } - - // we have a reply from the origin + HttpReply *old_rep = (HttpReply *) old_entry->getReply(); + + // origin replied 304 + + if (status == HTTP_NOT_MODIFIED) { + http->logType = LOG_TCP_REFRESH_UNMODIFIED; + + // update headers on existing entry + HttpReply *old_rep = (HttpReply *) old_entry->getReply(); + old_rep->updateOnNotModified(http->storeEntry()->getReply()); + old_entry->timestampsSet(); + + // if client sent IMS + + if (http->request->flags.ims) { + // forward the 304 from origin + debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and forwarding 304 to client"); + sendClientUpstreamResponse(); + } else { + // send existing entry, it's still valid + debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and sending " << + old_rep->sline.status << " to client"); + sendClientOldEntry(); + } + } + + // origin replied with a non-error code + else if (status > HTTP_STATUS_NONE && status < HTTP_INTERNAL_SERVER_ERROR) { + // forward response from origin + http->logType = LOG_TCP_REFRESH_MODIFIED; + debugs(88, 3, "handleIMSReply: origin replied " << status << ", replacing existing entry and forwarding to client"); + sendClientUpstreamResponse(); + } + + // origin replied with an error else { - HttpReply *old_rep = (HttpReply *) old_entry->getReply(); - - // origin replied 304 - - if (status == HTTP_NOT_MODIFIED) { - http->logType = LOG_TCP_REFRESH_UNMODIFIED; - - // update headers on existing entry - HttpReply *old_rep = (HttpReply *) old_entry->getReply(); - old_rep->updateOnNotModified(http->storeEntry()->getReply()); - old_entry->timestampsSet(); - - // if client sent IMS - - if (http->request->flags.ims) { - // forward the 304 from origin - debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and forwarding 304 to client"); - sendClientUpstreamResponse(); - } else { - // send existing entry, it's still valid - debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and sending " << - old_rep->sline.status << " to client"); - sendClientOldEntry(); - } - } - - // origin replied with a non-error code - else if (status > HTTP_STATUS_NONE && status < HTTP_INTERNAL_SERVER_ERROR) { - // forward response from origin - http->logType = LOG_TCP_REFRESH_MODIFIED; - debugs(88, 3, "handleIMSReply: origin replied " << status << ", replacing existing entry and forwarding to client"); - sendClientUpstreamResponse(); - } - - // origin replied with an error - else { - // ignore and let client have old entry - http->logType = LOG_TCP_REFRESH_FAIL; - debugs(88, 3, "handleIMSReply: origin replied with error " << - status << ", sending old entry (" << old_rep->sline.status << ") to client"); - sendClientOldEntry(); - } + // ignore and let client have old entry + http->logType = LOG_TCP_REFRESH_FAIL; + debugs(88, 3, "handleIMSReply: origin replied with error " << + status << ", sending old entry (" << old_rep->sline.status << ") to client"); + sendClientOldEntry(); } } @@ -472,33 +451,6 @@ /* update size of the request */ reqsize = result.length + reqofs; - if (e->getReply()->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) { - processMiss(); - } else if (result.length + reqofs >= HTTP_REQBUF_SZ - && http->out.offset == 0) { - processMiss(); - } else { - debugs(88, 3, "clientCacheHit: waiting for HTTP reply headers"); - reqofs += result.length; - assert(reqofs <= HTTP_REQBUF_SZ); - /* get the next users' buffer */ - StoreIOBuffer tempBuffer; - tempBuffer.offset = http->out.offset + reqofs; - tempBuffer.length = next()->readBuffer.length - reqofs; - tempBuffer.data = next()->readBuffer.data + reqofs; - storeClientCopy(sc, e, - tempBuffer, CacheHit, this); - } - - return; - } - /* * Got the headers, now grok them */ @@ -1371,32 +1323,14 @@ void -clientReplyContext::buildReply(const char *buf, size_t size) +clientReplyContext::cloneReply() { - size_t k = headersEnd(buf, size); - - if (!k) - return; - assert(reply == NULL); - HttpReply *rep = new HttpReply; + HttpReply *rep = http->storeEntry()->getReply()->clone(); reply = HTTPMSGLOCK(rep); - if (!reply->parseCharBuf(buf, k)) { - /* parsing failure, get rid of the invalid reply */ - HTTPMSGUNLOCK(reply); - - if (http->request->range) { - debugs(0,0,HERE << "look for bug here"); - /* this will fail and destroy request->range */ - // clientBuildRangeHeader(http, reply); - } - - return; - } - /* enforce 1.0 reply version */ reply->sline.version = HttpVersion(1,0); @@ -1703,32 +1637,6 @@ return getNextNode(); } -void -clientReplyContext::waitForMoreData () -{ - debugs(88, 5, "clientReplyContext::waitForMoreData: Waiting for more data to parse reply headers in client side."); - /* We don't have enough to parse the metadata yet */ - /* TODO: the store should give us out of band metadata and - * obsolete this routine - */ - /* wait for more to arrive */ - startSendProcess(); -} - -void -clientReplyContext::startSendProcess() -{ - debugs(88, 5, "clientReplyContext::startSendProcess: triggering store read to SendMoreData"); - assert(reqofs <= HTTP_REQBUF_SZ); - /* TODO: copy into the supplied buffer */ - StoreIOBuffer tempBuffer; - tempBuffer.offset = reqofs; - tempBuffer.length = next()->readBuffer.length - reqofs; - tempBuffer.data = next()->readBuffer.data + reqofs; - storeClientCopy(sc, http->storeEntry(), - tempBuffer, SendMoreData, this); -} - /* * Calculates the maximum size allowed for an HTTP response */ @@ -1841,8 +1749,10 @@ http->loggingEntry(http->storeEntry()); ssize_t body_size = reqofs - reply->hdr_sz; - - assert(body_size >= 0); + if (body_size < 0) { + reqofs = reply->hdr_sz; + body_size = 0; + } debugs(88, 3, "clientReplyContext::sendMoreData: Appending " << (int) body_size << " bytes after " << reply->hdr_sz << @@ -1872,7 +1782,7 @@ StoreIOBuffer tempBuffer; char *buf = next()->readBuffer.data; - char *body_buf = buf + reply->hdr_sz; + char *body_buf = buf + reply->hdr_sz - next()->readBuffer.offset; //Server side may disable ranges under some circumstances. @@ -1916,23 +1826,11 @@ char *body_buf = buf; - /* This is always valid until we get the headers as metadata from - * storeClientCopy. - * Then it becomes reqofs == next->readBuffer.offset() - */ - assert(reqofs == 0 || flags.storelogiccomplete); - - if (flags.headersSent && buf != result.data) { + if (buf != result.data) { /* we've got to copy some data */ assert(result.length <= next()->readBuffer.length); xmemcpy(buf, result.data, result.length); body_buf = buf; - } else if (!flags.headersSent && - buf + reqofs !=result.data) { - /* we've got to copy some data */ - assert(result.length + reqofs <= next()->readBuffer.length); - xmemcpy(buf + reqofs, result.data, result.length); - body_buf = buf; } /* We've got the final data to start pushing... */ @@ -1971,38 +1869,23 @@ return; } - buildReply(buf, reqofs); - - if (reply) { - - /* handle headers */ - - if (Config.onoff.log_mime_hdrs) { - size_t k; - - if ((k = headersEnd(buf, reqofs))) { - safe_free(http->al.headers.reply); - http->al.headers.reply = (char *)xcalloc(k + 1, 1); - xstrncpy(http->al.headers.reply, buf, k); - } - } - - holdingBuffer = result; - processReplyAccess(); - return; - - } else if (reqofs < HTTP_REQBUF_SZ && entry->store_status == STORE_PENDING) { - waitForMoreData(); - return; - } else { - debugs(88, 0, "clientReplyContext::sendMoreData: Unable to parse reply headers within a single HTTP_REQBUF_SZ length buffer"); - StoreIOBuffer tempBuffer; - tempBuffer.flags.error = 1; - /* XXX FIXME: make an html error page here */ - sendStreamError(tempBuffer); - return; + cloneReply(); + + /* handle headers */ + + if (Config.onoff.log_mime_hdrs) { + size_t k; + + if ((k = headersEnd(buf, reqofs))) { + safe_free(http->al.headers.reply); + http->al.headers.reply = (char *)xcalloc(k + 1, 1); + xstrncpy(http->al.headers.reply, buf, k); + } } - fatal ("clientReplyContext::sendMoreData: Unreachable code reached \n"); + + holdingBuffer = result; + processReplyAccess(); + return; } === modified file 'src/client_side_reply.h' --- src/client_side_reply.h 2008-02-26 06:08:50 +0000 +++ src/client_side_reply.h 2008-03-30 14:29:57 +0000 @@ -124,15 +124,13 @@ bool errorInStream(StoreIOBuffer const &result, size_t const &sizeToProcess)const ; void sendStreamError(StoreIOBuffer const &result); void pushStreamData(StoreIOBuffer const &result, char *source); - void waitForMoreData (); clientStreamNode * next() const; - void startSendProcess(); StoreIOBuffer holdingBuffer; HttpReply *reply; void processReplyAccess(); static PF ProcessReplyAccessResult; void processReplyAccessResult(bool accessAllowed); - void buildReply(const char *buf, size_t size); + void cloneReply(); void buildReplyHeader (); bool alwaysAllowResponse(http_status sline) const; int checkTransferDone(); === modified file 'src/http.cc' --- src/http.cc 2007-11-19 05:00:58 +0000 +++ src/http.cc 2008-03-30 16:38:00 +0000 @@ -1213,12 +1213,16 @@ * handler until we get a notification from someone that * its okay to read again. */ - if (read_sz < 2) - return; + if (read_sz < 2) { + if (flags.headers_parsed) + return; + else + read_sz = 1024; + } if (flags.do_next_read) { - flags.do_next_read = 0; - entry->delayAwareRead(fd, readBuf->space(), read_sz, ReadReplyWrapper, this); + flags.do_next_read = 0; + entry->delayAwareRead(fd, readBuf->space(read_sz), read_sz, ReadReplyWrapper, this); } } # Begin bundle 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