# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: henrik@henriknordstrom.net-20080407231553-\ # djj9wfqy63noyuy4 # target_branch: http://www.squid-cache.org/bzr/squid3/branches\ # /SQUID_3_0/ # testament_sha1: 309c90bdcc487ef284f323dbc5e63b6eb80c0302 # timestamp: 2008-04-08 01:16:38 +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/HttpMsg.cc' --- src/HttpMsg.cc 2007-08-13 23:20:50 +0000 +++ src/HttpMsg.cc 2008-04-07 23:15:53 +0000 @@ -1,6 +1,6 @@ /* - * $Id: HttpMsg.cc,v 1.43 2007/08/13 17:20:51 hno Exp $ + * $Id: HttpMsg.cc,v 1.44 2007/12/21 23:50:24 hno Exp $ * * DEBUG: section 74 HTTP Message * AUTHOR: Alex Rousskov @@ -153,6 +153,14 @@ // TODO: Remove? httpReplyParseStep() should do similar checks const size_t hdr_len = headersEnd(buf->content(), buf->contentSize()); + // TODO: move to httpReplyParseStep() + if (hdr_len > Config.maxReplyHeaderSize || hdr_len <= 0 && (size_t)buf->contentSize() > Config.maxReplyHeaderSize) { + debugs(58, 1, "HttpMsg::parse: Too large reply header (" << + hdr_len << " > " << Config.maxReplyHeaderSize); + *error = HTTP_HEADER_TOO_LARGE; + return false; + } + if (hdr_len <= 0) { debugs(58, 3, "HttpMsg::parse: failed to find end of headers " << "(eof: " << eof << ") in '" << buf->content() << "'"); @@ -163,14 +171,6 @@ return false; } - // TODO: move to httpReplyParseStep() - if (hdr_len > Config.maxReplyHeaderSize) { - debugs(58, 1, "HttpMsg::parse: Too large reply header (" << - hdr_len << " > " << Config.maxReplyHeaderSize); - *error = HTTP_HEADER_TOO_LARGE; - return false; - } - if (!sanityCheckStartLine(buf, error)) { debugs(58,1, HERE << "first line of HTTP message is invalid"); *error = HTTP_INVALID_HEADER; === 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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 tK12hxofbB+0bGiD4FEf/F3JFOFCQjy5iZA=