]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpReply.cc
Partial Revert and replace revno10132
[thirdparty/squid.git] / src / HttpReply.cc
CommitLineData
2ac76861 1
cb69b4c7 2/*
262a0e14 3 * $Id$
cb69b4c7 4 *
123abbe1 5 * DEBUG: section 58 HTTP Reply (Response)
cb69b4c7 6 * AUTHOR: Alex Rousskov
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
cb69b4c7 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
cb69b4c7 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
cb69b4c7 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
cb69b4c7 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
cb69b4c7 34 */
35
cb69b4c7 36#include "squid.h"
985c86bc 37#include "SquidTime.h"
528b2c61 38#include "Store.h"
8596962e 39#include "HttpReply.h"
528b2c61 40#include "HttpHdrContRange.h"
25b6a907 41#include "HttpHdrSc.h"
c0941a6a 42#include "acl/FilledChecklist.h"
0667cbfb 43#include "HttpRequest.h"
0eb49b6d 44#include "MemBuf.h"
cb69b4c7 45
46/* local constants */
47
1d7ab0f4 48/* If we receive a 304 from the origin during a cache revalidation, we must
49 * update the headers of the existing entry. Specifically, we need to update all
50 * end-to-end headers and not any hop-by-hop headers (rfc2616 13.5.3).
51 *
52 * This is not the whole story though: since it is possible for a faulty/malicious
53 * origin server to set headers it should not in a 304, we must explicitly ignore
54 * these too. Specifically all entity-headers except those permitted in a 304
55 * (rfc2616 10.3.5) must be ignored.
26ac0430 56 *
1d7ab0f4 57 * The list of headers we don't update is made up of:
58 * all hop-by-hop headers
59 * all entity-headers except Expires and Content-Location
60 */
2246b732 61static HttpHeaderMask Denied304HeadersMask;
26ac0430
AJ
62static http_hdr_type Denied304HeadersArr[] = {
63 // hop-by-hop headers
64 HDR_CONNECTION, HDR_KEEP_ALIVE, HDR_PROXY_AUTHENTICATE, HDR_PROXY_AUTHORIZATION,
65 HDR_TE, HDR_TRAILERS, HDR_TRANSFER_ENCODING, HDR_UPGRADE,
66 // entity headers
67 HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
68 HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_LAST_MODIFIED
69};
2246b732 70
2246b732 71/* module initialization */
72void
9bc73deb 73httpReplyInitModule(void)
2246b732 74{
8596962e 75 assert(HTTP_STATUS_NONE == 0); // HttpReply::parse() interface assumes that
97474590 76 httpHeaderMaskInit(&Denied304HeadersMask, 0);
8abf232c 77 httpHeaderCalcMask(&Denied304HeadersMask, Denied304HeadersArr, countof(Denied304HeadersArr));
2246b732 78}
79
26ac0430
AJ
80HttpReply::HttpReply() : HttpMsg(hoReply), date (0), last_modified (0),
81 expires (0), surrogate_control (NULL), content_range (NULL), keep_alive (0),
82 protoPrefix("HTTP/"), bodySizeMax(-2)
cb69b4c7 83{
06a5ae20 84 init();
cb69b4c7 85}
86
06a5ae20 87HttpReply::~HttpReply()
cb69b4c7 88{
06a5ae20 89 if (do_clean)
90 clean();
cb69b4c7 91}
92
93void
06a5ae20 94HttpReply::init()
cb69b4c7 95{
06a5ae20 96 httpBodyInit(&body);
97 hdrCacheInit();
98 httpStatusLineInit(&sline);
c99de607 99 pstate = psReadyToParseStartLine;
06a5ae20 100 do_clean = true;
cb69b4c7 101}
102
06a5ae20 103void HttpReply::reset()
cb69b4c7 104{
06a5ae20 105
8596962e 106 // reset should not reset the protocol; could have made protoPrefix a
107 // virtual function instead, but it is not clear whether virtual methods
108 // are allowed with MEMPROXY_CLASS() and whether some cbdata void*
109 // conversions are not going to kill virtual tables
30abd221 110 const String pfx = protoPrefix;
06a5ae20 111 clean();
112 init();
113 protoPrefix = pfx;
114}
115
116void
117HttpReply::clean()
118{
26ac0430 119 // we used to assert that the pipe is NULL, but now the message only
5f8252d2 120 // points to a pipe that is owned and initiated by another object.
121 body_pipe = NULL;
122
06a5ae20 123 httpBodyClean(&body);
124 hdrCacheClean();
519e0948 125 header.clean();
06a5ae20 126 httpStatusLineClean(&sline);
0667cbfb 127 bodySizeMax = -2; // hack: make calculatedBodySizeMax() false
cb69b4c7 128}
129
cb69b4c7 130void
06a5ae20 131HttpReply::packHeadersInto(Packer * p) const
cb69b4c7 132{
06a5ae20 133 httpStatusLinePackInto(&sline, p);
a9925b40 134 header.packInto(p);
cb69b4c7 135 packerAppend(p, "\r\n", 2);
528b2c61 136}
137
138void
06a5ae20 139HttpReply::packInto(Packer * p)
528b2c61 140{
06a5ae20 141 packHeadersInto(p);
142 httpBodyPackInto(&body, p);
cb69b4c7 143}
144
06a5ae20 145/* create memBuf, create mem-based packer, pack, destroy packer, return MemBuf */
032785bf 146MemBuf *
06a5ae20 147HttpReply::pack()
cb69b4c7 148{
032785bf 149 MemBuf *mb = new MemBuf;
cb69b4c7 150 Packer p;
cb69b4c7 151
2fe7eff9 152 mb->init();
032785bf 153 packerToMemInit(&p, mb);
06a5ae20 154 packInto(&p);
cb69b4c7 155 packerClean(&p);
156 return mb;
157}
158
032785bf 159MemBuf *
450e0c10 160httpPackedReply(HttpVersion ver, http_status status, const char *ctype,
47f6e231 161 int64_t clen, time_t lmt, time_t expires)
cb69b4c7 162{
06a5ae20 163 HttpReply *rep = new HttpReply;
164 rep->setHeaders(ver, status, ctype, NULL, clen, lmt, expires);
165 MemBuf *mb = rep->pack();
166 delete rep;
cb69b4c7 167 return mb;
168}
169
528b2c61 170HttpReply *
06a5ae20 171HttpReply::make304 () const
cb69b4c7 172{
62e76326 173 static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER};
174
06a5ae20 175 HttpReply *rv = new HttpReply;
728da2ee 176 int t;
de336bbe 177 HttpHeaderEntry *e;
cb69b4c7 178
528b2c61 179 /* rv->content_length; */
06a5ae20 180 rv->date = date;
181 rv->last_modified = last_modified;
182 rv->expires = expires;
183 rv->content_type = content_type;
528b2c61 184 /* rv->cache_control */
185 /* rv->content_range */
186 /* rv->keep_alive */
450e0c10 187 HttpVersion ver(1,0);
528b2c61 188 httpStatusLineSet(&rv->sline, ver,
62e76326 189 HTTP_NOT_MODIFIED, "");
190
de336bbe 191 for (t = 0; ImsEntries[t] != HDR_OTHER; ++t)
a9925b40 192 if ((e = header.findEntry(ImsEntries[t])))
eede25e7 193 rv->header.addEntry(e->clone());
62e76326 194
528b2c61 195 /* rv->body */
196 return rv;
197}
198
032785bf 199MemBuf *
06a5ae20 200HttpReply::packed304Reply()
528b2c61 201{
202 /* Not as efficient as skipping the header duplication,
203 * but easier to maintain
204 */
06a5ae20 205 HttpReply *temp = make304 ();
206 MemBuf *rv = temp->pack();
207 delete temp;
528b2c61 208 return rv;
cb69b4c7 209}
210
211void
06a5ae20 212HttpReply::setHeaders(HttpVersion ver, http_status status, const char *reason,
47f6e231 213 const char *ctype, int64_t clen, time_t lmt, time_t expires)
cb69b4c7 214{
215 HttpHeader *hdr;
06a5ae20 216 httpStatusLineSet(&sline, ver, status, reason);
217 hdr = &header;
a9925b40 218 hdr->putStr(HDR_SERVER, visible_appname_string);
219 hdr->putStr(HDR_MIME_VERSION, "1.0");
220 hdr->putTime(HDR_DATE, squid_curtime);
62e76326 221
d8b249ef 222 if (ctype) {
a9925b40 223 hdr->putStr(HDR_CONTENT_TYPE, ctype);
06a5ae20 224 content_type = ctype;
d8b249ef 225 } else
30abd221 226 content_type = String();
62e76326 227
de336bbe 228 if (clen >= 0)
47f6e231 229 hdr->putInt64(HDR_CONTENT_LENGTH, clen);
62e76326 230
cb69b4c7 231 if (expires >= 0)
a9925b40 232 hdr->putTime(HDR_EXPIRES, expires);
62e76326 233
2ac76861 234 if (lmt > 0) /* this used to be lmt != 0 @?@ */
a9925b40 235 hdr->putTime(HDR_LAST_MODIFIED, lmt);
62e76326 236
06a5ae20 237 date = squid_curtime;
62e76326 238
06a5ae20 239 content_length = clen;
62e76326 240
06a5ae20 241 expires = expires;
62e76326 242
06a5ae20 243 last_modified = lmt;
cb69b4c7 244}
245
6d38ef86 246void
06a5ae20 247HttpReply::redirect(http_status status, const char *loc)
6d38ef86 248{
249 HttpHeader *hdr;
450e0c10 250 HttpVersion ver(1,0);
06a5ae20 251 httpStatusLineSet(&sline, ver, status, httpStatusString(status));
252 hdr = &header;
7dbca7a4 253 hdr->putStr(HDR_SERVER, APP_FULLNAME);
a9925b40 254 hdr->putTime(HDR_DATE, squid_curtime);
47f6e231 255 hdr->putInt64(HDR_CONTENT_LENGTH, 0);
a9925b40 256 hdr->putStr(HDR_LOCATION, loc);
06a5ae20 257 date = squid_curtime;
258 content_length = 0;
6d38ef86 259}
260
528b2c61 261/* compare the validators of two replies.
262 * 1 = they match
263 * 0 = they do not match
264 */
265int
06a5ae20 266HttpReply::validatorsMatch(HttpReply const * otherRep) const
62e76326 267{
30abd221 268 String one,two;
06a5ae20 269 assert (otherRep);
528b2c61 270 /* Numbers first - easiest to check */
271 /* Content-Length */
272 /* TODO: remove -1 bypass */
62e76326 273
06a5ae20 274 if (content_length != otherRep->content_length
275 && content_length > -1 &&
62e76326 276 otherRep->content_length > -1)
277 return 0;
278
528b2c61 279 /* ETag */
a9925b40 280 one = header.getStrOrList(HDR_ETAG);
62e76326 281
a9925b40 282 two = otherRep->header.getStrOrList(HDR_ETAG);
62e76326 283
9d7a89a5 284 if (one.undefined() || two.undefined() || one.caseCmp(two)!=0 ) {
30abd221 285 one.clean();
286 two.clean();
62e76326 287 return 0;
528b2c61 288 }
62e76326 289
06a5ae20 290 if (last_modified != otherRep->last_modified)
62e76326 291 return 0;
292
528b2c61 293 /* MD5 */
a9925b40 294 one = header.getStrOrList(HDR_CONTENT_MD5);
62e76326 295
a9925b40 296 two = otherRep->header.getStrOrList(HDR_CONTENT_MD5);
62e76326 297
9d7a89a5 298 if (one.undefined() || two.undefined() || one.caseCmp(two) != 0 ) {
30abd221 299 one.clean();
300 two.clean();
62e76326 301 return 0;
528b2c61 302 }
62e76326 303
528b2c61 304 return 1;
305}
306
cb69b4c7 307void
06a5ae20 308HttpReply::updateOnNotModified(HttpReply const * freshRep)
cb69b4c7 309{
07947ad8 310 assert(freshRep);
1d7ab0f4 311
d8b249ef 312 /* clean cache */
06a5ae20 313 hdrCacheClean();
d8b249ef 314 /* update raw headers */
a9925b40 315 header.update(&freshRep->header,
316 (const HttpHeaderMask *) &Denied304HeadersMask);
1d7ab0f4 317
394499bd 318 header.compact();
d8b249ef 319 /* init cache */
07947ad8 320 hdrCacheInit();
cb69b4c7 321}
322
d8b249ef 323/* internal routines */
cb69b4c7 324
06a5ae20 325time_t
326HttpReply::hdrExpirationTime()
d20b1cd0 327{
328 /* The s-maxage and max-age directive takes priority over Expires */
62e76326 329
06a5ae20 330 if (cache_control) {
331 if (date >= 0) {
332 if (cache_control->s_maxage >= 0)
333 return date + cache_control->s_maxage;
62e76326 334
06a5ae20 335 if (cache_control->max_age >= 0)
336 return date + cache_control->max_age;
62e76326 337 } else {
338 /*
339 * Conservatively handle the case when we have a max-age
340 * header, but no Date for reference?
341 */
342
06a5ae20 343 if (cache_control->s_maxage >= 0)
62e76326 344 return squid_curtime;
345
06a5ae20 346 if (cache_control->max_age >= 0)
62e76326 347 return squid_curtime;
348 }
d20b1cd0 349 }
62e76326 350
f66a9ef4 351 if (Config.onoff.vary_ignore_expire &&
a9925b40 352 header.has(HDR_VARY)) {
353 const time_t d = header.getTime(HDR_DATE);
354 const time_t e = header.getTime(HDR_EXPIRES);
62e76326 355
356 if (d == e)
357 return -1;
f66a9ef4 358 }
62e76326 359
a9925b40 360 if (header.has(HDR_EXPIRES)) {
361 const time_t e = header.getTime(HDR_EXPIRES);
62e76326 362 /*
363 * HTTP/1.0 says that robust implementations should consider
364 * bad or malformed Expires header as equivalent to "expires
365 * immediately."
366 */
367 return e < 0 ? squid_curtime : e;
d20b1cd0 368 }
62e76326 369
d20b1cd0 370 return -1;
371}
372
d8b249ef 373/* sync this routine when you update HttpReply struct */
8596962e 374void
07947ad8 375HttpReply::hdrCacheInit()
cb69b4c7 376{
07947ad8 377 HttpMsg::hdrCacheInit();
378
47f6e231 379 content_length = header.getInt64(HDR_CONTENT_LENGTH);
a9925b40 380 date = header.getTime(HDR_DATE);
381 last_modified = header.getTime(HDR_LAST_MODIFIED);
382 surrogate_control = header.getSc();
383 content_range = header.getContRange();
07947ad8 384 keep_alive = httpMsgIsPersistent(sline.version, &header);
a9925b40 385 const char *str = header.getStr(HDR_CONTENT_TYPE);
62e76326 386
d8b249ef 387 if (str)
07947ad8 388 content_type.limitInit(str, strcspn(str, ";\t "));
d8b249ef 389 else
30abd221 390 content_type = String();
62e76326 391
d20b1cd0 392 /* be sure to set expires after date and cache-control */
06a5ae20 393 expires = hdrExpirationTime();
cb69b4c7 394}
395
d8b249ef 396/* sync this routine when you update HttpReply struct */
06a5ae20 397void
398HttpReply::hdrCacheClean()
2ac76861 399{
30abd221 400 content_type.clean();
62e76326 401
06a5ae20 402 if (cache_control) {
403 httpHdrCcDestroy(cache_control);
404 cache_control = NULL;
07947ad8 405 }
62e76326 406
06a5ae20 407 if (surrogate_control) {
408 httpHdrScDestroy(surrogate_control);
409 surrogate_control = NULL;
07947ad8 410 }
43ae1d95 411
06a5ae20 412 if (content_range) {
413 httpHdrContRangeDestroy(content_range);
414 content_range = NULL;
07947ad8 415 }
63259c34 416}
cb69b4c7 417
35282fbf 418/*
419 * Returns the body size of a HTTP response
420 */
47f6e231 421int64_t
60745f24 422HttpReply::bodySize(const HttpRequestMethod& method) const
35282fbf 423{
06a5ae20 424 if (sline.version.major < 1)
1bda350e 425 return -1;
914b89a2 426 else if (method.id() == METHOD_HEAD)
62e76326 427 return 0;
06a5ae20 428 else if (sline.status == HTTP_OK)
62e76326 429 (void) 0; /* common case, continue */
06a5ae20 430 else if (sline.status == HTTP_NO_CONTENT)
62e76326 431 return 0;
06a5ae20 432 else if (sline.status == HTTP_NOT_MODIFIED)
62e76326 433 return 0;
06a5ae20 434 else if (sline.status < HTTP_OK)
62e76326 435 return 0;
436
06a5ae20 437 return content_length;
35282fbf 438}
8596962e 439
96ee497f
AJ
440/**
441 * Checks the first line of an HTTP Reply is valid.
442 * currently only checks "HTTP/" exists.
443 *
444 * NP: not all error cases are detected yet. Some are left for detection later in parse.
445 */
446bool
447HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error)
8596962e 448{
96ee497f
AJ
449 // hack warning: using psize instead of size here due to type mismatches with MemBuf.
450
451 // content is long enough to possibly hold a reply
452 // 4 being magic size of a 3-digit number plus space delimiter
453 if ( buf->contentSize() < (protoPrefix.psize() + 4) ) {
0246f6b8
AJ
454 if (hdr_len > 0) {
455 debugs(58, 3, HERE << "Too small reply header (" << hdr_len << " bytes)");
96ee497f 456 *error = HTTP_INVALID_HEADER;
0246f6b8 457 }
96ee497f
AJ
458 return false;
459 }
460
e77d7ef0 461 int pos;
96ee497f 462 // catch missing or mismatched protocol identifier
e77d7ef0
AJ
463 // allow special-case for ICY protocol (non-HTTP identifier) in response to faked HTTP request.
464 if (strncmp(buf->content(), "ICY", 3) == 0) {
465 protoPrefix = "ICY";
466 pos = protoPrefix.psize();
dd20bfd3 467 } else {
8596962e 468
e77d7ef0
AJ
469 if (protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
470 debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol prefix (" << protoPrefix << ") in '" << buf->content() << "'");
471 *error = HTTP_INVALID_HEADER;
472 return false;
473 }
96ee497f 474
e77d7ef0
AJ
475 // catch missing or negative status value (negative '-' is not a digit)
476 pos = protoPrefix.psize();
dd20bfd3 477
e77d7ef0
AJ
478 // skip arbitrary number of digits and a dot in the verion portion
479 while ( pos <= buf->contentSize() && (*(buf->content()+pos) == '.' || xisdigit(*(buf->content()+pos)) ) ) ++pos;
96ee497f 480
e77d7ef0
AJ
481 // catch missing version info
482 if (pos == protoPrefix.psize()) {
483 debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf->content() << "'");
484 *error = HTTP_INVALID_HEADER;
485 return false;
486 }
96ee497f
AJ
487 }
488
489 // skip arbitrary number of spaces...
490 while (pos <= buf->contentSize() && (char)*(buf->content()+pos) == ' ') ++pos;
491
6934ca51 492 if (pos < buf->contentSize() && !xisdigit(*(buf->content()+pos))) {
96ee497f
AJ
493 debugs(58, 3, "HttpReply::sanityCheckStartLine: missing or invalid status number in '" << buf->content() << "'");
494 *error = HTTP_INVALID_HEADER;
495 return false;
496 }
497
8596962e 498 return true;
499}
500
501void HttpReply::packFirstLineInto(Packer *p, bool unused) const
502{
503 httpStatusLinePackInto(&sline, p);
504}
429f7150 505
506bool HttpReply::parseFirstLine(const char *blk_start, const char *blk_end)
507{
508 return httpStatusLineParse(&sline, protoPrefix, blk_start, blk_end);
509}
5c09dcb8 510
fb525683 511/* handy: resets and returns -1 */
512int
513HttpReply::httpMsgParseError()
514{
515 int result(HttpMsg::httpMsgParseError());
516 /* indicate an error in the status line */
517 sline.status = HTTP_INVALID_HEADER;
518 return result;
519}
520
5c09dcb8 521/*
522 * Indicate whether or not we would usually expect an entity-body
523 * along with this response
524 */
525bool
60745f24 526HttpReply::expectingBody(const HttpRequestMethod& req_method, int64_t& theSize) const
5c09dcb8 527{
528 bool expectBody = true;
529
530 if (req_method == METHOD_HEAD)
531 expectBody = false;
532 else if (sline.status == HTTP_NO_CONTENT)
533 expectBody = false;
534 else if (sline.status == HTTP_NOT_MODIFIED)
535 expectBody = false;
536 else if (sline.status < HTTP_OK)
537 expectBody = false;
538 else
539 expectBody = true;
540
541 if (expectBody) {
a9925b40 542 if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
5c09dcb8 543 theSize = -1;
544 else if (content_length >= 0)
545 theSize = content_length;
546 else
547 theSize = -1;
548 }
549
550 return expectBody;
551}
0667cbfb 552
553bool
554HttpReply::receivedBodyTooLarge(HttpRequest& request, int64_t receivedSize)
555{
556 calcMaxBodySize(request);
557 debugs(58, 3, HERE << receivedSize << " >? " << bodySizeMax);
558 return bodySizeMax >= 0 && receivedSize > bodySizeMax;
559}
560
561bool
562HttpReply::expectedBodyTooLarge(HttpRequest& request)
563{
564 calcMaxBodySize(request);
565 debugs(58, 7, HERE << "bodySizeMax=" << bodySizeMax);
566
567 if (bodySizeMax < 0) // no body size limit
568 return false;
569
570 int64_t expectedSize = -1;
571 if (!expectingBody(request.method, expectedSize))
572 return false;
26ac0430 573
0667cbfb 574 debugs(58, 6, HERE << expectedSize << " >? " << bodySizeMax);
575
576 if (expectedSize < 0) // expecting body of an unknown length
577 return false;
578
579 return expectedSize > bodySizeMax;
580}
581
582void
583HttpReply::calcMaxBodySize(HttpRequest& request)
584{
585 // hack: -2 is used as "we have not calculated max body size yet" state
586 if (bodySizeMax != -2) // already tried
587 return;
588 bodySizeMax = -1;
589
c0941a6a 590 ACLFilledChecklist ch(NULL, &request, NULL);
0667cbfb 591 ch.src_addr = request.client_addr;
592 ch.my_addr = request.my_addr;
593 ch.reply = HTTPMSGLOCK(this); // XXX: this lock makes method non-const
0667cbfb 594 for (acl_size_t *l = Config.ReplyBodySize; l; l = l -> next) {
b50e327b
AJ
595 /* if there is no ACL list or if the ACLs listed match use this size value */
596 if (!l->aclList || ch.matchAclListFast(l->aclList)) {
0667cbfb 597 debugs(58, 4, HERE << "bodySizeMax=" << bodySizeMax);
598 bodySizeMax = l->size; // may be -1
599 break;
600 }
601 }
602}
da33c835 603
fa0e6114 604// XXX: check that this is sufficient for eCAP cloning
da33c835
HN
605HttpReply *
606HttpReply::clone() const
607{
608 HttpReply *rep = new HttpReply();
609 rep->header.append(&header);
610 rep->hdrCacheInit();
611 rep->hdr_sz = hdr_sz;
f230832f
HN
612 rep->http_ver = http_ver;
613 rep->pstate = pstate;
fa0e6114
AR
614 rep->body_pipe = body_pipe;
615
f230832f
HN
616 rep->protocol = protocol;
617 rep->sline = sline;
d67acb4e 618 rep->keep_alive = keep_alive;
da33c835
HN
619 return rep;
620}
d67acb4e
AJ
621
622
623bool HttpReply::inheritProperties(const HttpMsg *aMsg)
624{
625 const HttpReply *aRep = dynamic_cast<const HttpReply*>(aMsg);
26ac0430
AJ
626 if (!aRep)
627 return false;
d67acb4e
AJ
628 keep_alive = aRep->keep_alive;
629 return true;
630}