http.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 11 Hypertext Transfer Protocol (HTTP) */
10 
11 /*
12  * Anonymizing patch by lutz@as-node.jena.thur.de
13  * have a look into http-anon.c to get more informations.
14  */
15 
16 #include "squid.h"
17 #include "acl/FilledChecklist.h"
18 #include "base/AsyncJobCalls.h"
19 #include "base/TextException.h"
20 #include "base64.h"
21 #include "CachePeer.h"
22 #include "client_side.h"
23 #include "comm/Connection.h"
24 #include "comm/Read.h"
25 #include "comm/Write.h"
26 #include "CommRead.h"
27 #include "err_detail_type.h"
28 #include "errorpage.h"
29 #include "fd.h"
30 #include "fde.h"
31 #include "globals.h"
32 #include "http.h"
35 #include "http/Stream.h"
36 #include "HttpControlMsg.h"
37 #include "HttpHdrCc.h"
38 #include "HttpHdrContRange.h"
39 #include "HttpHdrSc.h"
40 #include "HttpHdrScTarget.h"
41 #include "HttpHeaderTools.h"
42 #include "HttpReply.h"
43 #include "HttpRequest.h"
44 #include "log/access_log.h"
45 #include "MemBuf.h"
46 #include "MemObject.h"
47 #include "neighbors.h"
49 #include "profiler/Profiler.h"
50 #include "refresh.h"
51 #include "RefreshPattern.h"
52 #include "rfc1738.h"
53 #include "SquidConfig.h"
54 #include "SquidTime.h"
55 #include "StatCounters.h"
56 #include "Store.h"
57 #include "StrList.h"
58 #include "tools.h"
59 #include "util.h"
60 
61 #if USE_AUTH
62 #include "auth/UserRequest.h"
63 #endif
64 #if USE_DELAY_POOLS
65 #include "DelayPools.h"
66 #endif
67 
68 #define SQUID_ENTER_THROWING_CODE() try {
69 #define SQUID_EXIT_THROWING_CODE(status) \
70  status = true; \
71  } \
72  catch (const std::exception &e) { \
73  debugs (11, 1, "Exception error:" << e.what()); \
74  status = false; \
75  }
76 
78 
79 static const char *const crlf = "\r\n";
80 
82 static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request,
83  HttpHeader * hdr_out, const int we_do_ranges, const Http::StateFlags &);
84 
86  AsyncJob("HttpStateData"),
87  Client(theFwdState),
88  lastChunk(0),
89  httpChunkDecoder(NULL),
90  payloadSeen(0),
91  payloadTruncated(0),
92  sawDateGoBack(false)
93 {
94  debugs(11,5,HERE << "HttpStateData " << this << " created");
95  ignoreCacheControl = false;
96  surrogateNoStore = false;
98 
99  if (fwd->serverConnection() != NULL)
100  _peer = cbdataReference(fwd->serverConnection()->getPeer()); /* might be NULL */
101 
102  if (_peer) {
103  request->flags.proxying = true;
104  /*
105  * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
106  * We might end up getting the object from somewhere else if,
107  * for example, the request to this neighbor fails.
108  */
109  if (_peer->options.proxy_only)
110  entry->releaseRequest(true);
111 
112 #if USE_DELAY_POOLS
114 #endif
115  }
116 
117  /*
118  * register the handler to free HTTP state data when the FD closes
119  */
123 }
124 
126 {
127  /*
128  * don't forget that ~Client() gets called automatically
129  */
130 
131  if (httpChunkDecoder)
132  delete httpChunkDecoder;
133 
135 
136  debugs(11,5, HERE << "HttpStateData " << this << " destroyed; " << serverConnection);
137 }
138 
141 {
142  return serverConnection;
143 }
144 
145 void
147 {
148  debugs(11, 5, "httpStateFree: FD " << params.fd << ", httpState=" << params.data);
149  doneWithFwd = "httpStateConnClosed()"; // assume FwdState is monitoring too
150  mustStop("HttpStateData::httpStateConnClosed");
151 }
152 
153 void
155 {
156  debugs(11, 4, serverConnection << ": '" << entry->url() << "'");
157 
158  if (entry->store_status == STORE_PENDING) {
160  }
161 
162  closeServer();
163  mustStop("HttpStateData::httpTimeout");
164 }
165 
166 static StoreEntry *
168  assert(newEntry->mem_obj);
169  return newEntry->mem_obj->request ?
171  storeGetPublic(newEntry->mem_obj->storeId(), newEntry->mem_obj->method);
172 }
173 
176 static void
178 {
179  int remove = 0;
180  int forbidden = 0;
181 
182  // If the incoming response already goes into a public entry, then there is
183  // nothing to remove. This protects ready-for-collapsing entries as well.
184  if (!EBIT_TEST(e->flags, KEY_PRIVATE))
185  return;
186 
187  // If the new/incoming response cannot be stored, then it does not
188  // compete with the old stored response for the public key, and the
189  // old stored response should be left as is.
190  if (e->mem_obj->request && !e->mem_obj->request->flags.cachable)
191  return;
192 
193  switch (status) {
194 
195  case Http::scOkay:
196 
198 
200 
202 
203  case Http::scFound:
204 
205  case Http::scSeeOther:
206 
207  case Http::scGone:
208 
209  case Http::scNotFound:
210  remove = 1;
211 
212  break;
213 
214  case Http::scForbidden:
215 
217  forbidden = 1;
218 
219  break;
220 
221 #if WORK_IN_PROGRESS
222 
224  forbidden = 1;
225 
226  break;
227 
228 #endif
229 
230  default:
231 #if QUESTIONABLE
232  /*
233  * Any 2xx response should eject previously cached entities...
234  */
235 
236  if (status >= 200 && status < 300)
237  remove = 1;
238 
239 #endif
240 
241  break;
242  }
243 
244  if (!remove && !forbidden)
245  return;
246 
248 
249  if (pe != NULL) {
250  assert(e != pe);
251 #if USE_HTCP
253 #endif
254  pe->release(true);
255  }
256 
261  if (e->mem_obj->request)
263  else
265 
266  if (pe != NULL) {
267  assert(e != pe);
268 #if USE_HTCP
270 #endif
271  pe->release(true);
272  }
273 }
274 
275 void
277 {
278  if (request->flags.accelerated && reply->surrogate_control) {
280 
281  if (sctusable) {
282  if (sctusable->hasNoStore() ||
284  && sctusable->noStoreRemote())) {
285  surrogateNoStore = true;
286  // Be conservative for now and make it non-shareable because
287  // there is no enough information here to make the decision.
288  entry->makePrivate(false);
289  }
290 
291  /* The HttpHeader logic cannot tell if the header it's parsing is a reply to an
292  * accelerated request or not...
293  * Still, this is an abstraction breach. - RC
294  */
295  if (sctusable->hasMaxAge()) {
296  if (sctusable->maxAge() < sctusable->maxStale())
297  reply->expires = reply->date + sctusable->maxAge();
298  else
299  reply->expires = reply->date + sctusable->maxStale();
300 
301  /* And update the timestamps */
302  entry->timestampsSet();
303  }
304 
305  /* We ignore cache-control directives as per the Surrogate specification */
306  ignoreCacheControl = true;
307 
308  delete sctusable;
309  }
310  }
311 }
312 
315 {
316  HttpReply const *rep = finalReply();
317  HttpHeader const *hdr = &rep->header;
318  const char *v;
319 #if USE_HTTP_VIOLATIONS
320 
321  const RefreshPattern *R = NULL;
322 
323  /* This strange looking define first looks up the refresh pattern
324  * and then checks if the specified flag is set. The main purpose
325  * of this is to simplify the refresh pattern lookup and USE_HTTP_VIOLATIONS
326  * condition
327  */
328 #define REFRESH_OVERRIDE(flag) \
329  ((R = (R ? R : refreshLimits(entry->mem_obj->storeId()))) , \
330  (R && R->flags.flag))
331 #else
332 #define REFRESH_OVERRIDE(flag) 0
333 #endif
334 
336  return decision.make(ReuseDecision::doNotCacheButShare, "the entry has been released");
337 
338  // RFC 7234 section 4: a cache MUST use the most recent response
339  // (as determined by the Date header field)
340  // TODO: whether such responses could be shareable?
341  if (sawDateGoBack)
342  return decision.make(ReuseDecision::reuseNot, "the response has an older date header");
343 
344  // Check for Surrogate/1.0 protocol conditions
345  // NP: reverse-proxy traffic our parent server has instructed us never to cache
346  if (surrogateNoStore)
347  return decision.make(ReuseDecision::reuseNot, "Surrogate-Control:no-store");
348 
349  // RFC 2616: HTTP/1.1 Cache-Control conditions
350  if (!ignoreCacheControl) {
351  // XXX: check to see if the request headers alone were enough to prevent caching earlier
352  // (ie no-store request header) no need to check those all again here if so.
353  // for now we are not reliably doing that so we waste CPU re-checking request CC
354 
355  // RFC 2616 section 14.9.2 - MUST NOT cache any response with request CC:no-store
357  !REFRESH_OVERRIDE(ignore_no_store))
358  return decision.make(ReuseDecision::reuseNot,
359  "client request Cache-Control:no-store");
360 
361  // NP: request CC:no-cache only means cache READ is forbidden. STORE is permitted.
363  /* TODO: we are allowed to cache when no-cache= has parameters.
364  * Provided we strip away any of the listed headers unless they are revalidated
365  * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
366  * That is a bit tricky for squid right now so we avoid caching entirely.
367  */
368  return decision.make(ReuseDecision::reuseNot,
369  "server reply Cache-Control:no-cache has parameters");
370  }
371 
372  // NP: request CC:private is undefined. We ignore.
373  // NP: other request CC flags are limiters on HIT/MISS. We don't care about here.
374 
375  // RFC 2616 section 14.9.2 - MUST NOT cache any response with CC:no-store
376  if (rep->cache_control && rep->cache_control->hasNoStore() &&
377  !REFRESH_OVERRIDE(ignore_no_store))
378  return decision.make(ReuseDecision::reuseNot,
379  "server reply Cache-Control:no-store");
380 
381  // RFC 2616 section 14.9.1 - MUST NOT cache any response with CC:private in a shared cache like Squid.
382  // CC:private overrides CC:public when both are present in a response.
383  // TODO: add a shared/private cache configuration possibility.
384  if (rep->cache_control &&
385  rep->cache_control->hasPrivate() &&
386  !REFRESH_OVERRIDE(ignore_private)) {
387  /* TODO: we are allowed to cache when private= has parameters.
388  * Provided we strip away any of the listed headers unless they are revalidated
389  * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
390  * That is a bit tricky for squid right now so we avoid caching entirely.
391  */
392  return decision.make(ReuseDecision::reuseNot,
393  "server reply Cache-Control:private");
394  }
395  }
396 
397  // RFC 2068, sec 14.9.4 - MUST NOT cache any response with Authentication UNLESS certain CC controls are present
398  // allow HTTP violations to IGNORE those controls (ie re-block caching Auth)
399  if (request && (request->flags.auth || request->flags.authSent)) {
400  if (!rep->cache_control)
401  return decision.make(ReuseDecision::reuseNot,
402  "authenticated and server reply missing Cache-Control");
403 
404  if (ignoreCacheControl)
405  return decision.make(ReuseDecision::reuseNot,
406  "authenticated and ignoring Cache-Control");
407 
408  bool mayStore = false;
409  // HTTPbis pt6 section 3.2: a response CC:public is present
410  if (rep->cache_control->hasPublic()) {
411  debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:public");
412  mayStore = true;
413 
414  // HTTPbis pt6 section 3.2: a response CC:must-revalidate is present
415  } else if (rep->cache_control->hasMustRevalidate()) {
416  debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:must-revalidate");
417  mayStore = true;
418 
419 #if USE_HTTP_VIOLATIONS
420  // NP: given the must-revalidate exception we should also be able to exempt no-cache.
421  // HTTPbis WG verdict on this is that it is omitted from the spec due to being 'unexpected' by
422  // some. The caching+revalidate is not exactly unsafe though with Squids interpretation of no-cache
423  // (without parameters) as equivalent to must-revalidate in the reply.
424  } else if (rep->cache_control->hasNoCacheWithoutParameters()) {
425  debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:no-cache (equivalent to must-revalidate)");
426  mayStore = true;
427 #endif
428 
429  // HTTPbis pt6 section 3.2: a response CC:s-maxage is present
430  } else if (rep->cache_control->hasSMaxAge()) {
431  debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:s-maxage");
432  mayStore = true;
433  }
434 
435  if (!mayStore)
436  return decision.make(ReuseDecision::reuseNot, "authenticated transaction");
437 
438  // NP: response CC:no-cache is equivalent to CC:must-revalidate,max-age=0. We MAY cache, and do so.
439  // NP: other request CC flags are limiters on HIT/MISS/REFRESH. We don't care about here.
440  }
441 
442  /* HACK: The "multipart/x-mixed-replace" content type is used for
443  * continuous push replies. These are generally dynamic and
444  * probably should not be cachable
445  */
446  if ((v = hdr->getStr(Http::HdrType::CONTENT_TYPE)))
447  if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
448  return decision.make(ReuseDecision::reuseNot, "Content-Type:multipart/x-mixed-replace");
449 
450  // TODO: if possible, provide more specific message for each status code
451  static const char *shareableError = "shareable error status code";
452  static const char *nonShareableError = "non-shareable error status code";
454  const char *statusReason = nonShareableError;
455 
456  switch (rep->sline.status()) {
457 
458  /* There are several situations when a non-cacheable response may be
459  * still shareable (e.g., among collapsed clients). We assume that these
460  * are 3xx and 5xx responses, indicating server problems and some of
461  * 4xx responses, common for all clients with a given cache key (e.g.,
462  * 404 Not Found or 414 URI Too Long). On the other hand, we should not
463  * share non-cacheable client-specific errors, such as 400 Bad Request
464  * or 406 Not Acceptable.
465  */
466 
467  /* Responses that are cacheable */
468 
469  case Http::scOkay:
470 
472 
474 
477 
478  case Http::scGone:
479  /*
480  * Don't cache objects that need to be refreshed on next request,
481  * unless we know how to refresh it.
482  */
483 
484  if (refreshIsCachable(entry) || REFRESH_OVERRIDE(store_stale))
485  decision.make(ReuseDecision::cachePositively, "refresh check returned cacheable");
486  else
487  decision.make(ReuseDecision::doNotCacheButShare, "refresh check returned non-cacheable");
488  break;
489 
490  /* Responses that only are cacheable if the server says so */
491 
492  case Http::scFound:
494  if (rep->date <= 0)
495  decision.make(ReuseDecision::doNotCacheButShare, "Date is missing/invalid");
496  else if (rep->expires > rep->date)
497  decision.make(ReuseDecision::cachePositively, "Expires > Date");
498  else
499  decision.make(ReuseDecision::doNotCacheButShare, "Expires <= Date");
500  break;
501 
502  /* These responses can be negatively cached. Most can also be shared. */
503  case Http::scNoContent:
504  case Http::scUseProxy:
505  case Http::scForbidden:
506  case Http::scNotFound:
508  case Http::scUriTooLong:
511  case Http::scBadGateway:
515  statusAnswer = ReuseDecision::doNotCacheButShare;
516  statusReason = shareableError;
517  // fall through to the actual decision making below
518 
519  case Http::scBadRequest: // no sharing; perhaps the server did not like something specific to this request
520 #if USE_HTTP_VIOLATIONS
521  if (Config.negativeTtl > 0)
522  decision.make(ReuseDecision::cacheNegatively, "Config.negativeTtl > 0");
523  else
524 #endif
525  decision.make(statusAnswer, statusReason);
526  break;
527 
528  /* these responses can never be cached, some
529  of them can be shared though */
530  case Http::scSeeOther:
531  case Http::scNotModified:
536  // TODO: use more specific reason for non-error status codes
537  decision.make(ReuseDecision::doNotCacheButShare, shareableError);
538  break;
539 
540  case Http::scPartialContent: /* Not yet supported. TODO: make shareable for suitable ranges */
542  case Http::scRequestTimeout: // TODO: is this shareable?
543  case Http::scConflict: // TODO: is this shareable?
549  case Http::scLocked: // TODO: is this shareable?
553  case Http::scInvalidHeader: /* Squid header parsing error */
555  decision.make(ReuseDecision::reuseNot, nonShareableError);
556  break;
557 
558  default:
559  /* RFC 2616 section 6.1.1: an unrecognized response MUST NOT be cached. */
560  decision.make(ReuseDecision::reuseNot, "unknown status code");
561  break;
562  }
563 
564  return decision.answer;
565 }
566 
568 static void
570 {
571  static const SBuf asterisk("*");
572  const char *pos = nullptr;
573  const char *item = nullptr;
574  int ilen = 0;
575 
576  while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
577  SBuf name(item, ilen);
578  if (name == asterisk) {
579  vstr = asterisk;
580  break;
581  }
582  name.toLower();
583  if (!vstr.isEmpty())
584  vstr.append(", ", 2);
585  vstr.append(name);
586  String hdr(request.header.getByName(name));
587  const char *value = hdr.termedBuf();
588  if (value) {
589  value = rfc1738_escape_part(value);
590  vstr.append("=\"", 2);
591  vstr.append(value);
592  vstr.append("\"", 1);
593  }
594 
595  hdr.clean();
596  }
597 }
598 
599 /*
600  * For Vary, store the relevant request headers as
601  * virtual headers in the reply
602  * Returns an empty SBuf if the variance cannot be stored
603  */
604 SBuf
606 {
607  SBuf vstr;
608  String vary;
609 
610  vary = reply->header.getList(Http::HdrType::VARY);
611  assembleVaryKey(vary, vstr, *request);
612 
613 #if X_ACCELERATOR_VARY
614  vary.clean();
616  assembleVaryKey(vary, vstr, *request);
617 #endif
618 
619  debugs(11, 3, vstr);
620  return vstr;
621 }
622 
623 void
625 {
626  if (flags.keepalive)
627  if (_peer)
629 
630  if (reply->keep_alive) {
631  if (_peer)
633 
635  && reply->bodySize(request->method) == -1 && !flags.chunked) {
636  debugs(11, DBG_IMPORTANT, "keepaliveAccounting: Impossible keep-alive header from '" << entry->url() << "'" );
637  // debugs(11, 2, "GOT HTTP REPLY HDR:\n---------\n" << readBuf->content() << "\n----------" );
638  flags.keepalive_broken = true;
639  }
640  }
641 }
642 
643 void
645 {
646  if (reply->date > -1 && !_peer) {
647  int skew = abs((int)(reply->date - squid_curtime));
648 
649  if (skew > 86400)
650  debugs(11, 3, "" << request->url.host() << "'s clock is skewed by " << skew << " seconds!");
651  }
652 }
653 
660 void
662 {
665  /* NP: all exit points to this function MUST call ctx_exit(ctx) */
666  Ctx ctx = ctx_enter(entry->mem_obj->urlXXX());
667 
668  debugs(11, 3, "processReplyHeader: key '" << entry->getMD5Text() << "'");
669 
671 
672  if (!inBuf.length()) {
673  ctx_exit(ctx);
674  return;
675  }
676 
677  /* Attempt to parse the first line; this will define where the protocol, status, reason-phrase and header begin */
678  {
679  if (hp == NULL)
681 
682  bool parsedOk = hp->parse(inBuf);
683 
684  // sync the buffers after parsing.
685  inBuf = hp->remaining();
686 
687  if (hp->needsMoreData()) {
688  if (eof) { // no more data coming
689  /* Bug 2879: Replies may terminate with \r\n then EOF instead of \r\n\r\n.
690  * We also may receive truncated responses.
691  * Ensure here that we have at minimum two \r\n when EOF is seen.
692  */
693  inBuf.append("\r\n\r\n", 4);
694  // retry the parse
695  parsedOk = hp->parse(inBuf);
696  // sync the buffers after parsing.
697  inBuf = hp->remaining();
698  } else {
699  debugs(33, 5, "Incomplete response, waiting for end of response headers");
700  ctx_exit(ctx);
701  return;
702  }
703  }
704 
705  if (!parsedOk) {
706  // unrecoverable parsing error
707  // TODO: Use Raw! XXX: inBuf no longer has the [beginning of the] malformed header.
708  debugs(11, 3, "Non-HTTP-compliant header:\n---------\n" << inBuf << "\n----------");
709  flags.headers_parsed = true;
710  HttpReply *newrep = new HttpReply;
711  newrep->sline.set(Http::ProtocolVersion(), hp->parseStatusCode);
712  setVirginReply(newrep);
713  ctx_exit(ctx);
714  return;
715  }
716  }
717 
718  /* We know the whole response is in parser now */
719  debugs(11, 2, "HTTP Server " << serverConnection);
720  debugs(11, 2, "HTTP Server RESPONSE:\n---------\n" <<
721  hp->messageProtocol() << " " << hp->messageStatus() << " " << hp->reasonPhrase() << "\n" <<
722  hp->mimeHeader() <<
723  "----------");
724 
725  // reset payload tracking to begin after message headers
727 
728  HttpReply *newrep = new HttpReply;
729  // XXX: RFC 7230 indicates we MAY ignore the reason phrase,
730  // and use an empty string on unknown status.
731  // We do that now to avoid performance regression from using SBuf::c_str()
732  newrep->sline.set(Http::ProtocolVersion(1,1), hp->messageStatus() /* , hp->reasonPhrase() */);
733  newrep->sline.protocol = newrep->sline.version.protocol = hp->messageProtocol().protocol;
734  newrep->sline.version.major = hp->messageProtocol().major;
735  newrep->sline.version.minor = hp->messageProtocol().minor;
736 
737  // parse headers
738  if (!newrep->parseHeader(*hp)) {
739  // XXX: when Http::ProtocolVersion is a function, remove this hack. just set with messageProtocol()
741  newrep->sline.version.protocol = hp->messageProtocol().protocol;
742  newrep->sline.version.major = hp->messageProtocol().major;
743  newrep->sline.version.minor = hp->messageProtocol().minor;
744  debugs(11, 2, "error parsing response headers mime block");
745  }
746 
747  // done with Parser, now process using the HttpReply
748  hp = NULL;
749 
751 
752  newrep->removeStaleWarnings();
753 
754  if (newrep->sline.protocol == AnyP::PROTO_HTTP && Http::Is1xx(newrep->sline.status())) {
755  handle1xx(newrep);
756  ctx_exit(ctx);
757  return;
758  }
759 
760  flags.chunked = false;
761  if (newrep->sline.protocol == AnyP::PROTO_HTTP && newrep->header.chunked()) {
762  flags.chunked = true;
764  }
765 
768 
769  HttpReply *vrep = setVirginReply(newrep);
770  flags.headers_parsed = true;
771 
772  keepaliveAccounting(vrep);
773 
774  checkDateSkew(vrep);
775 
777 
779 
780  ctx_exit(ctx);
781 }
782 
784 void
786 {
787  HttpReply::Pointer msg(reply); // will destroy reply if unused
788 
789  // one 1xx at a time: we must not be called while waiting for previous 1xx
791  flags.handling1xx = true;
792 
794  debugs(11, 2, "ignoring 1xx because it is " << (request->forcedBodyContinuation ? "already sent" : "not supported by client"));
795  proceedAfter1xx();
796  return;
797  }
798 
799 #if USE_HTTP_VIOLATIONS
800  // check whether the 1xx response forwarding is allowed by squid.conf
801  if (Config.accessList.reply) {
803  ch.al = fwd->al;
804  ch.reply = reply;
805  ch.syncAle(originalRequest().getRaw(), nullptr);
806  HTTPMSGLOCK(ch.reply);
807  if (!ch.fastCheck().allowed()) { // TODO: support slow lookups?
808  debugs(11, 3, HERE << "ignoring denied 1xx");
809  proceedAfter1xx();
810  return;
811  }
812  }
813 #endif // USE_HTTP_VIOLATIONS
814 
815  debugs(11, 2, HERE << "forwarding 1xx to client");
816 
817  // the Sink will use this to call us back after writing 1xx to the client
818  typedef NullaryMemFunT<HttpStateData> CbDialer;
819  const AsyncCall::Pointer cb = JobCallback(11, 3, CbDialer, this,
823  // If the call is not fired, then the Sink is gone, and HttpStateData
824  // will terminate due to an aborted store entry or another similar error.
825  // If we get stuck, it is not handle1xx fault if we could get stuck
826  // for similar reasons without a 1xx response.
827 }
828 
830 void
832 {
834  debugs(11, 2, "continuing with " << payloadSeen << " bytes in buffer after 1xx");
836 }
837 
841 bool
843 {
844  if (!_peer)
845  return true;
846 
847  /*If this peer does not support connection pinning (authenticated
848  connections) return false
849  */
850  if (!_peer->connection_auth)
851  return false;
852 
853  const HttpReplyPointer rep(entry->mem_obj->getReply());
854 
855  /*The peer supports connection pinning and the http reply status
856  is not unauthorized, so the related connection can be pinned
857  */
858  if (rep->sline.status() != Http::scUnauthorized)
859  return true;
860 
861  /*The server respond with Http::scUnauthorized and the peer configured
862  with "connection-auth=on" we know that the peer supports pinned
863  connections
864  */
865  if (_peer->connection_auth == 1)
866  return true;
867 
868  /*At this point peer has configured with "connection-auth=auto"
869  parameter so we need some extra checks to decide if we are going
870  to allow pinned connections or not
871  */
872 
873  /*if the peer configured with originserver just allow connection
874  pinning (squid 2.6 behaviour)
875  */
877  return true;
878 
879  /*if the connections it is already pinned it is OK*/
880  if (request->flags.pinned)
881  return true;
882 
883  /*Allow pinned connections only if the Proxy-support header exists in
884  reply and has in its list the "Session-Based-Authentication"
885  which means that the peer supports connection pinning.
886  */
887  if (rep->header.hasListMember(Http::HdrType::PROXY_SUPPORT, "Session-Based-Authentication", ','))
888  return true;
889 
890  return false;
891 }
892 
893 // Called when we parsed (and possibly adapted) the headers but
894 // had not starting storing (a.k.a., sending) the body yet.
895 void
897 {
899 
900  Ctx ctx = ctx_enter(entry->mem_obj->urlXXX());
901  HttpReply *rep = finalReply();
902  const Http::StatusCode statusCode = rep->sline.status();
903 
904  entry->timestampsSet();
905 
906  /* Check if object is cacheable or not based on reply code */
907  debugs(11, 3, "HTTP CODE: " << statusCode);
908 
909  if (StoreEntry *oldEntry = findPreviouslyCachedEntry(entry)) {
910  oldEntry->lock("HttpStateData::haveParsedReplyHeaders");
911  sawDateGoBack = rep->olderThan(oldEntry->getReply());
912  oldEntry->unlock("HttpStateData::haveParsedReplyHeaders");
913  }
914 
916  httpMaybeRemovePublic(entry, rep->sline.status());
917 
918  bool varyFailure = false;
919  if (rep->header.has(Http::HdrType::VARY)
920 #if X_ACCELERATOR_VARY
921  || rep->header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY)
922 #endif
923  ) {
924  const SBuf vary(httpMakeVaryMark(request.getRaw(), rep));
925 
926  if (vary.isEmpty()) {
927  // TODO: check whether such responses are shareable.
928  // Do not share for now.
929  entry->makePrivate(false);
930  if (fwd->reforwardableStatus(rep->sline.status()))
932  varyFailure = true;
933  } else {
934  entry->mem_obj->vary_headers = vary;
935 
936  // RFC 7231 section 7.1.4
937  // Vary:* can be cached, but has mandatory revalidation
938  static const SBuf asterisk("*");
939  if (vary == asterisk)
941  }
942  }
943 
944  if (!varyFailure) {
945  /*
946  * If its not a reply that we will re-forward, then
947  * allow the client to get it.
948  */
949  if (fwd->reforwardableStatus(rep->sline.status()))
951 
952  ReuseDecision decision(entry, statusCode);
953 
954  switch (reusableReply(decision)) {
955 
957  entry->makePrivate(false);
958  break;
959 
961  if (!entry->makePublic()) {
962  decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
963  entry->makePrivate(true);
964  }
965  break;
966 
968  if (!entry->cacheNegatively()) {
969  decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
970  entry->makePrivate(true);
971  }
972  break;
973 
975  entry->makePrivate(true);
976  break;
977 
978  default:
979  assert(0);
980  break;
981  }
982  debugs(11, 3, "decided: " << decision);
983  }
984 
985  if (!ignoreCacheControl) {
986  if (rep->cache_control) {
987  // We are required to revalidate on many conditions.
988  // For security reasons we do so even if storage was caused by refresh_pattern ignore-* option
989 
990  // CC:must-revalidate or CC:proxy-revalidate
991  const bool ccMustRevalidate = (rep->cache_control->hasProxyRevalidate() || rep->cache_control->hasMustRevalidate());
992 
993  // CC:no-cache (only if there are no parameters)
994  const bool ccNoCacheNoParams = rep->cache_control->hasNoCacheWithoutParameters();
995 
996  // CC:s-maxage=N
997  const bool ccSMaxAge = rep->cache_control->hasSMaxAge();
998 
999  // CC:private (yes, these can sometimes be stored)
1000  const bool ccPrivate = rep->cache_control->hasPrivate();
1001 
1002  if (ccNoCacheNoParams || ccPrivate)
1004  else if (ccMustRevalidate || ccSMaxAge)
1006  }
1007 #if USE_HTTP_VIOLATIONS // response header Pragma::no-cache is undefined in HTTP
1008  else {
1009  // Expensive calculation. So only do it IF the CC: header is not present.
1010 
1011  /* HACK: Pragma: no-cache in _replies_ is not documented in HTTP,
1012  * but servers like "Active Imaging Webcast/2.0" sure do use it */
1013  if (rep->header.has(Http::HdrType::PRAGMA) &&
1014  rep->header.hasListMember(Http::HdrType::PRAGMA,"no-cache",','))
1016  }
1017 #endif
1018  }
1019 
1020 #if HEADERS_LOG
1021  headersLog(1, 0, request->method, rep);
1022 
1023 #endif
1024 
1025  ctx_exit(ctx);
1026 }
1027 
1030 {
1031  const HttpReply *rep = virginReply();
1035  static SBuf close("close", 5);
1036  if (httpHeaderHasConnDir(&rep->header, close))
1038 
1043  if (!flags.keepalive)
1045 
1050  if (!flags.request_sent) {
1051  debugs(11, 2, "Request not yet fully sent " << request->method << ' ' << entry->url());
1053  }
1054 
1067  if (!rep->keep_alive)
1069 
1070  return COMPLETE_PERSISTENT_MSG;
1071 }
1072 
1075 {
1076  debugs(11, 3, HERE << serverConnection << " eof=" << eof);
1077  if (eof) // already reached EOF
1079 
1080  /* If server fd is closing (but we have not been notified yet), stop Comm
1081  I/O to avoid assertions. TODO: Change Comm API to handle callers that
1082  want more I/O after async closing (usually initiated by others). */
1083  // XXX: add canReceive or s/canSend/canTalkToServer/
1086 
1092  if (lastChunk && flags.chunked)
1093  return statusIfComplete();
1094 
1095  const HttpReply *vrep = virginReply();
1096  debugs(11, 5, "persistentConnStatus: content_length=" << vrep->content_length);
1097 
1098  const int64_t clen = vrep->bodySize(request->method);
1099 
1100  debugs(11, 5, "persistentConnStatus: clen=" << clen);
1101 
1102  /* If the body size is unknown we must wait for EOF */
1103  if (clen < 0)
1104  return INCOMPLETE_MSG;
1105 
1108  if (clen > 0) {
1109  debugs(11,5, "payloadSeen=" << payloadSeen << " content_length=" << vrep->content_length);
1110 
1111  if (payloadSeen < vrep->content_length)
1112  return INCOMPLETE_MSG;
1113 
1114  if (payloadTruncated > 0) // already read more than needed
1115  return COMPLETE_NONPERSISTENT_MSG; // disable pconns
1116  }
1117 
1120  return statusIfComplete();
1121 }
1122 
1123 static void
1124 readDelayed(void *context, CommRead const &)
1125 {
1126  HttpStateData *state = static_cast<HttpStateData*>(context);
1127  state->flags.do_next_read = true;
1128  state->maybeReadVirginBody();
1129 }
1130 
1131 void
1133 {
1134  Must(!flags.do_next_read); // XXX: should have been set false by mayReadVirginBody()
1135  flags.do_next_read = false;
1136 
1137  debugs(11, 5, io.conn);
1138 
1139  // Bail out early on Comm::ERR_CLOSING - close handlers will tidy up for us
1140  if (io.flag == Comm::ERR_CLOSING) {
1141  debugs(11, 3, "http socket closing");
1142  return;
1143  }
1144 
1146  abortTransaction("store entry aborted while reading reply");
1147  return;
1148  }
1149 
1151  Must(io.conn->fd == serverConnection->fd);
1152 
1153  /*
1154  * Don't reset the timeout value here. The value should be
1155  * counting Config.Timeout.request and applies to the request
1156  * as a whole, not individual read() calls.
1157  * Plus, it breaks our lame *HalfClosed() detection
1158  */
1159 
1161  CommIoCbParams rd(this); // will be expanded with ReadNow results
1162  rd.conn = io.conn;
1164 
1165  if (rd.size <= 0) {
1166  assert(entry->mem_obj);
1167  AsyncCall::Pointer nilCall;
1168  entry->mem_obj->delayRead(DeferredRead(readDelayed, this, CommRead(io.conn, NULL, 0, nilCall)));
1169  return;
1170  }
1171 
1172  switch (Comm::ReadNow(rd, inBuf)) {
1173  case Comm::INPROGRESS:
1174  if (inBuf.isEmpty())
1175  debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
1176  flags.do_next_read = true;
1178  return;
1179 
1180  case Comm::OK:
1181  {
1182  payloadSeen += rd.size;
1183 #if USE_DELAY_POOLS
1184  DelayId delayId = entry->mem_obj->mostBytesAllowed();
1185  delayId.bytesIn(rd.size);
1186 #endif
1187 
1188  statCounter.server.all.kbytes_in += rd.size;
1189  statCounter.server.http.kbytes_in += rd.size;
1190  ++ IOStats.Http.reads;
1191 
1192  int bin = 0;
1193  for (int clen = rd.size - 1; clen; ++bin)
1194  clen >>= 1;
1195 
1196  ++ IOStats.Http.read_hist[bin];
1197 
1199  }
1200 
1201  /* Continue to process previously read data */
1202  break;
1203 
1204  case Comm::ENDFILE: // close detected by 0-byte read
1205  eof = 1;
1206  flags.do_next_read = false;
1207 
1208  /* Continue to process previously read data */
1209  break;
1210 
1211  // case Comm::COMM_ERROR:
1212  default: // no other flags should ever occur
1213  debugs(11, 2, io.conn << ": read failure: " << xstrerr(rd.xerrno));
1215  err->xerrno = rd.xerrno;
1216  fwd->fail(err);
1217  flags.do_next_read = false;
1218  closeServer();
1219  mustStop("HttpStateData::readReply");
1220  return;
1221  }
1222 
1223  /* Process next response from buffer */
1224  processReply();
1225 }
1226 
1229 void
1231 {
1232 
1233  if (flags.handling1xx) { // we came back after handling a 1xx response
1234  debugs(11, 5, HERE << "done with 1xx handling");
1235  flags.handling1xx = false;
1237  }
1238 
1239  if (!flags.headers_parsed) { // have not parsed headers yet?
1240  PROF_start(HttpStateData_processReplyHeader);
1242  PROF_stop(HttpStateData_processReplyHeader);
1243 
1244  if (!continueAfterParsingHeader()) // parsing error or need more data
1245  return; // TODO: send errors to ICAP
1246 
1247  adaptOrFinalizeReply(); // may write to, abort, or "close" the entry
1248  }
1249 
1250  // kick more reads if needed and/or process the response body, if any
1251  PROF_start(HttpStateData_processReplyBody);
1252  processReplyBody(); // may call serverComplete()
1253  PROF_stop(HttpStateData_processReplyBody);
1254 }
1255 
1259 bool
1261 {
1262  if (flags.handling1xx) {
1263  debugs(11, 5, HERE << "wait for 1xx handling");
1265  return false;
1266  }
1267 
1268  if (!flags.headers_parsed && !eof) {
1269  debugs(11, 9, "needs more at " << inBuf.length());
1270  flags.do_next_read = true;
1274  maybeReadVirginBody(); // schedules all kinds of reads; TODO: rename
1275  return false;
1276  }
1277 
1281 
1282  if (flags.headers_parsed) { // parsed headers, possibly with errors
1283  // check for header parsing errors
1284  if (HttpReply *vrep = virginReply()) {
1285  const Http::StatusCode s = vrep->sline.status();
1286  const AnyP::ProtocolVersion &v = vrep->sline.version;
1287  if (s == Http::scInvalidHeader && v != Http::ProtocolVersion(0,9)) {
1288  debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Bad header encountered from " << entry->url() << " AKA " << request->url);
1289  error = ERR_INVALID_RESP;
1290  } else if (s == Http::scHeaderTooLarge) {
1291  fwd->dontRetry(true);
1292  error = ERR_TOO_BIG;
1293  } else if (vrep->header.conflictingContentLength()) {
1294  fwd->dontRetry(true);
1295  error = ERR_INVALID_RESP;
1296  } else {
1297  return true; // done parsing, got reply, and no error
1298  }
1299  } else {
1300  // parsed headers but got no reply
1301  debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: No reply at all for " << entry->url() << " AKA " << request->url);
1302  error = ERR_INVALID_RESP;
1303  }
1304  } else {
1305  assert(eof);
1306  if (inBuf.length()) {
1307  error = ERR_INVALID_RESP;
1308  debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Headers did not parse at all for " << entry->url() << " AKA " << request->url);
1309  } else {
1310  error = ERR_ZERO_SIZE_OBJECT;
1311  debugs(11, (request->flags.accelerated?DBG_IMPORTANT:2), "WARNING: HTTP: Invalid Response: No object data received for " << entry->url() << " AKA " << request->url);
1312  }
1313  }
1314 
1315  assert(error != ERR_NONE);
1316  entry->reset();
1317  fwd->fail(new ErrorState(error, Http::scBadGateway, fwd->request));
1318  flags.do_next_read = false;
1319  closeServer();
1320  mustStop("HttpStateData::continueAfterParsingHeader");
1321  return false; // quit on error
1322 }
1323 
1326 void
1328 {
1330 
1331  HttpReply *vrep = virginReply();
1332  int64_t clen = -1;
1333  if (!vrep->expectingBody(request->method, clen) || clen < 0)
1334  return; // no body or a body of unknown size, including chunked
1335 
1336  if (payloadSeen - payloadTruncated <= clen)
1337  return; // we did not read too much or already took care of the extras
1338 
1339  if (const int64_t extras = payloadSeen - payloadTruncated - clen) {
1340  // server sent more that the advertised content length
1341  debugs(11, 5, "payloadSeen=" << payloadSeen <<
1342  " clen=" << clen << '/' << vrep->content_length <<
1343  " trucated=" << payloadTruncated << '+' << extras);
1344 
1345  inBuf.chop(0, inBuf.length() - extras);
1346  payloadTruncated += extras;
1347  }
1348 }
1349 
1354 void
1356 {
1357  truncateVirginBody(); // if needed
1358  const char *data = inBuf.rawContent();
1359  int len = inBuf.length();
1360  addVirginReplyBody(data, len);
1361  inBuf.consume(len);
1362 }
1363 
1364 bool
1366 {
1367  const char *data = NULL;
1368  int len;
1369  bool wasThereAnException = false;
1370  assert(flags.chunked);
1373  MemBuf decodedData;
1374  decodedData.init();
1375  httpChunkDecoder->setPayloadBuffer(&decodedData);
1376  const bool doneParsing = httpChunkDecoder->parse(inBuf);
1377  inBuf = httpChunkDecoder->remaining(); // sync buffers after parse
1378  len = decodedData.contentSize();
1379  data=decodedData.content();
1380  addVirginReplyBody(data, len);
1381  if (doneParsing) {
1382  lastChunk = 1;
1383  flags.do_next_read = false;
1384  }
1385  SQUID_EXIT_THROWING_CODE(wasThereAnException);
1386  return wasThereAnException;
1387 }
1388 
1396 void
1398 {
1399  if (!flags.headers_parsed) {
1400  flags.do_next_read = true;
1402  return;
1403  }
1404 
1405 #if USE_ADAPTATION
1406  debugs(11,5, HERE << "adaptationAccessCheckPending=" << adaptationAccessCheckPending);
1408  return;
1409 
1410 #endif
1411 
1412  /*
1413  * At this point the reply headers have been parsed and consumed.
1414  * That means header content has been removed from readBuf and
1415  * it contains only body data.
1416  */
1417  if (entry->isAccepting()) {
1418  if (flags.chunked) {
1419  if (!decodeAndWriteReplyBody()) {
1420  flags.do_next_read = false;
1421  serverComplete();
1422  return;
1423  }
1424  } else
1425  writeReplyBody();
1426  }
1427 
1428  // storing/sending methods like earlier adaptOrFinalizeReply() or
1429  // above writeReplyBody() may release/abort the store entry.
1431  // TODO: In some cases (e.g., 304), we should keep persistent conn open.
1432  // Detect end-of-reply (and, hence, pool our idle pconn) earlier (ASAP).
1433  abortTransaction("store entry aborted while storing reply");
1434  return;
1435  } else
1436  switch (persistentConnStatus()) {
1437  case INCOMPLETE_MSG: {
1438  debugs(11, 5, "processReplyBody: INCOMPLETE_MSG from " << serverConnection);
1439  /* Wait for more data or EOF condition */
1440  AsyncCall::Pointer nil;
1441  if (flags.keepalive_broken) {
1443  } else {
1445  }
1446 
1447  flags.do_next_read = true;
1448  }
1449  break;
1450 
1451  case COMPLETE_PERSISTENT_MSG: {
1452  debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG from " << serverConnection);
1453 
1454  // TODO: Remove serverConnectionSaved but preserve exception safety.
1455 
1457  flags.do_next_read = false;
1458 
1460  closeHandler = NULL;
1461 
1462  Ip::Address client_addr; // XXX: Remove as unused. Why was it added?
1464  client_addr = request->client_addr;
1465 
1466  auto serverConnectionSaved = serverConnection;
1468  serverConnection = nullptr;
1469 
1470  bool ispinned = false; // TODO: Rename to isOrShouldBePinned
1471  if (request->flags.pinned) {
1472  ispinned = true;
1473  } else if (request->flags.connectionAuth && request->flags.authSent) {
1474  ispinned = true;
1475  }
1476 
1477  if (ispinned) {
1480  ConnStateData,
1481  notePinnedConnectionBecameIdle,
1482  ConnStateData::PinnedIdleContext(serverConnectionSaved, request));
1483  } else {
1484  // must not pool/share ispinned connections, even orphaned ones
1485  serverConnectionSaved->close();
1486  }
1487  } else {
1488  fwd->pconnPush(serverConnectionSaved, request->url.host());
1489  }
1490 
1491  serverComplete();
1492  return;
1493  }
1494 
1496  debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG from " << serverConnection);
1497  serverComplete();
1498  return;
1499  }
1500 
1502 }
1503 
1504 bool
1506 {
1507  // TODO: Be more precise here. For example, if/when reading trailer, we may
1508  // not be doneWithServer() yet, but we should return false. Similarly, we
1509  // could still be writing the request body after receiving the whole reply.
1510  return !doneWithServer();
1511 }
1512 
1513 void
1515 {
1516  // too late to read
1518  return;
1519 
1520  if (!maybeMakeSpaceAvailable(false))
1521  return;
1522 
1523  // XXX: get rid of the do_next_read flag
1524  // check for the proper reasons preventing read(2)
1525  if (!flags.do_next_read)
1526  return;
1527 
1528  flags.do_next_read = false;
1529 
1530  // must not already be waiting for read(2) ...
1532 
1533  // wait for read(2) to be possible.
1535  AsyncCall::Pointer call = JobCallback(11, 5, Dialer, this, HttpStateData::readReply);
1537 }
1538 
1539 bool
1541 {
1542  // how much we are allowed to buffer
1543  const int limitBuffer = (flags.headers_parsed ? Config.readAheadGap : Config.maxReplyHeaderSize);
1544 
1545  if (limitBuffer < 0 || inBuf.length() >= (SBuf::size_type)limitBuffer) {
1546  // when buffer is at or over limit already
1547  debugs(11, 7, "will not read up to " << limitBuffer << ". buffer has (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection);
1548  debugs(11, DBG_DATA, "buffer has {" << inBuf << "}");
1549  // Process next response from buffer
1550  processReply();
1551  return false;
1552  }
1553 
1554  // how much we want to read
1555  const size_t read_size = calcBufferSpaceToReserve(inBuf.spaceSize(), (limitBuffer - inBuf.length()));
1556 
1557  if (!read_size) {
1558  debugs(11, 7, "will not read up to " << read_size << " into buffer (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection);
1559  return false;
1560  }
1561 
1562  // just report whether we could grow or not, do not actually do it
1563  if (doGrow)
1564  return (read_size >= 2);
1565 
1566  // we may need to grow the buffer
1567  inBuf.reserveSpace(read_size);
1568  debugs(11, 8, (!flags.do_next_read ? "will not" : "may") <<
1569  " read up to " << read_size << " bytes info buf(" << inBuf.length() << "/" << inBuf.spaceSize() <<
1570  ") from " << serverConnection);
1571 
1572  return (inBuf.spaceSize() >= 2); // only read if there is 1+ bytes of space available
1573 }
1574 
1576 void
1578 {
1579  debugs(11, 5, HERE << serverConnection << ": size " << io.size << ": errflag " << io.flag << ".");
1580 #if URL_CHECKSUM_DEBUG
1581 
1582  entry->mem_obj->checkUrlChecksum();
1583 #endif
1584 
1585  // XXX: Keep in sync with Client::sentRequestBody().
1586  // TODO: Extract common parts.
1587 
1588  if (io.size > 0) {
1589  fd_bytes(io.fd, io.size, FD_WRITE);
1590  statCounter.server.all.kbytes_out += io.size;
1591  statCounter.server.http.kbytes_out += io.size;
1592  }
1593 
1594  if (io.flag == Comm::ERR_CLOSING)
1595  return;
1596 
1597  // both successful and failed writes affect response times
1599 
1600  if (io.flag) {
1602  err->xerrno = io.xerrno;
1603  fwd->fail(err);
1604  closeServer();
1605  mustStop("HttpStateData::wroteLast");
1606  return;
1607  }
1608 
1609  sendComplete();
1610 }
1611 
1613 void
1615 {
1616  /*
1617  * Set the read timeout here because it hasn't been set yet.
1618  * We only set the read timeout after the request has been
1619  * fully written to the peer. If we start the timeout
1620  * after connection establishment, then we are likely to hit
1621  * the timeout for POST/PUT requests that have very large
1622  * request bodies.
1623  */
1625  AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
1626  TimeoutDialer, this, HttpStateData::httpTimeout);
1627 
1629  flags.request_sent = true;
1630 }
1631 
1632 void
1634 {
1635  debugs(11,5, HERE << "closing HTTP server " << serverConnection << " this " << this);
1636 
1640  closeHandler = NULL;
1642  }
1643 }
1644 
1645 bool
1647 {
1649 }
1650 
1651 /*
1652  * Fixup authentication request headers for special cases
1653  */
1654 static void
1656 {
1658 
1659  /* Nothing to do unless we are forwarding to a peer */
1660  if (!request->flags.proxying)
1661  return;
1662 
1663  /* Needs to be explicitly enabled */
1664  if (!request->peer_login)
1665  return;
1666 
1667  /* Maybe already dealt with? */
1668  if (hdr_out->has(header))
1669  return;
1670 
1671  /* Nothing to do here for PASSTHRU */
1672  if (strcmp(request->peer_login, "PASSTHRU") == 0)
1673  return;
1674 
1675  /* PROXYPASS is a special case, single-signon to servers with the proxy password (basic only) */
1676  if (flags.originpeer && strcmp(request->peer_login, "PROXYPASS") == 0 && hdr_in->has(Http::HdrType::PROXY_AUTHORIZATION)) {
1677  const char *auth = hdr_in->getStr(Http::HdrType::PROXY_AUTHORIZATION);
1678 
1679  if (auth && strncasecmp(auth, "basic ", 6) == 0) {
1680  hdr_out->putStr(header, auth);
1681  return;
1682  }
1683  }
1684 
1685  char loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
1686  size_t blen;
1687  struct base64_encode_ctx ctx;
1688  base64_encode_init(&ctx);
1689 
1690  /* Special mode to pass the username to the upstream cache */
1691  if (*request->peer_login == '*') {
1692  const char *username = "-";
1693 
1694  if (request->extacl_user.size())
1695  username = request->extacl_user.termedBuf();
1696 #if USE_AUTH
1697  else if (request->auth_user_request != NULL)
1698  username = request->auth_user_request->username();
1699 #endif
1700 
1701  blen = base64_encode_update(&ctx, loginbuf, strlen(username), reinterpret_cast<const uint8_t*>(username));
1702  blen += base64_encode_update(&ctx, loginbuf+blen, strlen(request->peer_login +1), reinterpret_cast<const uint8_t*>(request->peer_login +1));
1703  blen += base64_encode_final(&ctx, loginbuf+blen);
1704  httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
1705  return;
1706  }
1707 
1708  /* external_acl provided credentials */
1709  if (request->extacl_user.size() && request->extacl_passwd.size() &&
1710  (strcmp(request->peer_login, "PASS") == 0 ||
1711  strcmp(request->peer_login, "PROXYPASS") == 0)) {
1712 
1713  blen = base64_encode_update(&ctx, loginbuf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
1714  blen += base64_encode_update(&ctx, loginbuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
1715  blen += base64_encode_update(&ctx, loginbuf+blen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
1716  blen += base64_encode_final(&ctx, loginbuf+blen);
1717  httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
1718  return;
1719  }
1720  // if no external user credentials are available to fake authentication with PASS acts like PASSTHRU
1721  if (strcmp(request->peer_login, "PASS") == 0)
1722  return;
1723 
1724  /* Kerberos login to peer */
1725 #if HAVE_AUTH_MODULE_NEGOTIATE && HAVE_KRB5 && HAVE_GSSAPI
1726  if (strncmp(request->peer_login, "NEGOTIATE",strlen("NEGOTIATE")) == 0) {
1727  char *Token=NULL;
1728  char *PrincipalName=NULL,*p;
1729  int negotiate_flags = 0;
1730 
1731  if ((p=strchr(request->peer_login,':')) != NULL ) {
1732  PrincipalName=++p;
1733  }
1734  if (request->flags.auth_no_keytab) {
1735  negotiate_flags |= PEER_PROXY_NEGOTIATE_NOKEYTAB;
1736  }
1737  Token = peer_proxy_negotiate_auth(PrincipalName, request->peer_host, negotiate_flags);
1738  if (Token) {
1739  httpHeaderPutStrf(hdr_out, header, "Negotiate %s",Token);
1740  }
1741  return;
1742  }
1743 #endif /* HAVE_KRB5 && HAVE_GSSAPI */
1744 
1745  blen = base64_encode_update(&ctx, loginbuf, strlen(request->peer_login), reinterpret_cast<const uint8_t*>(request->peer_login));
1746  blen += base64_encode_final(&ctx, loginbuf+blen);
1747  httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
1748  return;
1749 }
1750 
1751 /*
1752  * build request headers and append them to a given MemBuf
1753  * used by buildRequestPrefix()
1754  * note: initialised the HttpHeader, the caller is responsible for Clean()-ing
1755  */
1756 void
1758  StoreEntry * entry,
1759  const AccessLogEntryPointer &al,
1760  HttpHeader * hdr_out,
1761  const Http::StateFlags &flags)
1762 {
1763  /* building buffer for complex strings */
1764 #define BBUF_SZ (MAX_URL+32)
1765  LOCAL_ARRAY(char, bbuf, BBUF_SZ);
1766  LOCAL_ARRAY(char, ntoabuf, MAX_IPSTRLEN);
1767  const HttpHeader *hdr_in = &request->header;
1768  const HttpHeaderEntry *e = NULL;
1770  assert (hdr_out->owner == hoRequest);
1771 
1772  /* use our IMS header if the cached entry has Last-Modified time */
1773  if (request->lastmod > -1)
1774  hdr_out->putTime(Http::HdrType::IF_MODIFIED_SINCE, request->lastmod);
1775 
1776  // Add our own If-None-Match field if the cached entry has a strong ETag.
1777  // copyOneHeaderFromClientsideRequestToUpstreamRequest() adds client ones.
1778  if (request->etag.size() > 0) {
1780  request->etag.termedBuf()));
1781  }
1782 
1783  bool we_do_ranges = decideIfWeDoRanges (request);
1784 
1785  String strConnection (hdr_in->getList(Http::HdrType::CONNECTION));
1786 
1787  while ((e = hdr_in->getEntry(&pos)))
1788  copyOneHeaderFromClientsideRequestToUpstreamRequest(e, strConnection, request, hdr_out, we_do_ranges, flags);
1789 
1790  /* Abstraction break: We should interpret multipart/byterange responses
1791  * into offset-length data, and this works around our inability to do so.
1792  */
1793  if (!we_do_ranges && request->multipartRangeRequest()) {
1794  /* don't cache the result */
1795  request->flags.cachable = false;
1796  /* pretend it's not a range request */
1797  request->ignoreRange("want to request the whole object");
1798  request->flags.isRanged = false;
1799  }
1800 
1801  hdr_out->addVia(request->http_ver, hdr_in);
1802 
1803  if (request->flags.accelerated) {
1804  /* Append Surrogate-Capabilities */
1805  String strSurrogate(hdr_in->getList(Http::HdrType::SURROGATE_CAPABILITY));
1806 #if USE_SQUID_ESI
1807  snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"", Config.Accel.surrogate_id);
1808 #else
1809  snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0\"", Config.Accel.surrogate_id);
1810 #endif
1811  strListAdd(&strSurrogate, bbuf, ',');
1812  hdr_out->putStr(Http::HdrType::SURROGATE_CAPABILITY, strSurrogate.termedBuf());
1813  }
1814 
1816  if (strcmp(opt_forwarded_for, "delete") != 0) {
1817 
1818  String strFwd = hdr_in->getList(Http::HdrType::X_FORWARDED_FOR);
1819 
1820  // if we cannot double strFwd size, then it grew past 50% of the limit
1821  if (!strFwd.canGrowBy(strFwd.size())) {
1822  // There is probably a forwarding loop with Via detection disabled.
1823  // If we do nothing, String will assert on overflow soon.
1824  // TODO: Terminate all transactions with huge XFF?
1825  strFwd = "error";
1826 
1827  static int warnedCount = 0;
1828  if (warnedCount++ < 100) {
1829  const SBuf url(entry ? SBuf(entry->url()) : request->effectiveRequestUri());
1830  debugs(11, DBG_IMPORTANT, "Warning: likely forwarding loop with " << url);
1831  }
1832  }
1833 
1834  if (strcmp(opt_forwarded_for, "on") == 0) {
1836  if ( request->client_addr.isNoAddr() )
1837  strListAdd(&strFwd, "unknown", ',');
1838  else
1839  strListAdd(&strFwd, request->client_addr.toStr(ntoabuf, MAX_IPSTRLEN), ',');
1840  } else if (strcmp(opt_forwarded_for, "off") == 0) {
1842  strListAdd(&strFwd, "unknown", ',');
1843  } else if (strcmp(opt_forwarded_for, "transparent") == 0) {
1845  } else if (strcmp(opt_forwarded_for, "truncate") == 0) {
1847  if ( request->client_addr.isNoAddr() )
1848  strFwd = "unknown";
1849  else
1850  strFwd = request->client_addr.toStr(ntoabuf, MAX_IPSTRLEN);
1851  }
1852  if (strFwd.size() > 0)
1853  hdr_out->putStr(Http::HdrType::X_FORWARDED_FOR, strFwd.termedBuf());
1854  }
1857  /* append Host if not there already */
1858  if (!hdr_out->has(Http::HdrType::HOST)) {
1859  if (request->peer_domain) {
1860  hdr_out->putStr(Http::HdrType::HOST, request->peer_domain);
1861  } else {
1862  SBuf authority = request->url.authority();
1863  hdr_out->putStr(Http::HdrType::HOST, authority.c_str());
1864  }
1865  }
1866 
1867  /* append Authorization if known in URL, not in header and going direct */
1868  if (!hdr_out->has(Http::HdrType::AUTHORIZATION)) {
1869  if (!request->flags.proxying && !request->url.userInfo().isEmpty()) {
1870  static char result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
1871  struct base64_encode_ctx ctx;
1872  base64_encode_init(&ctx);
1873  size_t blen = base64_encode_update(&ctx, result, request->url.userInfo().length(), reinterpret_cast<const uint8_t*>(request->url.userInfo().rawContent()));
1874  blen += base64_encode_final(&ctx, result+blen);
1875  result[blen] = '\0';
1876  if (blen)
1877  httpHeaderPutStrf(hdr_out, Http::HdrType::AUTHORIZATION, "Basic %.*s", (int)blen, result);
1878  }
1879  }
1880 
1881  /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */
1882  httpFixupAuthentication(request, hdr_in, hdr_out, flags);
1883 
1884  /* append Cache-Control, add max-age if not there already */
1885  {
1886  HttpHdrCc *cc = hdr_in->getCc();
1887 
1888  if (!cc)
1889  cc = new HttpHdrCc();
1890 
1891 #if 0 /* see bug 2330 */
1892  /* Set no-cache if determined needed but not found */
1893  if (request->flags.nocache)
1895 #endif
1896 
1897  /* Add max-age only without no-cache */
1898  if (!cc->hasMaxAge() && !cc->hasNoCache()) {
1899  // XXX: performance regression. c_str() reallocates
1900  SBuf tmp(request->effectiveRequestUri());
1901  cc->maxAge(getMaxAge(entry ? entry->url() : tmp.c_str()));
1902  }
1903 
1904  /* Enforce sibling relations */
1905  if (flags.only_if_cached)
1906  cc->onlyIfCached(true);
1907 
1908  hdr_out->putCc(cc);
1909 
1910  delete cc;
1911  }
1912 
1913  /* maybe append Connection: keep-alive */
1914  if (flags.keepalive) {
1915  hdr_out->putStr(Http::HdrType::CONNECTION, "keep-alive");
1916  }
1917 
1918  /* append Front-End-Https */
1919  if (flags.front_end_https) {
1920  if (flags.front_end_https == 1 || request->url.getScheme() == AnyP::PROTO_HTTPS)
1921  hdr_out->putStr(Http::HdrType::FRONT_END_HTTPS, "On");
1922  }
1923 
1924  if (flags.chunked_request) {
1925  // Do not just copy the original value so that if the client-side
1926  // starts decode other encodings, this code may remain valid.
1927  hdr_out->putStr(Http::HdrType::TRANSFER_ENCODING, "chunked");
1928  }
1929 
1930  /* Now mangle the headers. */
1931  httpHdrMangleList(hdr_out, request, al, ROR_REQUEST);
1932 
1933  strConnection.clean();
1934 }
1935 
1940 void
1941 copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, HttpHeader * hdr_out, const int we_do_ranges, const Http::StateFlags &flags)
1942 {
1943  debugs(11, 5, "httpBuildRequestHeader: " << e->name << ": " << e->value );
1944 
1945  switch (e->id) {
1946 
1954  if (!flags.originpeer && flags.proxying && request->peer_login &&
1955  (strcmp(request->peer_login, "PASS") == 0 ||
1956  strcmp(request->peer_login, "PROXYPASS") == 0 ||
1957  strcmp(request->peer_login, "PASSTHRU") == 0)) {
1958  hdr_out->addEntry(e->clone());
1959  }
1960  break;
1961 
1965  case Http::HdrType::TE:
1968  case Http::HdrType::TRAILER:
1969  case Http::HdrType::UPGRADE:
1971  break;
1972 
1979  if (!flags.originpeer) {
1980  hdr_out->addEntry(e->clone());
1981  } else {
1985  if (request->peer_login &&
1986  (strcmp(request->peer_login, "PASS") == 0 ||
1987  strcmp(request->peer_login, "PASSTHRU") == 0 ||
1988  strcmp(request->peer_login, "PROXYPASS") == 0)) {
1989  hdr_out->addEntry(e->clone());
1990  }
1991  }
1992 
1993  break;
1994 
1995  case Http::HdrType::HOST:
2002  if (request->peer_domain)
2003  hdr_out->putStr(Http::HdrType::HOST, request->peer_domain);
2004  else if (request->flags.redirected && !Config.onoff.redir_rewrites_host)
2005  hdr_out->addEntry(e->clone());
2006  else {
2007  SBuf authority = request->url.authority();
2008  hdr_out->putStr(Http::HdrType::HOST, authority.c_str());
2009  }
2010 
2011  break;
2012 
2021  // XXX: need to check and cleanup the auth case so cacheable auth requests get cached.
2022  if (hdr_out->has(Http::HdrType::IF_MODIFIED_SINCE))
2023  break;
2024  else if (Config.onoff.cache_miss_revalidate || !request->flags.cachable || request->flags.auth)
2025  hdr_out->addEntry(e->clone());
2026  break;
2027 
2036  // XXX: need to check and cleanup the auth case so cacheable auth requests get cached.
2037  if (hdr_out->hasListMember(Http::HdrType::IF_MATCH, "*", ',') || Config.onoff.cache_miss_revalidate || !request->flags.cachable || request->flags.auth)
2038  hdr_out->addEntry(e->clone());
2039  break;
2040 
2044  if (request->method == Http::METHOD_TRACE || request->method == Http::METHOD_OPTIONS) {
2045  const int64_t hops = e->getInt64();
2046 
2047  if (hops > 0)
2048  hdr_out->putInt64(Http::HdrType::MAX_FORWARDS, hops - 1);
2049  }
2050 
2051  break;
2052 
2053  case Http::HdrType::VIA:
2058  if (!Config.onoff.via)
2059  hdr_out->addEntry(e->clone());
2060 
2061  break;
2062 
2063  case Http::HdrType::RANGE:
2064 
2066 
2070  if (!we_do_ranges)
2071  hdr_out->addEntry(e->clone());
2072 
2073  break;
2074 
2075  case Http::HdrType::PROXY_CONNECTION: // SHOULD ignore. But doing so breaks things.
2076  break;
2077 
2079  // pass through unless we chunk; also, keeping this away from default
2080  // prevents request smuggling via Connection: Content-Length tricks
2081  if (!flags.chunked_request)
2082  hdr_out->addEntry(e->clone());
2083  break;
2084 
2086 
2091  break;
2092 
2096  if (!flags.front_end_https)
2097  hdr_out->addEntry(e->clone());
2098 
2099  break;
2100 
2101  default:
2105  if (strConnection.size()>0 && strListIsMember(&strConnection, e->name, ',')) {
2106  debugs(11, 2, "'" << e->name << "' header cropped by Connection: definition");
2107  return;
2108  }
2109 
2110  hdr_out->addEntry(e->clone());
2111  }
2112 }
2113 
2114 bool
2116 {
2117  bool result = true;
2118  /* decide if we want to do Ranges ourselves
2119  * and fetch the whole object now)
2120  * We want to handle Ranges ourselves iff
2121  * - we can actually parse client Range specs
2122  * - the specs are expected to be simple enough (e.g. no out-of-order ranges)
2123  * - reply will be cachable
2124  * (If the reply will be uncachable we have to throw it away after
2125  * serving this request, so it is better to forward ranges to
2126  * the server and fetch only the requested content)
2127  */
2128 
2129  int64_t roffLimit = request->getRangeOffsetLimit();
2130 
2131  if (NULL == request->range || !request->flags.cachable
2132  || request->range->offsetLimitExceeded(roffLimit) || request->flags.connectionAuth)
2133  result = false;
2134 
2135  debugs(11, 8, "decideIfWeDoRanges: range specs: " <<
2136  request->range << ", cachable: " <<
2137  request->flags.cachable << "; we_do_ranges: " << result);
2138 
2139  return result;
2140 }
2141 
2142 /* build request prefix and append it to a given MemBuf;
2143  * return the length of the prefix */
2144 mb_size_t
2146 {
2147  const int offset = mb->size;
2148  /* Uses a local httpver variable to print the HTTP label
2149  * since the HttpRequest may have an older version label.
2150  * XXX: This could create protocol bugs as the headers sent and
2151  * flow control should all be based on the HttpRequest version
2152  * not the one we are sending. Needs checking.
2153  */
2154  const AnyP::ProtocolVersion httpver = Http::ProtocolVersion();
2156  mb->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\r\n",
2158  SQUIDSBUFPRINT(url),
2160  httpver.major,httpver.minor);
2161  /* build and pack headers */
2162  {
2163  HttpHeader hdr(hoRequest);
2165 
2167  request->flags.authSent = true;
2168  else if (hdr.has(Http::HdrType::AUTHORIZATION))
2169  request->flags.authSent = true;
2170 
2171  hdr.packInto(mb);
2172  hdr.clean();
2173  }
2174  /* append header terminator */
2175  mb->append(crlf, 2);
2176  return mb->size - offset;
2177 }
2178 
2179 /* This will be called when connect completes. Write request. */
2180 bool
2182 {
2183  MemBuf mb;
2184 
2185  debugs(11, 5, HERE << serverConnection << ", request " << request << ", this " << this << ".");
2186 
2188  debugs(11,3, HERE << "cannot send request to closing " << serverConnection);
2189  assert(closeHandler != NULL);
2190  return false;
2191  }
2192 
2194  AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
2195  TimeoutDialer, this, HttpStateData::httpTimeout);
2197  flags.do_next_read = true;
2199 
2200  if (request->body_pipe != NULL) {
2201  if (!startRequestBodyFlow()) // register to receive body data
2202  return false;
2204  requestSender = JobCallback(11,5,
2205  Dialer, this, HttpStateData::sentRequestBody);
2206 
2208  // use chunked encoding if we do not know the length
2209  if (request->content_length < 0)
2210  flags.chunked_request = true;
2211  } else {
2214  requestSender = JobCallback(11,5,
2215  Dialer, this, HttpStateData::wroteLast);
2216  }
2217 
2219  flags.proxying = (_peer != NULL && !flags.originpeer);
2220 
2221  /*
2222  * Is keep-alive okay for all request methods?
2223  */
2225  flags.keepalive = true;
2226  else if (request->flags.pinned)
2228  else if (!Config.onoff.server_pconns)
2229  flags.keepalive = false;
2230  else if (_peer == NULL)
2231  flags.keepalive = true;
2232  else if (_peer->stats.n_keepalives_sent < 10)
2233  flags.keepalive = true;
2234  else if ((double) _peer->stats.n_keepalives_recv /
2235  (double) _peer->stats.n_keepalives_sent > 0.50)
2236  flags.keepalive = true;
2237 
2238  if (_peer) {
2239  /*The old code here was
2240  if (neighborType(_peer, request->url) == PEER_SIBLING && ...
2241  which is equivalent to:
2242  if (neighborType(_peer, URL()) == PEER_SIBLING && ...
2243  or better:
2244  if (((_peer->type == PEER_MULTICAST && p->options.mcast_siblings) ||
2245  _peer->type == PEER_SIBLINGS ) && _peer->options.allow_miss)
2246  flags.only_if_cached = 1;
2247 
2248  But I suppose it was a bug
2249  */
2251  flags.only_if_cached = true;
2252 
2254  }
2255 
2256  mb.init();
2258  buildRequestPrefix(&mb);
2259 
2260  debugs(11, 2, "HTTP Server " << serverConnection);
2261  debugs(11, 2, "HTTP Server REQUEST:\n---------\n" << mb.buf << "\n----------");
2262 
2264  return true;
2265 }
2266 
2267 bool
2269 {
2270  // parent's implementation can handle the no-encoding case
2271  if (!flags.chunked_request)
2272  return Client::getMoreRequestBody(buf);
2273 
2274  MemBuf raw;
2275 
2277  if (!requestBodySource->getMoreData(raw))
2278  return false; // no request body bytes to chunk yet
2279 
2280  // optimization: pre-allocate buffer size that should be enough
2281  const mb_size_t rawDataSize = raw.contentSize();
2282  // we may need to send: hex-chunk-size CRLF raw-data CRLF last-chunk
2283  buf.init(16 + 2 + rawDataSize + 2 + 5, raw.max_capacity);
2284 
2285  buf.appendf("%x\r\n", static_cast<unsigned int>(rawDataSize));
2286  buf.append(raw.content(), rawDataSize);
2287  buf.append("\r\n", 2);
2288 
2289  Must(rawDataSize > 0); // we did not accidently created last-chunk above
2290 
2291  // Do not send last-chunk unless we successfully received everything
2294  flags.sentLastChunk = true;
2295  buf.append("0\r\n\r\n", 5);
2296  }
2297 
2298  return true;
2299 }
2300 
2301 void
2303 {
2304  debugs(11, 3, fwd->request->method << ' ' << fwd->entry->url());
2305  AsyncJob::Start(new HttpStateData(fwd));
2306 }
2307 
2308 void
2310 {
2311  if (!sendRequest()) {
2312  debugs(11, 3, "httpStart: aborted");
2313  mustStop("HttpStateData::start failed");
2314  return;
2315  }
2316 
2317  ++ statCounter.server.all.requests;
2318  ++ statCounter.server.http.requests;
2319 
2320  /*
2321  * We used to set the read timeout here, but not any more.
2322  * Now its set in httpSendComplete() after the full request,
2323  * including request body, has been written to the server.
2324  */
2325 }
2326 
2328 bool
2330 {
2331 #if USE_HTTP_VIOLATIONS
2332  if (!Config.accessList.brokenPosts) {
2333  debugs(11, 5, HERE << "No brokenPosts list");
2334  return false;
2335  }
2336 
2338  ch.al = fwd->al;
2339  ch.syncAle(originalRequest().getRaw(), nullptr);
2340  if (!ch.fastCheck().allowed()) {
2341  debugs(11, 5, HERE << "didn't match brokenPosts");
2342  return false;
2343  }
2344 
2346  debugs(11, 3, HERE << "ignoring broken POST for closed " << serverConnection);
2347  assert(closeHandler != NULL);
2348  return true; // prevent caller from proceeding as if nothing happened
2349  }
2350 
2351  debugs(11, 3, "finishingBrokenPost: fixing broken POST");
2353  requestSender = JobCallback(11,5,
2354  Dialer, this, HttpStateData::wroteLast);
2356  return true;
2357 #else
2358  return false;
2359 #endif /* USE_HTTP_VIOLATIONS */
2360 }
2361 
2363 bool
2365 {
2366  if (flags.sentLastChunk) {
2367  debugs(11, 5, HERE << "already sent last-chunk");
2368  return false;
2369  }
2370 
2371  Must(receivedWholeRequestBody); // or we should not be sending last-chunk
2372  flags.sentLastChunk = true;
2373 
2375  requestSender = JobCallback(11,5, Dialer, this, HttpStateData::wroteLast);
2376  Comm::Write(serverConnection, "0\r\n\r\n", 5, requestSender, NULL);
2377  return true;
2378 }
2379 
2380 void
2382 {
2384  debugs(11,5, HERE << serverConnection);
2385 
2386  // do we need to write something after the last body byte?
2388  return;
2390  return;
2391 
2392  sendComplete();
2393 }
2394 
2395 // more origin request body data is available
2396 void
2398 {
2400  // XXX: we should check this condition in other callbacks then!
2401  // TODO: Check whether this can actually happen: We should unsubscribe
2402  // as a body consumer when the above condition(s) are detected.
2403  debugs(11, DBG_IMPORTANT, HERE << "Transaction aborted while reading HTTP body");
2404  return;
2405  }
2406 
2408 
2409  if (requestBodySource->buf().hasContent()) {
2410  // XXX: why does not this trigger a debug message on every request?
2411 
2413  flags.abuse_detected = true;
2414  debugs(11, DBG_IMPORTANT, "http handleMoreRequestBodyAvailable: Likely proxy abuse detected '" << request->client_addr << "' -> '" << entry->url() << "'" );
2415 
2417  closeServer();
2418  mustStop("HttpStateData::handleMoreRequestBodyAvailable");
2419  return;
2420  }
2421  }
2422  }
2423 
2425 }
2426 
2427 // premature end of the request body
2428 void
2430 {
2432  if (entry->isEmpty()) {
2433  debugs(11, 3, "request body aborted: " << serverConnection);
2434  // We usually get here when ICAP REQMOD aborts during body processing.
2435  // We might also get here if client-side aborts, but then our response
2436  // should not matter because either client-side will provide its own or
2437  // there will be no response at all (e.g., if the the client has left).
2440  fwd->fail(err);
2441  }
2442 
2443  abortTransaction("request body producer aborted");
2444 }
2445 
2446 // called when we wrote request headers(!) or a part of the body
2447 void
2449 {
2450  if (io.size > 0)
2451  statCounter.server.http.kbytes_out += io.size;
2452 
2454 }
2455 
2456 void
2457 HttpStateData::abortAll(const char *reason)
2458 {
2459  debugs(11,5, HERE << "aborting transaction for " << reason <<
2460  "; " << serverConnection << ", this " << this);
2461  mustStop(reason);
2462 }
2463 
2465  : answer(HttpStateData::ReuseDecision::reuseNot), reason(nullptr), entry(e), statusCode(code) {}
2466 
2469 {
2470  answer = ans;
2471  reason = why;
2472  return answer;
2473 }
2474 
2475 std::ostream &operator <<(std::ostream &os, const HttpStateData::ReuseDecision &d)
2476 {
2477  static const char *ReuseMessages[] = {
2478  "do not cache and do not share", // reuseNot
2479  "cache positively and share", // cachePositively
2480  "cache negatively and share", // cacheNegatively
2481  "do not cache but share" // doNotCacheButShare
2482  };
2483 
2486  return os << ReuseMessages[d.answer] << " because " << d.reason <<
2487  "; HTTP status " << d.statusCode << " " << *(d.entry);
2488 }
2489 
#define MAX_LOGIN_SZ
Definition: defines.h:119
virtual void haveParsedReplyHeaders()
called when we have final (possibly adapted) reply headers; kids extend
Definition: http.cc:896
HierarchyLogEntry hier
Definition: HttpRequest.h:149
void maxStale(int v)
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
void reserveSpace(size_type minSpace)
Definition: SBuf.h:429
int has(Http::HdrType id) const
Definition: HttpHeader.cc:1011
short int keep_alive
Definition: HttpReply.h:57
struct StatCounters::@129 server
assists in making and relaying entry caching/sharing decision
Definition: http.h:28
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
bool continueAfterParsingHeader()
Definition: http.cc:1260
bool isAccepting() const
Definition: store.cc:2047
bool hasNoStore() const
int strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
Definition: StrList.cc:77
#define fd_table
Definition: fde.h:157
struct StatCounters::@129::@138 http
struct SquidConfig::@105 Accel
HttpHdrRange * range
Definition: HttpRequest.h:135
StatCounters statCounter
Definition: StatCounters.cc:12
void makePrivate(const bool shareable)
Definition: store.cc:151
#define assert(EX)
Definition: assert.h:17
bool peerSupportsConnectionPinning() const
Definition: http.cc:842
bool finishingChunkedRequest()
if needed, write last-chunk to end the request body and return true
Definition: http.cc:2364
void processReply()
Definition: http.cc:1230
int neighbors_do_private_keys
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:57
#define HttpHeaderInitPos
Definition: HttpHeader.h:48
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
virtual const Comm::ConnectionPointer & dataConnection() const
Definition: http.cc:140
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
int cache_miss_revalidate
Definition: SquidConfig.h:323
static void assembleVaryKey(String &vary, SBuf &vstr, const HttpRequest &request)
assemble a variant key (vary-mark) from the given Vary header and HTTP request
Definition: http.cc:569
HttpHdrCc * getCc() const
Definition: HttpHeader.cc:1243
Comm::Flag ReadNow(CommIoCbParams &params, SBuf &buf)
Definition: Read.cc:80
https_port or bumped http_port tunnel; HTTPS server
Definition: Message.h:32
a representation of a refresh pattern.
HttpHdrCc * cache_control
Definition: Message.h:76
void release(const bool shareable=false)
Definition: store.cc:1189
void pconnPush(Comm::ConnectionPointer &conn, const char *domain)
Definition: FwdState.cc:1206
acl_access * brokenPosts
Definition: SquidConfig.h:375
void set(const AnyP::ProtocolVersion &newVersion, Http::StatusCode newStatus, const char *newReason=NULL)
Definition: StatusLine.cc:30
bool startRequestBodyFlow()
Definition: Client.cc:215
virtual void sentRequestBody(const CommIoCbParams &io)
Definition: http.cc:2448
size_t calcBufferSpaceToReserve(const size_t space, const size_t wantSpace) const
determine how much space the buffer needs to reserve
Definition: Client.cc:1002
void adaptOrFinalizeReply()
Definition: Client.cc:944
time_t getMaxAge(const char *url)
Definition: refresh.cc:646
static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest *request, HttpHeader *hdr_out, const int we_do_ranges, const Http::StateFlags &)
Definition: http.cc:1941
int64_t payloadSeen
amount of message payload/body received so far.
Definition: http.h:146
static void httpFixupAuthentication(HttpRequest *request, const HttpHeader *hdr_in, HttpHeader *hdr_out, const Http::StateFlags &flags)
Definition: http.cc:1655
void mustStop(const char *aReason)
Definition: AsyncJob.cc:69
void path(const char *p)
Definition: Uri.h:86
bool timestampsSet()
Definition: store.cc:1454
Definition: SBuf.h:86
virtual bool getMoreRequestBody(MemBuf &buf)
either fill buf with available [encoded] request body bytes or return false
Definition: Client.cc:414
bool canHandle1xx() const
whether the client is likely to be able to handle a 1xx reply
Definition: HttpRequest.cc:642
virtual bool mayReadVirginReplyBody() const
whether we may receive more virgin response body bytes
Definition: http.cc:1505
const HttpReply * virginReply() const
Definition: Client.cc:110
HttpRequestMethod method
Definition: HttpRequest.h:106
bool isNoAddr() const
Definition: Address.cc:277
void serverComplete()
Definition: Client.cc:156
const MemBuf & buf() const
Definition: BodyPipe.h:137
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void error(char *format,...)
acl_access * reply
Definition: SquidConfig.h:379
StoreEntry * entry
Definition: Client.h:164
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
Definition: Client.h:29
int n_keepalives_recv
Definition: CachePeer.h:53
struct CachePeer::@29 stats
static const char *const crlf
Definition: http.cc:79
void ctx_exit(Ctx ctx)
Definition: debug.cc:731
int64_t bodySize(const HttpRequestMethod &) const
Definition: HttpReply.cc:371
Definition: Flag.h:16
bool forcedBodyContinuation
whether we have responded with HTTP 100 or FTP 150 already
Definition: HttpRequest.h:187
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
Definition: Range.h:18
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:540
http_port or HTTP server
Definition: Message.h:38
void removeStaleWarnings()
Remove Warnings with warn-date different from Date value.
Definition: HttpReply.cc:594
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:157
bool persistent() const
Definition: Message.cc:261
HttpRequest * request
Definition: FwdState.h:138
ReuseDecision(const StoreEntry *e, const Http::StatusCode code)
Definition: http.cc:2464
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
HttpHeaderEntry * getEntry(HttpHeaderPos *pos) const
Definition: HttpHeader.cc:598
Definition: enums.h:24
StoreEntry * storeGetPublicByRequestMethod(HttpRequest *req, const HttpRequestMethod &method, const KeyScope keyScope)
Definition: store.cc:522
void strListAdd(String *str, const char *item, char del)
Definition: StrList.cc:19
int64_t getInt64() const
Definition: HttpHeader.cc:1547
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
#define REFRESH_OVERRIDE(flag)
bool isEmpty() const
Definition: SBuf.h:420
virtual void abortAll(const char *reason)
abnormal transaction termination; reason is for debugging only
Definition: http.cc:2457
char * p
Definition: membanger.c:43
int server_pconns
Definition: SquidConfig.h:307
String getByName(const SBuf &name) const
Definition: HttpHeader.cc:888
int strListIsMember(const String *list, const SBuf &m, char del)
Definition: StrList.cc:37
HttpHdrScTarget * getMergedTarget(const char *ourtarget)
Definition: HttpHdrSc.cc:334
static void httpBuildRequestHeader(HttpRequest *request, StoreEntry *entry, const AccessLogEntryPointer &al, HttpHeader *hdr_out, const Http::StateFlags &flags)
Definition: http.cc:1757
bool hasPublic() const
Definition: HttpHdrCc.h:69
size_type size() const
Definition: SquidString.h:72
bool keepalive_broken
Definition: StateFlags.h:25
StoreEntry * storeGetPublic(const char *uri, const HttpRequestMethod &method)
Definition: store.cc:516
SBuf httpMakeVaryMark(HttpRequest *request, HttpReply const *reply)
Definition: http.cc:605
time_t squid_curtime
Definition: stub_time.cc:17
void writeReplyBody()
Definition: http.cc:1355
bool canGrowBy(const size_type growthLen) const
whether appending growthLen characters is safe (i.e., unlikely to assert)
Definition: SquidString.h:123
bool connectionAuth
Definition: RequestFlags.h:78
int32_t mask
Definition: HttpHdrCc.h:173
const StoreEntry * entry
entry for debugging
Definition: http.h:39
CachePeer * _peer
Definition: http.h:63
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
bool offsetLimitExceeded(const int64_t limit) const
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
Definition: Read.cc:39
bool sentLastChunk
do not try to write last-chunk again
Definition: StateFlags.h:31
bool httpHeaderHasConnDir(const HttpHeader *hdr, const SBuf &directive)
void maxAge(int32_t v)
Definition: HttpHdrCc.h:123
AsyncCall::Pointer closeHandler
Definition: http.h:86
void fd_bytes(int fd, int len, unsigned int type)
Definition: fd.cc:260
bool parseHeader(Http1::Parser &hp)
parses reply header using Parser
Definition: HttpReply.cc:463
Http::HdrType id
Definition: HttpHeader.h:63
void handle1xx(HttpReply *msg)
ignore or start forwarding the 1xx response (a.k.a., control message)
Definition: http.cc:785
bool chunked
reading a chunked response; TODO: rename
Definition: StateFlags.h:29
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
void httpHeaderPutStrf(HttpHeader *hdr, Http::HdrType id, const char *fmt,...)
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:167
int read_hist[histSize]
Definition: IoStats.h:21
time_t lifetime
Definition: SquidConfig.h:108
void toLower()
converts all characters to lower case;
Definition: SBuf.cc:821
virtual void maybeReadVirginBody()
read response data from the network
Definition: http.cc:1514
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
AsyncCall::Pointer requestSender
Definition: Client.h:170
bool hasMustRevalidate() const
Definition: HttpHdrCc.h:112
unsigned int major
major version number
void const char HLPCB void * data
Definition: stub_helper.cc:16
void delayRead(DeferredRead const &)
Definition: MemObject.cc:428
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
int commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
Definition: comm.cc:578
StatusCode
Definition: StatusCode.h:20
int64_t readAheadGap
Definition: SquidConfig.h:92
bool isEmpty() const
Definition: Store.h:60
bool hasContent() const
Definition: MemBuf.h:54
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
String extacl_passwd
Definition: HttpRequest.h:173
int64_t content_length
Definition: Message.h:83
Http1::TeChunkedParser * httpChunkDecoder
Definition: http.h:143
virtual bool expectingBody(const HttpRequestMethod &, int64_t &) const
Definition: HttpReply.cc:484
virtual void sendControlMsg(HttpControlMsg)
called to send the 1xx message and notify the Source
peer_t neighborType(const CachePeer *p, const AnyP::Uri &url)
Definition: neighbors.cc:113
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
const char * storeId() const
Definition: MemObject.cc:54
#define cbdataReference(var)
Definition: cbdata.h:341
HttpRequestMethod method
Definition: MemObject.h:102
#define DBG_IMPORTANT
Definition: Debug.h:46
bool Is1xx(const int sc)
whether this is an informational 1xx response status code
Definition: StatusCode.h:92
virtual void haveParsedReplyHeaders()
called when we have final (possibly adapted) reply headers; kids extend
Definition: Client.cc:506
char const * rawBuf() const
Definition: SquidString.h:85
FwdState::Pointer fwd
Definition: Client.h:165
int eof
Definition: http.h:64
bool hasNoCache(const String **val=nullptr) const
Definition: HttpHdrCc.h:89
void processSurrogateControl(HttpReply *)
Definition: http.cc:276
virtual bool doneWithServer() const
Definition: http.cc:1646
int redir_rewrites_host
Definition: SquidConfig.h:299
bool auth_no_keytab
Definition: RequestFlags.h:30
Http1::ResponseParserPointer hp
Parser being used at present to parse the HTTP/ICY server response.
Definition: http.h:142
virtual void handleRequestBodyProducerAborted()=0
Definition: Client.cc:327
bool connectionAuthDisabled
Definition: RequestFlags.h:80
void checkDateSkew(HttpReply *)
Definition: http.cc:644
int lastChunk
Definition: http.h:65
Ip::Address client_addr
Definition: HttpRequest.h:141
virtual void sentRequestBody(const CommIoCbParams &io)=0
Definition: Client.cc:340
void putTime(Http::HdrType id, time_t htime)
Definition: HttpHeader.cc:1063
char * surrogate_id
Definition: SquidConfig.h:213
mb_size_t size
Definition: MemBuf.h:135
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:88
BodyPipe::Pointer requestBodySource
Definition: Client.h:169
virtual HttpRequestPointer originalRequest()
a hack to reach HttpStateData::orignal_request
Definition: Client.cc:535
char const * termedBuf() const
Definition: SquidString.h:91
char * peer_host
Definition: HttpRequest.h:158
bool MonitorsRead(int fd)
whether the FD socket is being monitored for read
Definition: Read.cc:28
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:828
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:687
bool mustKeepalive
Definition: RequestFlags.h:76
bundles HTTP 1xx reply and the "successfully forwarded" callback
AnyP::Uri url
the request URI
Definition: HttpRequest.h:107
ConnectionStatus statusIfComplete() const
Definition: http.cc:1029
http_hdr_owner_type owner
Definition: HttpHeader.h:158
void userInfo(const SBuf &s)
Definition: Uri.h:75
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:222
struct SquidConfig::@113 accessList
void httpStateConnClosed(const CommCloseCbParams &params)
Definition: http.cc:146
bool allowed() const
Definition: Acl.h:141
AnyP::UriScheme const & getScheme() const
Definition: Uri.h:67
bool allow_miss
Definition: CachePeer.h:104
size_t maxReplyHeaderSize
Definition: SquidConfig.h:131
bool ignoreCacheControl
Definition: http.h:69
void sendComplete()
successfully wrote the entire request (including body, last-chunk, etc.)
Definition: http.cc:1614
void releaseRequest(const bool shareable=false)
Definition: store.cc:446
void base64_encode_init(struct base64_encode_ctx *ctx)
Definition: base64.c:232
const char * c_str()
Definition: SBuf.cc:526
bool reforwardableStatus(const Http::StatusCode s) const
Definition: FwdState.cc:1174
uint16_t flags
Definition: Store.h:208
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:62
void setNoDelay(bool const)
Definition: store.cc:252
Http::StatusLine sline
Definition: HttpReply.h:60
void host(const char *src)
Definition: Uri.cc:47
unsigned int front_end_https
send "Front-End-Https: On" header (off/on/auto=2)
Definition: StateFlags.h:18
static void readDelayed(void *context, CommRead const &)
Definition: http.cc:1124
MemObject * mem_obj
Definition: Store.h:197
SBuf consume(size_type n=npos)
Definition: SBuf.cc:491
time_t date
Definition: HttpReply.h:44
Ctx ctx_enter(const char *descr)
Definition: debug.cc:715
#define LOCAL_ARRAY(type, name, size)
Definition: leakcheck.h:18
DelayId mostBytesAllowed() const
Definition: MemObject.cc:449
int hasListMember(Http::HdrType id, const char *member, const char separator) const
Definition: HttpHeader.cc:1674
bool hasPrivate(const String **val=nullptr) const
Definition: HttpHdrCc.h:74
AnyP::ProtocolType protocol
Definition: StatusLine.h:68
HttpHdrSc * surrogate_control
Definition: HttpReply.h:52
int connection_auth
0 - off, 1 - on, 2 - auto
Definition: CachePeer.h:196
void addVirginReplyBody(const char *buf, ssize_t len)
Definition: Client.cc:977
void httpTimeout(const CommTimeoutCbParams &params)
Definition: http.cc:154
Comm::ConnectionPointer const & serverConnection() const
Definition: FwdState.h:107
bool hasMaxAge() const
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
char * content()
start of the added data
Definition: MemBuf.h:41
const char * url() const
Definition: store.cc:1600
bool surrogateNoStore
Definition: http.h:70
CachePeer * getPeer() const
Definition: Connection.cc:98
void ignoreRange(const char *reason)
forgets about the cached Range header (for a reason)
Definition: HttpRequest.cc:628
void addVia(const AnyP::ProtocolVersion &ver, const HttpHeader *from=0)
Definition: HttpHeader.cc:1019
static void httpMaybeRemovePublic(StoreEntry *, Http::StatusCode)
Definition: http.cc:177
virtual void start()
called by AsyncStart; do not call directly
Definition: http.cc:2309
unsigned char code
Definition: html_quote.c:20
void const char * buf
Definition: stub_helper.cc:16
void keepaliveAccounting(HttpReply *)
Definition: http.cc:624
int n_keepalives_sent
Definition: CachePeer.h:52
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
ssize_t HttpHeaderPos
Definition: HttpHeader.h:45
time_t negativeTtl
Definition: SquidConfig.h:96
struct SquidConfig::@112 onoff
size_t getMoreData(MemBuf &buf)
Definition: BodyPipe.cc:295
ConnectionStatus persistentConnStatus() const
Definition: http.cc:1074
int reads
Definition: IoStats.h:19
int front_end_https
0 - off, 1 - on, 2 - auto
Definition: CachePeer.h:195
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
SBuf inBuf
I/O buffer for receiving server responses.
Definition: http.h:68
HttpHeader header
Definition: Message.h:74
virtual bool parse(const SBuf &)
bool makePublic(const KeyScope keyScope=ksDefault)
Definition: store.cc:144
virtual void doneSendingRequestBody()=0
Definition: Client.cc:316
bool accelerated
Definition: RequestFlags.h:60
bool sendRequest()
Definition: http.cc:2181
SBuf vary_headers
Definition: MemObject.h:174
size_t base64_encode_final(struct base64_encode_ctx *ctx, char *dst)
Definition: base64.c:308
Http::StateFlags flags
Definition: http.h:66
void putInt64(Http::HdrType id, int64_t number)
Definition: HttpHeader.cc:1054
char * buf
Definition: MemBuf.h:134
AccessLogEntryPointer al
info for the future access.log entry
Definition: FwdState.h:139
void httpStart(FwdState *fwd)
Definition: http.cc:2302
const char * getMD5Text() const
Definition: store.cc:184
RequestFlags flags
Definition: HttpRequest.h:133
#define EBIT_SET(flag, bit)
Definition: defines.h:105
bool sawDateGoBack
Definition: http.h:152
const SBuf & image() const
void maxAge(int v)
store_status_t store_status
Definition: Store.h:220
mb_size_t buildRequestPrefix(MemBuf *mb)
Definition: http.cc:2145
prohibits making the key public
Definition: enums.h:90
void neighborsHtcpClear(StoreEntry *e, const char *uri, HttpRequest *req, const HttpRequestMethod &method, htcp_clr_reason reason)
Definition: neighbors.cc:1785
Answers answer
the decision id
Definition: http.h:37
struct StatCounters::@129::@138 all
void processReplyBody()
Definition: http.cc:1397
allow_t const & fastCheck()
Definition: Checklist.cc:336
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:1072
bool hasMaxAge(int32_t *val=nullptr) const
Definition: HttpHdrCc.h:122
bool hasNoCacheWithParameters() const
Definition: HttpHdrCc.h:87
void clean()
Definition: HttpHeader.cc:187
bool hasNoCacheWithoutParameters() const
Definition: HttpHdrCc.h:88
bool cacheNegatively()
Definition: store.cc:165
#define BBUF_SZ
HttpRequestPointer request
Definition: Client.h:166
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
void onlyIfCached(bool v)
Definition: HttpHdrCc.h:146
Comm::ConnectionPointer serverConnection
Definition: http.h:85
int detect_broken_server_pconns
Definition: SquidConfig.h:317
mb_size_t max_capacity
Definition: MemBuf.h:142
int64_t getRangeOffsetLimit()
Definition: HttpRequest.cc:601
#define PROF_start(probename)
Definition: Profiler.h:62
void putCc(const HttpHdrCc *cc)
Definition: HttpHeader.cc:1088
bool no_delay
Definition: CachePeer.h:102
int64_t payloadTruncated
positive when we read more than we wanted
Definition: http.h:148
char * opt_forwarded_for
bool dontRetry()
Definition: FwdState.h:102
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
size_t base64_encode_update(struct base64_encode_ctx *ctx, char *dst, size_t length, const uint8_t *src)
Definition: base64.c:265
HttpReply * setVirginReply(HttpReply *r)
Definition: Client.cc:117
char const * username() const
Definition: UserRequest.cc:32
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:87
String extacl_user
Definition: HttpRequest.h:171
bool handling1xx
we are ignoring or forwarding 1xx response
Definition: StateFlags.h:22
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
void processReplyHeader()
Definition: http.cc:661
ssize_t mb_size_t
Definition: MemBuf.h:17
bool chunked() const
whether message uses chunked Transfer-Encoding
Definition: HttpHeader.h:188
virtual void handleMoreRequestBodyAvailable()
Definition: http.cc:2397
bool receivedWholeRequestBody
handleRequestBodyProductionEnded called
Definition: Client.h:180
Definition: MemBuf.h:23
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:119
struct CachePeer::@31 options
void abortTransaction(const char *reason)
Definition: http.h:108
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:554
bool decodeAndWriteReplyBody()
Definition: http.cc:1365
struct SquidConfig::@98 Timeout
void fail(ErrorState *err)
Definition: FwdState.cc:459
virtual void closeServer()
Definition: http.cc:1633
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:97
const char * ProtocolType_str[]
ReuseDecision::Answers reusableReply(ReuseDecision &decision)
Definition: http.cc:314
bool adaptationAccessCheckPending
Definition: Client.h:177
const HttpReplyPointer & getReply() const
Definition: MemObject.h:57
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:961
IoStats IOStats
bool multipartRangeRequest() const
Definition: HttpRequest.cc:444
const char * getStr(Http::HdrType id) const
Definition: HttpHeader.cc:1212
void detailError(int dCode)
set error type-specific detail code
Definition: errorpage.h:97
size_t bytesWanted(Range< size_t > const aRange, bool ignoreDelayPool=false) const
Definition: store.cc:228
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
const SBuf & remaining() const
the remaining unprocessed section of buffer
Definition: Parser.h:96
void clean()
Definition: String.cc:125
#define MAX_URL
Definition: defines.h:118
unsigned int minor
minor version number
int xerrno
Definition: errorpage.h:149
int surrogate_is_remote
Definition: SquidConfig.h:315
#define PROF_stop(probename)
Definition: Profiler.h:63
bool refreshIsCachable(const StoreEntry *entry)
Definition: refresh.cc:528
#define rfc1738_escape_part(x)
Definition: rfc1738.h:55
void addEntry(HttpHeaderEntry *e)
Definition: HttpHeader.cc:751
time_t expires
Definition: HttpReply.h:48
void readReply(const CommIoCbParams &io)
Definition: http.cc:1132
~HttpStateData()
Definition: http.cc:125
StoreEntry * storeGetPublicByRequest(HttpRequest *req, const KeyScope keyScope)
Definition: store.cc:528
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:795
bool hasNoStore() const
Definition: HttpHdrCc.h:102
#define PEER_PROXY_NEGOTIATE_NOKEYTAB
ConnectionStatus
Definition: http.h:87
void bytesIn(int qty)
Definition: DelayId.cc:154
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define DBG_DATA
Definition: Debug.h:48
std::ostream & operator<<(std::ostream &os, const HttpStateData::ReuseDecision &d)
Definition: http.cc:2475
Answers make(const Answers ans, const char *why)
stores the corresponding decision
Definition: http.cc:2468
ProtocolType protocol
which protocol this version is for
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:988
AnyP::ProtocolVersion version
breakdown of protocol version label: (HTTP/ICY) and (0.9/1.0/1.1)
Definition: StatusLine.h:70
SBuf & authority(bool requirePort=false) const
Definition: Uri.cc:470
static bool decideIfWeDoRanges(HttpRequest *orig_request)
Definition: http.cc:2115
const char * rawContent() const
Definition: SBuf.cc:519
void reset()
Definition: store.cc:1676
void doneSendingRequestBody()
Definition: http.cc:2381
HttpReply * finalReply()
Definition: Client.cc:128
const Http::StatusCode statusCode
HTTP status for debugging.
Definition: http.h:40
bool finishingBrokenPost()
if broken posts are enabled for the request, try to fix and return true
Definition: http.cc:2329
#define SQUID_ENTER_THROWING_CODE()
Definition: http.cc:68
MemBlob::size_type size_type
Definition: SBuf.h:89
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
virtual bool getMoreRequestBody(MemBuf &buf)
either fill buf with available [encoded] request body bytes or return false
Definition: http.cc:2268
char * peer_login
Definition: HttpRequest.h:156
virtual void handleRequestBodyProducerAborted()
Definition: http.cc:2429
bool originserver
Definition: CachePeer.h:118
bool spoofClientIp
Definition: RequestFlags.h:72
StoreEntry * entry
Definition: FwdState.h:137
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:552
HttpRequestPointer request
Definition: MemObject.h:155
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
time_t lastmod
Definition: HttpRequest.h:160
void wroteLast(const CommIoCbParams &io)
called after writing the very last request byte (body, last-chunk, etc)
Definition: http.cc:1577
C * getRaw() const
Definition: RefCount.h:74
const char * doneWithFwd
Definition: Client.h:184
class SquidConfig Config
Definition: SquidConfig.cc:12
bool hasSMaxAge(int32_t *val=nullptr) const
Definition: HttpHdrCc.h:127
String etag
A strong etag of the cached entry. Used for refreshing that entry.
Definition: HttpRequest.h:184
#define NULL
Definition: types.h:166
void httpHdrMangleList(HttpHeader *l, HttpRequest *request, const AccessLogEntryPointer &al, req_or_rep_t req_or_rep)
uint32_t sources
The message sources.
Definition: Message.h:99
static StoreEntry * findPreviouslyCachedEntry(StoreEntry *newEntry)
Definition: http.cc:167
Http::StatusCode peer_reply_status
last HTTP status code received
const char * urlXXX() const
Definition: MemObject.h:93
char * peer_domain
Definition: HttpRequest.h:165
time_t read
Definition: SquidConfig.h:106
size_type spaceSize() const
Definition: SBuf.h:382
bool maybeMakeSpaceAvailable(bool grow)
Definition: http.cc:1540
#define false
Definition: GnuRegex.c:233
char * host
Definition: CachePeer.h:41
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
int Ctx
Definition: Debug.h:37
const char * reason
the decision reason
Definition: http.h:38
err_type
Definition: err_type.h:12
bool chunked_request
writing a chunked request
Definition: StateFlags.h:30
HttpStateData(FwdState *)
Definition: http.cc:85
#define base64_encode_len(length)
Definition: base64.h:169
void truncateVirginBody()
Definition: http.cc:1327
HttpHeaderEntry * clone() const
Definition: HttpHeader.cc:1519
struct IoStats::@81 Http
bool proxy_only
Definition: CachePeer.h:83
void unregister(Comm::ConnectionPointer &conn)
Definition: FwdState.cc:488
#define SQUID_EXIT_THROWING_CODE(status)
Definition: http.cc:69
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
void noStoreRemote(bool v)
void proceedAfter1xx()
restores state and resumes processing after 1xx is ignored or forwarded
Definition: http.cc:831

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors