# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: henrik@henriknordstrom.net-20080406013408-\ # 63h3likn45namhsa # target_branch: file:///data/bzr/squid3/trunk/ # testament_sha1: 861409ffadcaf9c00dc89f6cc2eb48d9dcb8bb25 # timestamp: 2008-04-06 03:37:48 +0200 # base_revision_id: henrik@henriknordstrom.net-20080406013113-\ # yff1f2iecpkhoq4t # # Begin patch === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2008-02-09 01:27:59 +0000 +++ src/HttpReply.cc 2008-03-15 19:09:52 +0000 @@ -551,3 +551,17 @@ } } } + +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 2008-03-16 00:50:50 +0000 +++ src/HttpReply.h 2008-03-16 00:53:56 +0000 @@ -127,6 +127,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/client_side_reply.cc' --- src/client_side_reply.cc 2008-03-20 23:20:58 +0000 +++ src/client_side_reply.cc 2008-03-30 13:34:01 +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 */ @@ -1390,32 +1342,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); @@ -1721,32 +1655,6 @@ } 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); -} - -void clientReplyContext::sendBodyTooLargeError() { IPAddress tmp_noaddr; tmp_noaddr.SetNoAddr(); // TODO: make a global const @@ -1835,8 +1743,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 << @@ -1866,7 +1776,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. @@ -1910,23 +1820,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... */ @@ -1965,38 +1863,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-03-16 22:10:18 +0000 +++ src/client_side_reply.h 2008-03-22 01:47:25 +0000 @@ -122,15 +122,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(); # Begin bundle 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