ModXact.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 93 ICAP (RFC 3507) Client */
10 
11 #include "squid.h"
12 #include "AccessLogEntry.h"
13 #include "adaptation/Answer.h"
14 #include "adaptation/History.h"
15 #include "adaptation/icap/Client.h"
16 #include "adaptation/icap/Config.h"
21 #include "adaptation/Initiator.h"
22 #include "auth/UserRequest.h"
23 #include "base/TextException.h"
24 #include "base64.h"
25 #include "comm.h"
26 #include "comm/Connection.h"
27 #include "err_detail_type.h"
29 #include "HttpHeaderTools.h"
30 #include "HttpReply.h"
31 #include "MasterXaction.h"
32 #include "parser/Tokenizer.h"
33 #include "sbuf/Stream.h"
34 #include "SquidTime.h"
35 
36 // flow and terminology:
37 // HTTP| --> receive --> encode --> write --> |network
38 // end | <-- send <-- parse <-- read <-- |end
39 
40 // TODO: replace gotEncapsulated() with something faster; we call it often
41 
44 
45 static const size_t TheBackupLimit = BodyPipe::MaxCapacity;
46 
48 
50 {
51  memset(this, 0, sizeof(*this));
52 }
53 
56  AsyncJob("Adaptation::Icap::ModXact"),
57  Adaptation::Icap::Xaction("Adaptation::Icap::ModXact", aService),
58  virginConsumed(0),
60  canStartBypass(false), // too early
64  adaptHistoryId(-1),
65  trailerParser(nullptr),
66  alMaster(alp)
67 {
68  assert(virginHeader);
69 
70  virgin.setHeader(virginHeader); // sets virgin.body_pipe if needed
71  virgin.setCause(virginCause); // may be NULL
72 
73  // adapted header and body are initialized when we parse them
74 
75  // writing and reading ends are handled by Adaptation::Icap::Xaction
76 
77  // encoding
78  // nothing to do because we are using temporary buffers
79 
80  // parsing; TODO: do not set until we parse, see ICAPOptXact
81  icapReply = new HttpReply;
82  icapReply->protoPrefix = "ICAP/"; // TODO: make an IcapReply class?
83 
84  debugs(93,7, HERE << "initialized." << status());
85 }
86 
87 // initiator wants us to start
89 {
91 
92  // reserve an adaptation history slot (attempts are known at this time)
94  if (ah != NULL)
96 
97  estimateVirginBody(); // before virgin disappears!
98 
100 
101  // it is an ICAP violation to send request to a service w/o known OPTIONS
102  // and the service may is too busy for us: honor Max-Connections and such
103  if (service().up() && service().availableForNew())
104  startWriting();
105  else
106  waitForService();
107 }
108 
110 {
111  const char *comment;
113 
114  if (!service().up()) {
115  AsyncCall::Pointer call = JobCallback(93,5,
117 
118  service().callWhenReady(call);
119  comment = "to be up";
120  } else {
121  //The service is unavailable because of max-connection or other reason
122 
123  if (service().cfg().onOverload != srvWait) {
124  // The service is overloaded, but waiting to be available prohibited by
125  // user configuration (onOverload is set to "block" or "bypass")
126  if (service().cfg().onOverload == srvBlock)
127  disableBypass("not available", true);
128  else //if (service().cfg().onOverload == srvBypass)
129  canStartBypass = true;
130 
131  disableRetries();
132  disableRepeats("ICAP service is not available");
133 
134  debugs(93, 7, HERE << "will not wait for the service to be available" <<
135  status());
136 
137  throw TexcHere("ICAP service is not available");
138  }
139 
140  AsyncCall::Pointer call = JobCallback(93,5,
143  comment = "to be available";
144  }
145 
146  debugs(93, 7, HERE << "will wait for the service " << comment << status());
147  state.serviceWaiting = true; // after callWhenReady() which may throw
148  state.waitedForService = true;
149 }
150 
152 {
154  state.serviceWaiting = false;
155 
156  if (!service().up()) {
157  disableRetries();
158  disableRepeats("ICAP service is unusable");
159  throw TexcHere("ICAP service is unusable");
160  }
161 
162  if (service().availableForOld())
163  startWriting();
164  else
165  waitForService();
166 }
167 
169 {
171  state.serviceWaiting = false;
172 
173  if (service().up() && service().availableForOld())
174  startWriting();
175  else
176  waitForService();
177 }
178 
180 {
182 
183  decideOnPreview(); // must be decided before we decideOnRetries
184  decideOnRetries();
185 
186  openConnection();
187 }
188 
189 // connection with the ICAP service established
191 {
193 
194  startReading(); // wait for early errors from the ICAP server
195 
196  MemBuf requestBuf;
197  requestBuf.init();
198 
199  makeRequestHeaders(requestBuf);
200  debugs(93, 9, HERE << "will write" << status() << ":\n" <<
201  (requestBuf.terminate(), requestBuf.content()));
202 
203  // write headers
206  scheduleWrite(requestBuf);
207 }
208 
210 {
211  debugs(93, 5, HERE << "Wrote " << sz << " bytes");
212 
215  else
217 }
218 
220 {
222 
223  // determine next step
224  if (preview.enabled()) {
225  if (preview.done())
226  decideWritingAfterPreview("zero-size");
227  else
229  } else if (virginBody.expected()) {
231  } else {
232  stopWriting(true);
233  return;
234  }
235 
236  writeMore();
237 }
238 
240 {
241  debugs(93, 5, HERE << "checking whether to write more" << status());
242 
243  if (writer != NULL) // already writing something
244  return;
245 
246  switch (state.writing) {
247 
248  case State::writingInit: // waiting for service OPTIONS
250 
251  case State::writingConnect: // waiting for the connection to establish
252 
253  case State::writingHeaders: // waiting for the headers to be written
254 
255  case State::writingPaused: // waiting for the ICAP server response
256 
257  case State::writingReallyDone: // nothing more to write
258  return;
259 
260  case State::writingAlmostDone: // was waiting for the last write
261  stopWriting(false);
262  return;
263 
266  return;
267 
268  case State::writingPrime:
269  writePrimeBody();
270  return;
271 
272  default:
273  throw TexcHere("Adaptation::Icap::ModXact in bad writing state");
274  }
275 }
276 
278 {
279  debugs(93, 8, HERE << "will write Preview body from " <<
280  virgin.body_pipe << status());
283 
284  const size_t sizeMax = (size_t)virgin.body_pipe->buf().contentSize();
285  const size_t size = min(preview.debt(), sizeMax);
286  writeSomeBody("preview body", size);
287 
288  // change state once preview is written
289 
290  if (preview.done())
292 }
293 
296 {
297  if (preview.ieof()) // nothing more to write
298  stopWriting(true);
299  else if (state.parsing == State::psIcapHeader) // did not get a reply yet
300  state.writing = State::writingPaused; // wait for the ICAP server reply
301  else
302  stopWriting(true); // ICAP server reply implies no post-preview writing
303 
304  debugs(93, 6, HERE << "decided on writing after " << kind << " preview" <<
305  status());
306 }
307 
309 {
312 
313  const size_t size = (size_t)virgin.body_pipe->buf().contentSize();
314  writeSomeBody("prime virgin body", size);
315 
317  debugs(93, 5, HERE << "wrote entire body");
318  stopWriting(true);
319  }
320 }
321 
322 void Adaptation::Icap::ModXact::writeSomeBody(const char *label, size_t size)
323 {
326  debugs(93, 8, HERE << "will write up to " << size << " bytes of " <<
327  label);
328 
329  MemBuf writeBuf; // TODO: suggest a min size based on size and lastChunk
330 
331  writeBuf.init(); // note: we assume that last-chunk will fit
332 
333  const size_t writableSize = virginContentSize(virginBodyWriting);
334  const size_t chunkSize = min(writableSize, size);
335 
336  if (chunkSize) {
337  debugs(93, 7, HERE << "will write " << chunkSize <<
338  "-byte chunk of " << label);
339 
340  openChunk(writeBuf, chunkSize, false);
341  writeBuf.append(virginContentData(virginBodyWriting), chunkSize);
342  closeChunk(writeBuf);
343 
344  virginBodyWriting.progress(chunkSize);
345  virginConsume();
346  } else {
347  debugs(93, 7, HERE << "has no writable " << label << " content");
348  }
349 
350  const bool wroteEof = virginBodyEndReached(virginBodyWriting);
351  bool lastChunk = wroteEof;
353  preview.wrote(chunkSize, wroteEof); // even if wrote nothing
354  lastChunk = lastChunk || preview.done();
355  }
356 
357  if (lastChunk) {
358  debugs(93, 8, HERE << "will write last-chunk of " << label);
359  addLastRequestChunk(writeBuf);
360  }
361 
362  debugs(93, 7, HERE << "will write " << writeBuf.contentSize()
363  << " raw bytes of " << label);
364 
365  if (writeBuf.hasContent()) {
366  scheduleWrite(writeBuf); // comm will free the chunk
367  } else {
368  writeBuf.clean();
369  }
370 }
371 
373 {
374  const bool ieof = state.writing == State::writingPreview && preview.ieof();
375  openChunk(buf, 0, ieof);
376  closeChunk(buf);
377 }
378 
379 void Adaptation::Icap::ModXact::openChunk(MemBuf &buf, size_t chunkSize, bool ieof)
380 {
381  buf.appendf((ieof ? "%x; ieof\r\n" : "%x\r\n"), (int) chunkSize);
382 }
383 
385 {
386  buf.append(ICAP::crlf, 2); // chunk-terminating CRLF
387 }
388 
390 {
391  const HttpRequest *request = virgin.cause ?
392  virgin.cause : dynamic_cast<const HttpRequest*>(virgin.header);
393  Must(request);
394  return *request;
395 }
396 
397 // did the activity reached the end of the virgin body?
399 {
400  return
401  !act.active() || // did all (assuming it was originally planned)
402  !virgin.body_pipe->expectMoreAfter(act.offset()); // will not have more
403 }
404 
405 // the size of buffered virgin body data available for the specified activity
406 // if this size is zero, we may be done or may be waiting for more data
408 {
409  Must(act.active());
410  // asbolute start of unprocessed data
411  const uint64_t dataStart = act.offset();
412  // absolute end of buffered data
413  const uint64_t dataEnd = virginConsumed + virgin.body_pipe->buf().contentSize();
414  Must(virginConsumed <= dataStart && dataStart <= dataEnd);
415  return static_cast<size_t>(dataEnd - dataStart);
416 }
417 
418 // pointer to buffered virgin body data available for the specified activity
420 {
421  Must(act.active());
422  const uint64_t dataStart = act.offset();
423  Must(virginConsumed <= dataStart);
424  return virgin.body_pipe->buf().content() + static_cast<size_t>(dataStart-virginConsumed);
425 }
426 
428 {
429  debugs(93, 9, HERE << "consumption guards: " << !virgin.body_pipe << isRetriable <<
431 
432  if (!virgin.body_pipe)
433  return; // nothing to consume
434 
435  if (isRetriable)
436  return; // do not consume if we may have to retry later
437 
438  BodyPipe &bp = *virgin.body_pipe;
439  const bool wantToPostpone = isRepeatable || canStartBypass || protectGroupBypass;
440 
441  // Why > 2? HttpState does not use the last bytes in the buffer
442  // because delayAwareRead() is arguably broken. See
443  // HttpStateData::maybeReadVirginBody for more details.
444  if (wantToPostpone && bp.buf().spaceSize() > 2) {
445  // Postponing may increase memory footprint and slow the HTTP side
446  // down. Not postponing may increase the number of ICAP errors
447  // if the ICAP service fails. We may also use "potential" space to
448  // postpone more aggressively. Should the trade-off be configurable?
449  debugs(93, 8, HERE << "postponing consumption from " << bp.status());
450  return;
451  }
452 
453  const size_t have = static_cast<size_t>(bp.buf().contentSize());
454  const uint64_t end = virginConsumed + have;
455  uint64_t offset = end;
456 
457  debugs(93, 9, HERE << "max virgin consumption offset=" << offset <<
458  " acts " << virginBodyWriting.active() << virginBodySending.active() <<
459  " consumed=" << virginConsumed <<
460  " from " << virgin.body_pipe->status());
461 
463  offset = min(virginBodyWriting.offset(), offset);
464 
466  offset = min(virginBodySending.offset(), offset);
467 
468  Must(virginConsumed <= offset && offset <= end);
469 
470  if (const size_t size = static_cast<size_t>(offset - virginConsumed)) {
471  debugs(93, 8, HERE << "consuming " << size << " out of " << have <<
472  " virgin body bytes");
473  bp.consume(size);
474  virginConsumed += size;
475  Must(!isRetriable); // or we should not be consuming
476  disableRepeats("consumed content");
477  disableBypass("consumed content", true);
478  }
479 }
480 
482 {
483  writeMore();
484 }
485 
486 // Called when we do not expect to call comm_write anymore.
487 // We may have a pending write though.
488 // If stopping nicely, we will just wait for that pending write, if any.
490 {
492  return;
493 
494  if (writer != NULL) {
495  if (nicely) {
496  debugs(93, 7, HERE << "will wait for the last write" << status());
497  state.writing = State::writingAlmostDone; // may already be set
498  checkConsuming();
499  return;
500  }
501  debugs(93, 3, HERE << "will NOT wait for the last write" << status());
502 
503  // Comm does not have an interface to clear the writer callback nicely,
504  // but without clearing the writer we cannot recycle the connection.
505  // We prevent connection reuse and hope that we can handle a callback
506  // call at any time, usually in the middle of the destruction sequence!
507  // Somebody should add comm_remove_write_handler() to comm API.
508  reuseConnection = false;
509  ignoreLastWrite = true;
510  }
511 
512  debugs(93, 7, HERE << "will no longer write" << status());
513  if (virginBodyWriting.active()) {
515  virginConsume();
516  }
518  checkConsuming();
519 }
520 
522 {
523  if (!virginBodySending.active())
524  return;
525 
526  debugs(93, 7, HERE << "will no longer backup" << status());
528  virginConsume();
529 }
530 
532 {
534  doneSending() &&
536 }
537 
539 {
540  Must(haveConnection());
541  Must(!reader);
542  Must(!adapted.header);
544 
545  // we use the same buffer for headers and body and then consume headers
546  readMore();
547 }
548 
550 {
551  if (reader != NULL || doneReading()) {
552  debugs(93,3,HERE << "returning from readMore because reader or doneReading()");
553  return;
554  }
555 
556  // do not fill readBuf if we have no space to store the result
557  if (adapted.body_pipe != NULL &&
559  debugs(93,3,HERE << "not reading because ICAP reply pipe is full");
560  return;
561  }
562 
563  if (readBuf.length() < SQUID_TCP_SO_RCVBUF)
564  scheduleRead();
565  else
566  debugs(93,3,HERE << "cannot read with a full buffer");
567 }
568 
569 // comm module read a portion of the ICAP response for us
571 {
572  Must(!state.doneParsing());
574  parseMore();
575  readMore();
576 }
577 
579 {
583 
584  const size_t sizeMax = virginContentSize(virginBodySending);
585  debugs(93,5, HERE << "will echo up to " << sizeMax << " bytes from " <<
586  virgin.body_pipe->status());
587  debugs(93,5, HERE << "will echo up to " << sizeMax << " bytes to " <<
589 
590  if (sizeMax > 0) {
592  debugs(93,5, HERE << "echoed " << size << " out of " << sizeMax <<
593  " bytes");
595  disableRepeats("echoed content");
596  disableBypass("echoed content", true);
597  virginConsume();
598  }
599 
601  debugs(93, 5, HERE << "echoed all" << status());
602  stopSending(true);
603  } else {
604  debugs(93, 5, HERE << "has " <<
605  virgin.body_pipe->buf().contentSize() << " bytes " <<
606  "and expects more to echo" << status());
607  // TODO: timeout if virgin or adapted pipes are broken
608  }
609 }
610 
612 {
613  return state.sending == State::sendingDone;
614 }
615 
616 // stop (or do not start) sending adapted message body
618 {
619  debugs(93, 7, HERE << "Enter stop sending ");
620  if (doneSending())
621  return;
622  debugs(93, 7, HERE << "Proceed with stop sending ");
623 
625  debugs(93, 7, HERE << "will no longer send" << status());
626  if (adapted.body_pipe != NULL) {
628  // we may leave debts if we were echoing and the virgin
629  // body_pipe got exhausted before we echoed all planned bytes
630  const bool leftDebts = adapted.body_pipe->needsMoreData();
631  stopProducingFor(adapted.body_pipe, nicely && !leftDebts);
632  }
633  } else {
634  debugs(93, 7, HERE << "will not start sending" << status());
636  }
637 
639  checkConsuming();
640 }
641 
642 // should be called after certain state.writing or state.sending changes
644 {
645  // quit if we already stopped or are still using the pipe
647  return;
648 
649  debugs(93, 7, HERE << "will stop consuming" << status());
651 }
652 
654 {
655  debugs(93, 5, "have " << readBuf.length() << " bytes to parse" << status());
656  debugs(93, 5, "\n" << readBuf);
657 
658  if (state.parsingHeaders())
659  parseHeaders();
660 
661  if (state.parsing == State::psBody)
662  parseBody();
663 
666 }
667 
668 void Adaptation::Icap::ModXact::callException(const std::exception &e)
669 {
670  if (!canStartBypass || isRetriable) {
671  if (!isRetriable) {
672  if (const TextException *te = dynamic_cast<const TextException *>(&e))
674  else
676  }
678  return;
679  }
680 
681  try {
682  debugs(93, 3, HERE << "bypassing " << inCall << " exception: " <<
683  e.what() << ' ' << status());
684  bypassFailure();
685  } catch (const TextException &bypassTe) {
688  } catch (const std::exception &bypassE) {
691  }
692 }
693 
695 {
696  disableBypass("already started to bypass", false);
697 
698  Must(!isRetriable); // or we should not be bypassing
699  // TODO: should the same be enforced for isRepeatable? Check icap_repeat??
700 
701  prepEchoing();
702 
703  startSending();
704 
705  // end all activities associated with the ICAP server
706 
707  stopParsing(false);
708 
709  stopWriting(true); // or should we force it?
710  if (haveConnection()) {
711  reuseConnection = false; // be conservative
712  cancelRead(); // may not work; and we cannot stop connecting either
713  if (!doneWithIo())
714  debugs(93, 7, HERE << "Warning: bypass failed to stop I/O" << status());
715  }
716 
717  service().noteFailure(); // we are bypassing, but this is still a failure
718 }
719 
720 void Adaptation::Icap::ModXact::disableBypass(const char *reason, bool includingGroupBypass)
721 {
722  if (canStartBypass) {
723  debugs(93,7, HERE << "will never start bypass because " << reason);
724  canStartBypass = false;
725  }
726  if (protectGroupBypass && includingGroupBypass) {
727  debugs(93,7, HERE << "not protecting group bypass because " << reason);
728  protectGroupBypass = false;
729  }
730 }
731 
732 // note that allocation for echoing is done in handle204NoContent()
734 {
735  if (adapted.header) // already allocated
736  return;
737 
738  if (gotEncapsulated("res-hdr")) {
742  } else if (gotEncapsulated("req-hdr")) {
743  adapted.setHeader(new HttpRequest(virginRequest().masterXaction));
745  } else
746  throw TexcHere("Neither res-hdr nor req-hdr in maybeAllocateHttpMsg()");
747 }
748 
750 {
752 
754  debugs(93, 5, HERE << "parse ICAP headers");
755  parseIcapHead();
756  }
757 
759  debugs(93, 5, HERE << "parse HTTP headers");
760  parseHttpHead();
761  }
762 
763  if (state.parsingHeaders()) { // need more data
764  Must(mayReadMore());
765  return;
766  }
767 
768  startSending();
769 }
770 
771 // called after parsing all headers or when bypassing an exception
773 {
774  disableRepeats("sent headers");
775  disableBypass("sent headers", true);
777 
779  echoMore();
780  else {
781  // If we are not using the virgin HTTP object update the
782  // Http::Message::sources flag.
783  // The state.sending may set to State::sendingVirgin in the case
784  // of 206 responses too, where we do not want to update Http::Message::sources
785  // flag. However even for 206 responses the state.sending is
786  // not set yet to sendingVirgin. This is done in later step
787  // after the parseBody method called.
788  updateSources();
789  }
790 }
791 
793 {
795 
796  if (!parseHead(icapReply.getRaw()))
797  return;
798 
799  if (expectIcapTrailers()) {
802  }
803 
804  static SBuf close("close", 5);
805  if (httpHeaderHasConnDir(&icapReply->header, close)) {
806  debugs(93, 5, HERE << "found connection close");
807  reuseConnection = false;
808  }
809 
810  switch (icapReply->sline.status()) {
811 
812  case Http::scContinue:
814  break;
815 
816  case Http::scOkay:
817  case Http::scCreated: // Symantec Scan Engine 5.0 and later when modifying HTTP msg
818 
819  if (!validate200Ok()) {
820  throw TexcHere("Invalid ICAP Response");
821  } else {
822  handle200Ok();
823  }
824 
825  break;
826 
827  case Http::scNoContent:
829  break;
830 
833  break;
834 
835  default:
836  debugs(93, 5, "ICAP status " << icapReply->sline.status());
838  break;
839  }
840 
841  const HttpRequest *request = dynamic_cast<HttpRequest*>(adapted.header);
842  if (!request)
843  request = &virginRequest();
844 
845  // update the cross-transactional database if needed (all status codes!)
846  if (const char *xxName = Adaptation::Config::masterx_shared_name) {
847  Adaptation::History::Pointer ah = request->adaptHistory(true);
848  if (ah != NULL) { // TODO: reorder checks to avoid creating history
849  const String val = icapReply->header.getByName(xxName);
850  if (val.size() > 0) // XXX: HttpHeader lacks empty value detection
851  ah->updateXxRecord(xxName, val);
852  }
853  }
854 
855  // update the adaptation plan if needed (all status codes!)
856  if (service().cfg().routing) {
857  String services;
859  Adaptation::History::Pointer ah = request->adaptHistory(true);
860  if (ah != NULL)
861  ah->updateNextServices(services);
862  }
863  } // TODO: else warn (occasionally!) if we got Http::HdrType::X_NEXT_SERVICES
864 
865  // We need to store received ICAP headers for <icapLastHeader logformat option.
866  // If we already have stored headers from previous ICAP transaction related to this
867  // request, old headers will be replaced with the new one.
868 
870  if (ah != NULL)
871  ah->recordMeta(&icapReply->header);
872 
873  // handle100Continue() manages state.writing on its own.
874  // Non-100 status means the server needs no postPreview data from us.
876  stopWriting(true);
877 }
878 
882 
883  if (parsePart(trailerParser, "trailer")) {
884  for (const auto &e: trailerParser->trailer.entries)
885  debugs(93, 5, "ICAP trailer: " << e->name << ": " << e->value);
886  stopParsing();
887  }
888 }
889 
891 {
892  if (service().cfg().method == ICAP::methodRespmod)
893  return gotEncapsulated("res-hdr");
894 
895  return service().cfg().method == ICAP::methodReqmod &&
897 }
898 
900 {
902  // server must not respond before the end of preview: we may send ieof
903  Must(preview.enabled() && preview.done() && !preview.ieof());
904 
905  // 100 "Continue" cancels our Preview commitment,
906  // but not commitment to handle 204 or 206 outside Preview
908  stopBackup();
909 
910  state.parsing = State::psIcapHeader; // eventually
911  icapReply->reset();
912 
914 
915  writeMore();
916 }
917 
919 {
922  stopBackup();
923  checkConsuming();
924 }
925 
927 {
928  stopParsing();
929  prepEchoing();
930 }
931 
933 {
935  Must(preview.enabled());
937  debugs(93, 7, HERE << "206 inside preview");
938  } else {
941  debugs(93, 7, HERE << "206 outside preview");
942  }
945  state.readyForUob = true;
946  checkConsuming();
947 }
948 
949 // Called when we receive a 204 No Content response and
950 // when we are trying to bypass a service failure.
951 // We actually start sending (echoig or not) in startSending.
953 {
954  disableRepeats("preparing to echo content");
955  disableBypass("preparing to echo content", true);
957 
958  // We want to clone the HTTP message, but we do not want
959  // to copy some non-HTTP state parts that Http::Message kids carry in them.
960  // Thus, we cannot use a smart pointer, copy constructor, or equivalent.
961  // Instead, we simply write the HTTP message and "clone" it by parsing.
962  // TODO: use Http::Message::clone()!
963 
964  Http::Message *oldHead = virgin.header;
965  debugs(93, 7, HERE << "cloning virgin message " << oldHead);
966 
967  MemBuf httpBuf;
968 
969  // write the virgin message into a memory buffer
970  httpBuf.init();
971  packHead(httpBuf, oldHead);
972 
973  // allocate the adapted message and copy metainfo
974  Must(!adapted.header);
975  {
976  Http::MessagePointer newHead;
977  if (const HttpRequest *r = dynamic_cast<const HttpRequest*>(oldHead)) {
978  newHead = new HttpRequest(r->masterXaction);
979  } else if (dynamic_cast<const HttpReply*>(oldHead)) {
980  newHead = new HttpReply;
981  }
982  Must(newHead);
983 
984  newHead->inheritProperties(oldHead);
985 
986  adapted.setHeader(newHead.getRaw());
987  }
988 
989  // parse the buffer back
991 
992  httpBuf.terminate(); // Http::Message::parse requires nil-terminated buffer
993  Must(adapted.header->parse(httpBuf.content(), httpBuf.contentSize(), true, &error));
994  Must(adapted.header->hdr_sz == httpBuf.contentSize()); // no leftovers
995 
996  httpBuf.clean();
997 
998  debugs(93, 7, HERE << "cloned virgin message " << oldHead << " to " <<
999  adapted.header);
1000 
1001  // setup adapted body pipe if needed
1002  if (oldHead->body_pipe != NULL) {
1003  debugs(93, 7, HERE << "will echo virgin body from " <<
1004  oldHead->body_pipe);
1005  if (!virginBodySending.active())
1006  virginBodySending.plan(); // will throw if not possible
1008  checkConsuming();
1009 
1010  // TODO: optimize: is it possible to just use the oldHead pipe and
1011  // remove ICAP from the loop? This echoing is probably a common case!
1012  makeAdaptedBodyPipe("echoed virgin response");
1013  if (oldHead->body_pipe->bodySizeKnown())
1015  debugs(93, 7, HERE << "will echo virgin body to " <<
1016  adapted.body_pipe);
1017  } else {
1018  debugs(93, 7, HERE << "no virgin body to echo");
1019  stopSending(true);
1020  }
1021 }
1022 
1026 {
1029 
1031 
1032  debugs(93, 7, HERE << "will echo virgin body suffix from " <<
1033  virgin.header->body_pipe << " offset " << pos );
1034 
1035  // check that use-original-body=N does not point beyond buffered data
1036  const uint64_t virginDataEnd = virginConsumed +
1038  Must(pos <= virginDataEnd);
1039  virginBodySending.progress(static_cast<size_t>(pos));
1040 
1042  checkConsuming();
1043 
1046 
1047  debugs(93, 7, HERE << "will echo virgin body suffix to " <<
1048  adapted.body_pipe);
1049 
1050  // Start echoing data
1051  echoMore();
1052 }
1053 
1055 {
1056  stopParsing(false);
1057  stopBackup();
1058  // TODO: mark connection as "bad"
1059 
1060  // Terminate the transaction; we do not know how to handle this response.
1061  throw TexcHere("Unsupported ICAP status code");
1062 }
1063 
1065 {
1066  if (expectHttpHeader()) {
1067  replyHttpHeaderSize = 0;
1069 
1070  if (!parseHead(adapted.header))
1071  return; // need more header data
1072 
1073  if (adapted.header)
1075 
1076  if (dynamic_cast<HttpRequest*>(adapted.header)) {
1077  const HttpRequest *oldR = dynamic_cast<const HttpRequest*>(virgin.header);
1078  Must(oldR);
1079  // TODO: the adapted request did not really originate from the
1080  // client; give proxy admin an option to prevent copying of
1081  // sensitive client information here. See the following thread:
1082  // http://www.squid-cache.org/mail-archive/squid-dev/200703/0040.html
1083  }
1084 
1085  // Maybe adapted.header==NULL if HttpReply and have Http 0.9 ....
1086  if (adapted.header)
1088  }
1089 
1091 }
1092 
1093 template<class Part>
1094 bool Adaptation::Icap::ModXact::parsePart(Part *part, const char *description)
1095 {
1096  Must(part);
1097  debugs(93, 5, "have " << readBuf.length() << ' ' << description << " bytes to parse; state: " << state.parsing);
1099  // XXX: performance regression. c_str() data copies
1100  // XXX: Http::Message::parse requires a terminated string buffer
1101  const char *tmpBuf = readBuf.c_str();
1102  const bool parsed = part->parse(tmpBuf, readBuf.length(), commEof, &error);
1103  debugs(93, (!parsed && error) ? 2 : 5, description << " parsing result: " << parsed << " detail: " << error);
1104  Must(parsed || !error);
1105  if (parsed)
1106  readBuf.consume(part->hdr_sz);
1107  return parsed;
1108 }
1109 
1110 // parses both HTTP and ICAP headers
1111 bool
1113 {
1114  if (!parsePart(head, "head")) {
1115  head->reset();
1116  return false;
1117  }
1118  return true;
1119 }
1120 
1122 {
1123  return gotEncapsulated("res-hdr") || gotEncapsulated("req-hdr");
1124 }
1125 
1127 {
1128  return gotEncapsulated("res-body") || gotEncapsulated("req-body");
1129 }
1130 
1132 {
1133  String trailers;
1134  const bool promisesToSendTrailer = icapReply->header.getByIdIfPresent(Http::HdrType::TRAILER, &trailers);
1135  const bool supportsTrailers = icapReply->header.hasListMember(Http::HdrType::ALLOW, "trailers", ',');
1136  // ICAP Trailer specs require us to reject transactions having either Trailer
1137  // header or Allow:trailers
1138  Must((promisesToSendTrailer == supportsTrailers) || (!promisesToSendTrailer && supportsTrailers));
1139  if (promisesToSendTrailer && !trailers.size())
1140  debugs(93, DBG_IMPORTANT, "ERROR: ICAP Trailer response header field must not be empty (salvaged)");
1141  return promisesToSendTrailer;
1142 }
1143 
1145 {
1146  if (expectHttpBody()) {
1147  debugs(93, 5, HERE << "expecting a body");
1149  replyHttpBodySize = 0;
1152  makeAdaptedBodyPipe("adapted response from the ICAP server");
1154  } else {
1155  debugs(93, 5, HERE << "not expecting a body");
1156  if (trailerParser)
1158  else
1159  stopParsing();
1160  stopSending(true);
1161  }
1162 }
1163 
1165 {
1167  Must(bodyParser);
1168 
1169  debugs(93, 5, "have " << readBuf.length() << " body bytes to parse");
1170 
1171  // the parser will throw on errors
1173  bodyParser->setPayloadBuffer(&bpc.buf);
1174  const bool parsed = bodyParser->parse(readBuf);
1175  readBuf = bodyParser->remaining(); // sync buffers after parse
1176  bpc.checkIn();
1177 
1178  debugs(93, 5, "have " << readBuf.length() << " body bytes after parsed all: " << parsed);
1180 
1181  // TODO: expose BodyPipe::putSize() to make this check simpler and clearer
1182  // TODO: do we really need this if we disable when sending headers?
1183  if (adapted.body_pipe->buf().contentSize() > 0) { // parsed something sometime
1184  disableRepeats("sent adapted content");
1185  disableBypass("sent adapted content", true);
1186  }
1187 
1188  if (parsed) {
1191  else
1192  stopSending(true); // the parser succeeds only if all parsed data fits
1193  if (trailerParser)
1195  else
1196  stopParsing();
1197  return;
1198  }
1199 
1200  debugs(93,3,HERE << this << " needsMoreData = " << bodyParser->needsMoreData());
1201 
1202  if (bodyParser->needsMoreData()) {
1203  debugs(93,3,HERE << this);
1204  Must(mayReadMore());
1205  readMore();
1206  }
1207 
1208  if (bodyParser->needsMoreSpace()) {
1209  Must(!doneSending()); // can hope for more space
1210  Must(adapted.body_pipe->buf().contentSize() > 0); // paranoid
1211  // TODO: there should be a timeout in case the sink is broken
1212  // or cannot consume partial content (while we need more space)
1213  }
1214 }
1215 
1216 void Adaptation::Icap::ModXact::stopParsing(const bool checkUnparsedData)
1217 {
1218  if (state.parsing == State::psDone)
1219  return;
1220 
1221  if (checkUnparsedData)
1222  Must(readBuf.isEmpty());
1223 
1224  debugs(93, 7, "will no longer parse" << status());
1225 
1226  delete bodyParser;
1227  bodyParser = nullptr;
1228 
1229  delete trailerParser;
1230  trailerParser = nullptr;
1231 
1233 }
1234 
1235 // HTTP side added virgin body data
1237 {
1238  writeMore();
1239 
1241  echoMore();
1242 }
1243 
1244 // HTTP side sent us all virgin info
1246 {
1248 
1249  // push writer and sender in case we were waiting for the last-chunk
1250  writeMore();
1251 
1253  echoMore();
1254 }
1255 
1256 // body producer aborted, but the initiator may still want to know
1257 // the answer, even though the HTTP message has been truncated
1259 {
1261 
1262  // push writer and sender in case we were waiting for the last-chunk
1263  writeMore();
1264 
1266  echoMore();
1267 }
1268 
1269 // adapted body consumer wants more adapted data and
1270 // possibly freed some buffer space
1272 {
1274  echoMore();
1275  else if (state.sending == State::sendingAdapted)
1276  parseMore();
1277  else
1279 }
1280 
1281 // adapted body consumer aborted
1283 {
1285  mustStop("adapted body consumer aborted");
1286 }
1287 
1289 {
1290  delete bodyParser;
1291  delete trailerParser;
1292 }
1293 
1294 // internal cleanup
1296 {
1297  debugs(93, 5, HERE << "swan sings" << status());
1298 
1299  stopWriting(false);
1300  stopSending(false);
1301 
1302  if (theInitiator.set()) // we have not sent the answer to the initiator
1304 
1305  // update adaptation history if start was called and we reserved a slot
1307  if (ah != NULL && adaptHistoryId >= 0)
1309 
1311 }
1312 
1314 
1316 {
1317  HttpRequest *adapted_request_ = nullptr;
1318  HttpReply *adapted_reply_ = nullptr;
1319  HttpRequest *virgin_request_ = const_cast<HttpRequest*>(&virginRequest());
1320  if (!(adapted_request_ = dynamic_cast<HttpRequest*>(adapted.header))) {
1321  // if the request was not adapted, use virgin request to simplify
1322  // the code further below
1323  adapted_request_ = virgin_request_;
1324  adapted_reply_ = dynamic_cast<HttpReply*>(adapted.header);
1325  }
1326 
1327  Adaptation::Icap::History::Pointer h = virgin_request_->icapHistory();
1328  Must(h != NULL); // ICAPXaction::maybeLog calls only if there is a log
1330  al.url = h->log_uri.termedBuf();
1332  al.icap.reqMethod = s.cfg().method;
1333 
1334  al.cache.caddr = virgin_request_->client_addr;
1335 
1336  al.request = virgin_request_;
1338  al.adapted_request = adapted_request_;
1340 
1341  if (adapted_reply_) {
1342  al.reply = adapted_reply_;
1343  HTTPMSGLOCK(al.reply);
1344  } else
1345  al.reply = NULL;
1346 
1347  if (h->rfc931.size())
1348  al.cache.rfc931 = h->rfc931.termedBuf();
1349 
1350 #if USE_OPENSSL
1351  if (h->ssluser.size())
1352  al.cache.ssluser = h->ssluser.termedBuf();
1353 #endif
1354  al.cache.code = h->logType;
1355 
1356  const Http::Message *virgin_msg = dynamic_cast<HttpReply*>(virgin.header);
1357  if (!virgin_msg)
1358  virgin_msg = virgin_request_;
1359  assert(virgin_msg != virgin.cause);
1360  al.http.clientRequestSz.header = virgin_msg->hdr_sz;
1361  if (virgin_msg->body_pipe != NULL)
1363 
1364  // leave al.icap.bodyBytesRead negative if no body
1365  if (replyHttpHeaderSize >= 0 || replyHttpBodySize >= 0) {
1366  const int64_t zero = 0; // to make max() argument types the same
1367  const uint64_t headerSize = max(zero, replyHttpHeaderSize);
1368  const uint64_t bodySize = max(zero, replyHttpBodySize);
1369  al.icap.bodyBytesRead = headerSize + bodySize;
1370  al.http.clientReplySz.header = headerSize;
1371  al.http.clientReplySz.payloadData = bodySize;
1372  }
1373 
1374  if (adapted_reply_) {
1375  al.http.code = adapted_reply_->sline.status();
1376  al.http.content_type = adapted_reply_->content_type.termedBuf();
1377  if (replyHttpBodySize >= 0)
1379  //don't set al.cache.objectSize because it hasn't exist yet
1380 
1381  MemBuf mb;
1382  mb.init();
1383  adapted_reply_->header.packInto(&mb);
1384  al.headers.reply = xstrdup(mb.buf);
1385  mb.clean();
1386  }
1387  prepareLogWithRequestDetails(adapted_request_, alep);
1389 }
1390 
1392 {
1393  char ntoabuf[MAX_IPSTRLEN];
1394  /*
1395  * XXX These should use HttpHdr interfaces instead of Printfs
1396  */
1397  const Adaptation::ServiceConfig &s = service().cfg();
1398  buf.appendf("%s " SQUIDSTRINGPH " ICAP/1.0\r\n", s.methodStr(), SQUIDSTRINGPRINT(s.uri));
1399  buf.appendf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(s.host), s.port);
1400  buf.appendf("Date: %s\r\n", mkrfc1123(squid_curtime));
1401 
1403  buf.appendf("Connection: close\r\n");
1404 
1405  const HttpRequest *request = &virginRequest();
1406 
1407  // we must forward "Proxy-Authenticate" and "Proxy-Authorization"
1408  // as ICAP headers.
1411  buf.appendf("Proxy-Authenticate: " SQUIDSTRINGPH "\r\n",SQUIDSTRINGPRINT(vh));
1412  }
1413 
1416  buf.appendf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(vh));
1417  } else if (request->extacl_user.size() > 0 && request->extacl_passwd.size() > 0) {
1418  struct base64_encode_ctx ctx;
1419  base64_encode_init(&ctx);
1420  char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
1421  size_t resultLen = base64_encode_update(&ctx, base64buf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
1422  resultLen += base64_encode_update(&ctx, base64buf+resultLen, 1, reinterpret_cast<const uint8_t*>(":"));
1423  resultLen += base64_encode_update(&ctx, base64buf+resultLen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
1424  resultLen += base64_encode_final(&ctx, base64buf+resultLen);
1425  buf.appendf("Proxy-Authorization: Basic %.*s\r\n", (int)resultLen, base64buf);
1426  }
1427 
1428  // share the cross-transactional database records if needed
1430  Adaptation::History::Pointer ah = request->adaptHistory(false);
1431  if (ah != NULL) {
1432  String name, value;
1433  if (ah->getXxRecord(name, value)) {
1434  buf.appendf(SQUIDSTRINGPH ": " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(name), SQUIDSTRINGPRINT(value));
1435  }
1436  }
1437  }
1438 
1439  buf.append("Encapsulated: ", 14);
1440 
1441  MemBuf httpBuf;
1442 
1443  httpBuf.init();
1444 
1445  // build HTTP request header, if any
1446  ICAP::Method m = s.method;
1447 
1448  // to simplify, we could assume that request is always available
1449 
1450  if (request) {
1451  if (ICAP::methodRespmod == m)
1452  encapsulateHead(buf, "req-hdr", httpBuf, request);
1453  else if (ICAP::methodReqmod == m)
1454  encapsulateHead(buf, "req-hdr", httpBuf, virgin.header);
1455  }
1456 
1457  if (ICAP::methodRespmod == m)
1458  if (const Http::Message *prime = virgin.header)
1459  encapsulateHead(buf, "res-hdr", httpBuf, prime);
1460 
1461  if (!virginBody.expected())
1462  buf.appendf("null-body=%d", (int) httpBuf.contentSize());
1463  else if (ICAP::methodReqmod == m)
1464  buf.appendf("req-body=%d", (int) httpBuf.contentSize());
1465  else
1466  buf.appendf("res-body=%d", (int) httpBuf.contentSize());
1467 
1468  buf.append(ICAP::crlf, 2); // terminate Encapsulated line
1469 
1470  if (preview.enabled()) {
1471  buf.appendf("Preview: %d\r\n", (int)preview.ad());
1472  if (!virginBody.expected()) // there is no body to preview
1474  }
1475 
1476  makeAllowHeader(buf);
1477 
1478  if (TheConfig.send_client_ip && request) {
1479  Ip::Address client_addr;
1480 #if FOLLOW_X_FORWARDED_FOR
1482  client_addr = request->indirect_client_addr;
1483  } else
1484 #endif
1485  client_addr = request->client_addr;
1486  if (!client_addr.isAnyAddr() && !client_addr.isNoAddr())
1487  buf.appendf("X-Client-IP: %s\r\n", client_addr.toStr(ntoabuf,MAX_IPSTRLEN));
1488  }
1489 
1490  if (TheConfig.send_username && request)
1491  makeUsernameHeader(request, buf);
1492 
1493  // Adaptation::Config::metaHeaders
1494  for (auto h: Adaptation::Config::metaHeaders) {
1495  HttpRequest *r = virgin.cause ?
1496  virgin.cause : dynamic_cast<HttpRequest*>(virgin.header);
1497  Must(r);
1498 
1499  HttpReply *reply = dynamic_cast<HttpReply*>(virgin.header);
1500 
1501  SBuf matched;
1502  if (h->match(r, reply, alMaster, matched)) {
1503  buf.append(h->key().rawContent(), h->key().length());
1504  buf.append(": ", 2);
1505  buf.append(matched.rawContent(), matched.length());
1506  buf.append("\r\n", 2);
1507  Adaptation::History::Pointer ah = request->adaptHistory(false);
1508  if (ah != NULL) {
1509  if (ah->metaHeaders == NULL)
1510  ah->metaHeaders = new NotePairs;
1511  if (!ah->metaHeaders->hasPair(h->key(), matched))
1512  ah->metaHeaders->add(h->key(), matched);
1513  }
1514  }
1515  }
1516 
1517  // fprintf(stderr, "%s\n", buf.content());
1518 
1519  buf.append(ICAP::crlf, 2); // terminate ICAP header
1520 
1521  // fill icapRequest for logging
1523 
1524  // start ICAP request body with encapsulated HTTP headers
1525  buf.append(httpBuf.content(), httpBuf.contentSize());
1526 
1527  httpBuf.clean();
1528 }
1529 
1530 // decides which Allow values to write and updates the request buffer
1532 {
1533  const bool allow204in = preview.enabled(); // TODO: add shouldAllow204in()
1534  const bool allow204out = state.allowedPostview204 = shouldAllow204();
1535  const bool allow206in = state.allowedPreview206 = shouldAllow206in();
1536  const bool allow206out = state.allowedPostview206 = shouldAllow206out();
1537  const bool allowTrailers = true; // TODO: make configurable
1538 
1539  debugs(93, 9, "Allows: " << allow204in << allow204out <<
1540  allow206in << allow206out << allowTrailers);
1541 
1542  const bool allow204 = allow204in || allow204out;
1543  const bool allow206 = allow206in || allow206out;
1544 
1545  if (!allow204 && !allow206 && !allowTrailers)
1546  return; // nothing to do
1547 
1548  if (virginBody.expected()) // if there is a virgin body, plan to send it
1550 
1551  // writing Preview:... means we will honor 204 inside preview
1552  // writing Allow/204 means we will honor 204 outside preview
1553  // writing Allow:206 means we will honor 206 inside preview
1554  // writing Allow:204,206 means we will honor 206 outside preview
1555  if (allow204 || allow206 || allowTrailers) {
1556  buf.appendf("Allow: ");
1557  if (allow204out)
1558  buf.appendf("204, ");
1559  if (allow206)
1560  buf.appendf("206, ");
1561  if (allowTrailers)
1562  buf.appendf("trailers");
1563  buf.appendf("\r\n");
1564  }
1565 }
1566 
1568 {
1569 #if USE_AUTH
1570  struct base64_encode_ctx ctx;
1571  base64_encode_init(&ctx);
1572 
1573  const char *value = NULL;
1574  if (request->auth_user_request != NULL) {
1575  value = request->auth_user_request->username();
1576  } else if (request->extacl_user.size() > 0) {
1577  value = request->extacl_user.termedBuf();
1578  }
1579 
1580  if (value) {
1582  char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
1583  size_t resultLen = base64_encode_update(&ctx, base64buf, strlen(value), reinterpret_cast<const uint8_t*>(value));
1584  resultLen += base64_encode_final(&ctx, base64buf+resultLen);
1585  buf.appendf("%s: %.*s\r\n", TheConfig.client_username_header, (int)resultLen, base64buf);
1586  } else
1587  buf.appendf("%s: %s\r\n", TheConfig.client_username_header, value);
1588  }
1589 #endif
1590 }
1591 
1592 void
1593 Adaptation::Icap::ModXact::encapsulateHead(MemBuf &icapBuf, const char *section, MemBuf &httpBuf, const Http::Message *head)
1594 {
1595  // update ICAP header
1596  icapBuf.appendf("%s=%d, ", section, (int) httpBuf.contentSize());
1597 
1598  // begin cloning
1599  Http::MessagePointer headClone;
1600 
1601  if (const HttpRequest* old_request = dynamic_cast<const HttpRequest*>(head)) {
1602  HttpRequest::Pointer new_request(new HttpRequest(old_request->masterXaction));
1603  // copy the request-line details
1604  new_request->method = old_request->method;
1605  new_request->url = old_request->url;
1606  new_request->http_ver = old_request->http_ver;
1607  headClone = new_request.getRaw();
1608  } else if (const HttpReply *old_reply = dynamic_cast<const HttpReply*>(head)) {
1609  HttpReply::Pointer new_reply(new HttpReply);
1610  new_reply->sline = old_reply->sline;
1611  headClone = new_reply.getRaw();
1612  }
1613  Must(headClone);
1614  headClone->inheritProperties(head);
1615 
1617  while (HttpHeaderEntry* p_head_entry = head->header.getEntry(&pos))
1618  headClone->header.addEntry(p_head_entry->clone());
1619 
1620  // end cloning
1621 
1622  // remove all hop-by-hop headers from the clone
1624  headClone->header.removeHopByHopEntries();
1625 
1626  // pack polished HTTP header
1627  packHead(httpBuf, headClone.getRaw());
1628 
1629  // headClone unlocks and, hence, deletes the message we packed
1630 }
1631 
1632 void
1634 {
1635  head->packInto(&httpBuf, true);
1636 }
1637 
1638 // decides whether to offer a preview and calculates its size
1640 {
1641  if (!TheConfig.preview_enable) {
1642  debugs(93, 5, HERE << "preview disabled by squid.conf");
1643  return;
1644  }
1645 
1646  const SBuf urlPath(virginRequest().url.path());
1647  size_t wantedSize;
1648  if (!service().wantsPreview(urlPath, wantedSize)) {
1649  debugs(93, 5, "should not offer preview for " << urlPath);
1650  return;
1651  }
1652 
1653  // we decided to do preview, now compute its size
1654 
1655  // cannot preview more than we can backup
1656  size_t ad = min(wantedSize, TheBackupLimit);
1657 
1658  if (!virginBody.expected())
1659  ad = 0;
1660  else if (virginBody.knownSize())
1661  ad = min(static_cast<uint64_t>(ad), virginBody.size()); // not more than we have
1662 
1663  debugs(93, 5, HERE << "should offer " << ad << "-byte preview " <<
1664  "(service wanted " << wantedSize << ")");
1665 
1666  preview.enable(ad);
1667  Must(preview.enabled());
1668 }
1669 
1670 // decides whether to allow 204 responses
1672 {
1673  if (!service().allows204())
1674  return false;
1675 
1676  return canBackupEverything();
1677 }
1678 
1679 // decides whether to allow 206 responses in some mode
1681 {
1682  return TheConfig.allow206_enable && service().allows206() &&
1683  virginBody.expected(); // no need for 206 without a body
1684 }
1685 
1686 // decides whether to allow 206 responses in preview mode
1688 {
1689  return shouldAllow206any() && preview.enabled();
1690 }
1691 
1692 // decides whether to allow 206 responses outside of preview
1694 {
1695  return shouldAllow206any() && canBackupEverything();
1696 }
1697 
1698 // used by shouldAllow204 and decideOnRetries
1700 {
1701  if (!virginBody.expected())
1702  return true; // no body means no problems with backup
1703 
1704  // if there is a body, check whether we can backup it all
1705 
1706  if (!virginBody.knownSize())
1707  return false;
1708 
1709  // or should we have a different backup limit?
1710  // note that '<' allows for 0-termination of the "full" backup buffer
1711  return virginBody.size() < TheBackupLimit;
1712 }
1713 
1714 // Decide whether this transaction can be retried if pconn fails
1715 // Must be called after decideOnPreview and before openConnection()
1717 {
1718  if (!isRetriable)
1719  return; // no, already decided
1720 
1721  if (preview.enabled())
1722  return; // yes, because preview provides enough guarantees
1723 
1724  if (canBackupEverything())
1725  return; // yes, because we can back everything up
1726 
1727  disableRetries(); // no, because we cannot back everything up
1728 }
1729 
1730 // Normally, the body-writing code handles preview body. It can deal with
1731 // bodies of unexpected size, including those that turn out to be empty.
1732 // However, that code assumes that the body was expected and body control
1733 // structures were initialized. This is not the case when there is no body
1734 // or the body is known to be empty, because the virgin message will lack a
1735 // body_pipe. So we handle preview of null-body and zero-size bodies here.
1737 {
1738  Must(!virginBodyWriting.active()); // one reason we handle it here
1739  Must(!virgin.body_pipe); // another reason we handle it here
1740  Must(!preview.ad());
1741 
1742  // do not add last-chunk because our Encapsulated header says null-body
1743  // addLastRequestChunk(buf);
1744  preview.wrote(0, true);
1745 
1746  Must(preview.done());
1747  Must(preview.ieof());
1748 }
1749 
1751 {
1753 
1754  if (state.serviceWaiting)
1755  buf.append("U", 1);
1756 
1757  if (virgin.body_pipe != NULL)
1758  buf.append("R", 1);
1759 
1760  if (haveConnection() && !doneReading())
1761  buf.append("r", 1);
1762 
1764  buf.appendf("w(%d)", state.writing);
1765 
1766  if (preview.enabled()) {
1767  if (!preview.done())
1768  buf.appendf("P(%d)", (int) preview.debt());
1769  }
1770 
1771  if (virginBodySending.active())
1772  buf.append("B", 1);
1773 
1775  buf.appendf("p(%d)", state.parsing);
1776 
1778  buf.appendf("S(%d)", state.sending);
1779 
1780  if (state.readyForUob)
1781  buf.append("6", 1);
1782 
1783  if (canStartBypass)
1784  buf.append("Y", 1);
1785 
1786  if (protectGroupBypass)
1787  buf.append("G", 1);
1788 }
1789 
1791 {
1793 
1794  if (!virgin.body_pipe)
1795  buf.append("R", 1);
1796 
1797  if (state.doneWriting())
1798  buf.append("w", 1);
1799 
1800  if (preview.enabled()) {
1801  if (preview.done())
1802  buf.appendf("P%s", preview.ieof() ? "(ieof)" : "");
1803  }
1804 
1805  if (doneReading())
1806  buf.append("r", 1);
1807 
1808  if (state.doneParsing())
1809  buf.append("p", 1);
1810 
1811  if (doneSending())
1812  buf.append("S", 1);
1813 }
1814 
1815 bool Adaptation::Icap::ModXact::gotEncapsulated(const char *section) const
1816 {
1817  return !icapReply->header.getByNameListMember("Encapsulated",
1818  section, ',').isEmpty();
1819 }
1820 
1821 // calculate whether there is a virgin HTTP body and
1822 // whether its expected size is known
1823 // TODO: rename because we do not just estimate
1825 {
1826  // note: lack of size info may disable previews and 204s
1827 
1828  Http::Message *msg = virgin.header;
1829  Must(msg);
1830 
1832 
1833  if (virgin.cause)
1834  method = virgin.cause->method;
1835  else if (HttpRequest *req = dynamic_cast<HttpRequest*>(msg))
1836  method = req->method;
1837  else
1838  method = Http::METHOD_NONE;
1839 
1840  int64_t size;
1841  // expectingBody returns true for zero-sized bodies, but we will not
1842  // get a pipe for that body, so we treat the message as bodyless
1843  if (method != Http::METHOD_NONE && msg->expectingBody(method, size) && size) {
1844  debugs(93, 6, HERE << "expects virgin body from " <<
1845  virgin.body_pipe << "; size: " << size);
1846 
1847  virginBody.expect(size);
1849 
1850  // sign up as a body consumer
1851  Must(msg->body_pipe != NULL);
1852  Must(msg->body_pipe == virgin.body_pipe);
1854 
1855  // make sure TheBackupLimit is in-sync with the buffer size
1856  Must(TheBackupLimit <= static_cast<size_t>(msg->body_pipe->buf().max_capacity));
1857  } else {
1858  debugs(93, 6, HERE << "does not expect virgin body");
1859  Must(msg->body_pipe == NULL);
1860  checkConsuming();
1861  }
1862 }
1863 
1865 {
1868  adapted.header->body_pipe = new BodyPipe(this);
1870  debugs(93, 7, HERE << "will supply " << what << " via " <<
1871  adapted.body_pipe << " pipe");
1872 }
1873 
1874 // TODO: Move SizedEstimate and Preview elsewhere
1875 
1877  : theData(dtUnexpected)
1878 {}
1879 
1881 {
1882  theData = (aSize >= 0) ? aSize : (int64_t)dtUnknown;
1883 }
1884 
1886 {
1887  return theData != dtUnexpected;
1888 }
1889 
1891 {
1892  Must(expected());
1893  return theData != dtUnknown;
1894 }
1895 
1897 {
1898  Must(knownSize());
1899  return static_cast<uint64_t>(theData);
1900 }
1901 
1902 Adaptation::Icap::VirginBodyAct::VirginBodyAct(): theStart(0), theState(stUndecided)
1903 {}
1904 
1906 {
1907  Must(!disabled());
1908  Must(!theStart); // not started
1909  theState = stActive;
1910 }
1911 
1913 {
1914  theState = stDisabled;
1915 }
1916 
1918 {
1919  Must(active());
1920 #if SIZEOF_SIZE_T > 4
1921  /* always true for smaller size_t's */
1922  Must(static_cast<int64_t>(size) >= 0);
1923 #endif
1924  theStart += static_cast<int64_t>(size);
1925 }
1926 
1928 {
1929  Must(active());
1930  return static_cast<uint64_t>(theStart);
1931 }
1932 
1934 {}
1935 
1937 {
1938  // TODO: check for anAd not exceeding preview size limit
1939  Must(!enabled());
1940  theAd = anAd;
1941  theState = stWriting;
1942 }
1943 
1945 {
1946  return theState != stDisabled;
1947 }
1948 
1950 {
1951  Must(enabled());
1952  return theAd;
1953 }
1954 
1956 {
1957  Must(enabled());
1958  return theState >= stIeof;
1959 }
1960 
1962 {
1963  Must(enabled());
1964  return theState == stIeof;
1965 }
1966 
1968 {
1969  Must(enabled());
1970  return done() ? 0 : (theAd - theWritten);
1971 }
1972 
1973 void Adaptation::Icap::Preview::wrote(size_t size, bool wroteEof)
1974 {
1975  Must(enabled());
1976 
1977  theWritten += size;
1978 
1979  Must(theWritten <= theAd);
1980 
1981  if (wroteEof)
1982  theState = stIeof; // written size is irrelevant
1983  else if (theWritten >= theAd)
1984  theState = stDone;
1985 }
1986 
1988 {
1989  if (virgin.header == NULL)
1990  return false;
1991 
1992  virgin.header->firstLineBuf(mb);
1993 
1994  return true;
1995 }
1996 
1998 {
1999  HttpRequest *request = dynamic_cast<HttpRequest*>(adapted.header);
2000  // if no adapted request, update virgin (and inherit its properties later)
2001  // TODO: make this and HttpRequest::detailError constant, like adaptHistory
2002  if (!request)
2003  request = const_cast<HttpRequest*>(&virginRequest());
2004 
2005  if (request)
2006  request->detailError(ERR_ICAP_FAILURE, errDetail);
2007 }
2008 
2010 {
2011  HttpRequest *request = dynamic_cast<HttpRequest*>(adapted.header);
2012  // if no adapted request, update virgin (and inherit its properties later)
2013  if (!request)
2014  request = const_cast<HttpRequest*>(&virginRequest());
2015 
2016  if (request)
2017  request->clearError();
2018 }
2019 
2021 {
2022  Must(adapted.header);
2023  adapted.header->sources |= (service().cfg().connectionEncryption ? Http::Message::srcIcaps : Http::Message::srcIcap);
2024 }
2025 
2026 /* Adaptation::Icap::ModXactLauncher */
2027 
2029  AsyncJob("Adaptation::Icap::ModXactLauncher"),
2030  Adaptation::Icap::Launcher("Adaptation::Icap::ModXactLauncher", aService),
2031  al(alp)
2032 {
2033  virgin.setHeader(virginHeader);
2034  virgin.setCause(virginCause);
2035  updateHistory(true);
2036 }
2037 
2039 {
2042  Must(s != NULL);
2044 }
2045 
2047 {
2048  debugs(93, 5, HERE << "swan sings");
2049  updateHistory(false);
2051 }
2052 
2054 {
2055  HttpRequest *r = virgin.cause ?
2056  virgin.cause : dynamic_cast<HttpRequest*>(virgin.header);
2057 
2058  // r should never be NULL but we play safe; TODO: add Should()
2059  if (r) {
2061  if (h != NULL) {
2062  if (doStart)
2063  h->start("ICAPModXactLauncher");
2064  else
2065  h->stop("ICAPModXactLauncher");
2066  }
2067  }
2068 }
2069 
2072  // RFC 7230 section 4.1.2: MUST NOT generate a trailer that contains
2073  // a field necessary for message framing (e.g., Transfer-Encoding and Content-Length)
2074  clen.applyTrailerRules();
2075  const int parsed = trailer.parse(buf, len, atEnd, hdr_sz, clen);
2076  if (parsed < 0)
2077  *error = Http::scInvalidHeader; // TODO: should we add a new Http::scInvalidTrailer?
2078  return parsed > 0;
2079 }
2080 
2081 void
2083 {
2084  if (extName == UseOriginalBodyName) {
2085  useOriginalBody_ = tok.udec64("use-original-body");
2086  assert(useOriginalBody_ >= 0);
2087  } else {
2088  Ignore(tok, extName);
2089  }
2090 }
2091 
void updateSources()
Update the Http::Message sources.
Definition: ModXact.cc:2020
int hasListMember(Http::HdrType id, const char *member, const char separator) const
Definition: HttpHeader.cc:1640
#define MAX_LOGIN_SZ
Definition: defines.h:119
virtual void noteBodyProducerAborted(BodyPipe::Pointer)
Definition: ModXact.cc:1258
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
int delById(Http::HdrType id)
Definition: HttpHeader.cc:681
void makeAllowHeader(MemBuf &buf)
Definition: ModXact.cc:1531
char const * rawBuf() const
Definition: SquidString.h:85
bool isRepeatable
can repeat if no or unsatisfactory response
Definition: Xaction.h:137
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
const char * status() const
Definition: BodyPipe.cc:445
void makeAdaptedBodyPipe(const char *what)
Definition: ModXact.cc:1864
const MemBuf & buf() const
Definition: BodyPipe.h:137
#define SQUIDSTRINGPH
Definition: SquidString.h:21
VirginBodyAct virginBodySending
Definition: ModXact.h:298
void expectProductionEndAfter(uint64_t extraSize)
sets or checks body size
Definition: BodyPipe.cc:184
#define assert(EX)
Definition: assert.h:17
CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, ModXact)
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:22
class AccessLogEntry::IcapLogEntry icap
void encapsulateHead(MemBuf &icapBuf, const char *section, MemBuf &httpBuf, const Http::Message *head)
Definition: ModXact.cc:1593
bool isRetriable
can retry on persistent connection failures
Definition: Xaction.h:136
#define HttpHeaderInitPos
Definition: HttpHeader.h:48
AsyncCall::Pointer reader
Definition: Xaction.h:144
bool hasPair(const SBuf &key, const SBuf &value) const
Definition: Notes.cc:333
const SBuf & remaining() const
the remaining unprocessed section of buffer
Definition: Parser.h:98
const char * mkrfc1123(time_t)
Definition: rfc1123.c:202
static int use_indirect_client
Definition: Config.h:49
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
static Answer Forward(Http::Message *aMsg)
create an akForward answer
Definition: Answer.cc:26
void recordXactFinish(int hid)
record the end of a xact identified by its history ID
Definition: History.cc:60
virtual void start()
called by AsyncStart; do not call directly
Definition: Xaction.cc:143
size_t debt() const
Definition: ModXact.cc:1967
std::vector< HttpHeaderEntry *, PoolingAllocator< HttpHeaderEntry * > > entries
Definition: HttpHeader.h:160
int hdr_sz
Definition: Message.h:82
bool canBackupEverything() const
Definition: ModXact.cc:1699
virtual void finalizeLogInfo()
Definition: ModXact.cc:1315
Parses and stores ICAP trailer header block.
Definition: ModXact.h:110
void wrote(size_t size, bool wroteEof)
Definition: ModXact.cc:1973
AsyncCall::Pointer writer
Definition: Xaction.h:145
void mustStop(const char *aReason)
Definition: AsyncJob.cc:69
Definition: SBuf.h:86
String getByName(const SBuf &name) const
Definition: HttpHeader.cc:888
AsyncCall::Pointer inCall
the asynchronous call being handled, if any
Definition: AsyncJob.h:71
bool isNoAddr() const
Definition: Address.cc:284
HttpReply::Pointer icapReply
received ICAP reply, if any
Definition: Xaction.h:58
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:828
HttpRequestMethod method
Definition: HttpRequest.h:114
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:280
void error(char *format,...)
#define xstrdup
void removeHopByHopEntries()
Definition: HttpHeader.cc:1688
void decideWritingAfterPreview(const char *previewKind)
determine state.writing after we wrote the entire preview
Definition: ModXact.cc:295
char * client_username_header
Definition: Config.h:36
void recordMeta(const HttpHeader *lm)
store the last meta header fields received from the adaptation service
Definition: History.cc:139
Config TheConfig
Definition: Config.cc:19
Adaptation::History::Pointer adaptLogHistory() const
Returns possibly nil history, creating it if adapt. logging is enabled.
Definition: HttpRequest.cc:426
MessageSizes clientReplySz
counters for the response sent to client
Adaptation::History::Pointer adaptHistory(bool createIfNone=false) const
Returns possibly nil history, creating it if requested.
Definition: HttpRequest.cc:415
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:160
bool bodySizeKnown() const
Definition: BodyPipe.h:109
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
bool isEmpty() const
Definition: SBuf.h:420
virtual void reset()=0
virtual void noteBodyProductionEnded(BodyPipe::Pointer)
Definition: ModXact.cc:1245
AnyP::ProtocolVersion http_ver
Definition: Message.h:73
HttpHeaderEntry * getEntry(HttpHeaderPos *pos) const
Definition: HttpHeader.cc:598
static int send_username
Definition: Config.h:48
bool expectMoreAfter(uint64_t offset) const
Definition: BodyPipe.cc:167
void setBodySize(uint64_t aSize)
Definition: BodyPipe.cc:147
String protoPrefix
Definition: HttpReply.h:64
const char * methodStr() const
void callWhenAvailable(AsyncCall::Pointer &cb, bool priority=false)
Definition: ServiceRep.cc:413
struct timeval current_time
Definition: stub_time.cc:15
static Notes metaHeaders
The list of configured meta headers.
Definition: Config.h:58
A const & max(A const &lhs, A const &rhs)
virtual const char * status() const
internal cleanup; do not call directly
Definition: Xaction.cc:663
time_t squid_curtime
Definition: stub_time.cc:17
virtual void parse(Tokenizer &tok, const SBuf &extName) override
Definition: ModXact.cc:2082
size_t putMoreData(const char *buf, size_t size)
Definition: BodyPipe.cc:213
traditional ICAP service without encryption
Definition: Message.h:41
void applyTrailerRules()
prohibits Content-Length in GET/HEAD requests
NotePairs::Pointer metaHeaders
Definition: History.h:65
virtual void fillDoneStatus(MemBuf &buf) const
Definition: ModXact.cc:1790
void enable(size_t anAd)
Definition: ModXact.cc:1936
void expect(int64_t aSize)
Definition: ModXact.cc:1880
size_t virginContentSize(const VirginBodyAct &act) const
Definition: ModXact.cc:407
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
bool httpHeaderHasConnDir(const HttpHeader *hdr, const SBuf &directive)
const HttpRequest & virginRequest() const
locates the request, either as a cause or as a virgin message itself
Definition: ModXact.cc:389
SourceLocationId id() const
same-location exceptions have the same ID
Definition: TextException.h:39
char const * username() const
Definition: UserRequest.cc:32
virtual void fillDoneStatus(MemBuf &buf) const
Definition: Xaction.cc:692
virtual void callException(const std::exception &e)
called when the job throws during an async call
Definition: Xaction.cc:401
HttpRequest * adapted_request
ServiceRep & service()
Definition: Xaction.cc:123
enum Adaptation::Icap::Preview::State theState
virtual void swanSong()
Definition: Xaction.cc:598
void writeSomeBody(const char *label, size_t size)
Definition: ModXact.cc:322
void callWhenReady(AsyncCall::Pointer &cb)
Definition: ServiceRep.cc:431
VirginBodyAct virginBodyWriting
Definition: ModXact.h:297
uint64_t producedSize() const
Definition: BodyPipe.h:112
virtual void swanSong()
Definition: Launcher.cc:105
StatusCode
Definition: StatusCode.h:20
String getById(Http::HdrType id) const
Definition: HttpHeader.cc:897
String extacl_passwd
Definition: HttpRequest.h:181
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
bool expectIcapTrailers() const
whether ICAP response header indicates ICAP trailers presence
Definition: ModXact.cc:1131
HttpReply * reply
#define true
Definition: GnuRegex.c:234
#define DBG_IMPORTANT
Definition: Debug.h:46
HttpRequest * cause
Definition: InOut.h:60
bool getXxRecord(String &name, String &value) const
returns true and fills the record fields iff there is a db record
Definition: History.cc:110
const XactOutcome xoSatisfied
request satisfaction
Definition: Elements.cc:26
virtual bool inheritProperties(const Http::Message *)=0
int attempts
the number of times we tried to get to the service, including this time
Definition: Xaction.h:61
String content_type
Definition: HttpReply.h:50
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void const char int sz
Definition: stub_cbdata.cc:16
const char * virginContentData(const VirginBodyAct &act) const
Definition: ModXact.cc:419
bool needsMoreData() const
Definition: Parser.h:66
ModXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, Adaptation::ServicePointer s)
Definition: ModXact.cc:2028
void parseExtensionValuesWith(ChunkExtensionValueParser *parser)
Ip::Address client_addr
Definition: HttpRequest.h:149
bool virginBodyEndReached(const VirginBodyAct &act) const
Definition: ModXact.cc:398
const XactOutcome xoModified
replaced virgin msg with adapted
Definition: Elements.cc:25
void closeChunk(MemBuf &buf)
Definition: ModXact.cc:384
virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer)
Definition: ModXact.cc:1236
SBuf getByNameListMember(const char *name, const char *member, const char separator) const
Definition: HttpHeader.cc:957
ModXact(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, ServiceRep::Pointer &s)
Definition: ModXact.cc:54
enum Adaptation::Icap::ModXact::State::Writing writing
common parts of HttpRequest and HttpReply
Definition: Message.h:25
virtual Xaction * createXaction()
Definition: ModXact.cc:2038
bool mayReadMore() const
Definition: Xaction.cc:543
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
virtual void swanSong()
Definition: ModXact.cc:1295
void progress(size_t size)
Definition: ModXact.cc:1917
class AccessLogEntry::Headers headers
HttpRequest * request
uint64_t header
Definition: MessageSizes.h:21
void disableBypass(const char *reason, bool includeGroupBypass)
Definition: ModXact.cc:720
void base64_encode_init(struct base64_encode_ctx *ctx)
Definition: base64.c:232
bool parsePart(Part *part, const char *description)
Definition: ModXact.cc:1094
bool setConsumerIfNotLate(const Consumer::Pointer &aConsumer)
Definition: BodyPipe.cc:228
const char * c_str()
Definition: SBuf.cc:526
bool parse(const char *buf, int len, int atEnd, Http::StatusCode *error)
Definition: ModXact.cc:2070
bool haveConnection() const
Definition: Xaction.cc:566
virtual void handleCommConnected()
Definition: ModXact.cc:190
class AccessLogEntry::IcpDetails icp
const XactOutcome xoEcho
preserved virgin message (ICAP 204)
Definition: Elements.cc:23
virtual bool doneAll() const
whether positive goal has been reached
Definition: ModXact.cc:531
Http::StatusLine sline
Definition: HttpReply.h:60
class AccessLogEntry::HttpDetails http
Definition: parse.c:160
static const size_t TheBackupLimit
Definition: ModXact.cc:45
void stopParsing(const bool checkUnparsedData=true)
Definition: ModXact.cc:1216
int adaptHistoryId
adaptation history slot reservation
Definition: ModXact.h:318
SizedEstimate virginBody
Definition: ModXact.h:296
SBuf consume(size_type n=npos)
Definition: SBuf.cc:491
CbcPointer< Initiator > theInitiator
Definition: Initiate.h:51
bool isAnyAddr() const
Definition: Address.cc:170
void updateHistory(bool start)
starts or stops transaction accounting in ICAP history
Definition: ModXact.cc:2053
void clearError()
clear error details, useful for retries/repeats
Definition: HttpRequest.cc:490
char const * termedBuf() const
Definition: SquidString.h:91
virtual void detailError(int errDetail)
record error detail in the virgin request if possible
Definition: ModXact.cc:1997
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
virtual void clearError()
clear stored error details, if any; used for retries/repeats
Definition: ModXact.cc:2009
enum Adaptation::Icap::ModXact::State::Parsing parsing
int recordXactStart(const String &serviceId, const timeval &when, bool retrying)
record the start of a xact, return xact history ID
Definition: History.cc:50
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
class AccessLogEntry::CacheDetails cache
ssize_t HttpHeaderPos
Definition: HttpHeader.h:45
class Adaptation::Icap::ModXact::State state
void disableRepeats(const char *reason)
Definition: Xaction.cc:136
void packInto(Packable *, bool full_uri) const
produce a message copy, except for a few connection-specific settings
Definition: Message.cc:278
void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &)
Definition: client_side.cc:324
an std::runtime_error with thrower location info
Definition: TextException.h:19
static int send_client_ip
Definition: Config.h:47
HttpHeader header
Definition: Message.h:75
virtual bool parse(const SBuf &)
void clean()
Definition: MemBuf.cc:113
virtual bool doneAll() const
whether positive goal has been reached
Definition: Xaction.cc:417
size_t base64_encode_final(struct base64_encode_ctx *ctx, char *dst)
Definition: base64.c:308
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)
Definition: ModXact.cc:1282
bool parseHead(Http::Message *head)
Definition: ModXact.cc:1112
virtual bool doneReading() const
Definition: ModXact.h:206
const CharacterSet crlf("crlf","\")
Definition: Elements.cc:12
char * buf
Definition: MemBuf.h:134
void sendAnswer(const Answer &answer)
Definition: Initiate.cc:79
int has(Http::HdrType id) const
Definition: HttpHeader.cc:977
mb_size_t spaceSize() const
Definition: MemBuf.cc:158
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
AccessLogEntry::Pointer al
Definition: ModXact.h:394
mb_size_t max_capacity
Definition: MemBuf.h:142
void stopProducingFor(RefCount< BodyPipe > &, bool atEof)
Definition: BodyPipe.cc:107
void finishNullOrEmptyBodyPreview(MemBuf &buf)
Definition: ModXact.cc:1736
void scheduleWrite(MemBuf &buf)
Definition: Xaction.cc:331
void detailError(err_type aType, int aDetail)
sets error detail if no earlier detail was available
Definition: HttpRequest.cc:476
size_t base64_encode_update(struct base64_encode_ctx *ctx, char *dst, size_t length, const uint8_t *src)
Definition: base64.c:265
HttpRequest * icapRequest
sent (or at least created) ICAP request
Definition: Xaction.h:57
void setHeader(Header *h)
Definition: InOut.h:48
String extacl_user
Definition: HttpRequest.h:179
Adaptation::ServicePointer theService
ICAP service for all launches.
Definition: Launcher.h:75
C * getRaw() const
Definition: RefCount.h:74
enum Adaptation::Icap::ModXact::State::Sending sending
void packHead(MemBuf &httpBuf, const Http::Message *head)
Definition: ModXact.cc:1633
static char * masterx_shared_name
Definition: Config.h:45
void makeUsernameHeader(const HttpRequest *request, MemBuf &buf)
Definition: ModXact.cc:1567
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
virtual void fillPendingStatus(MemBuf &buf) const
Definition: Xaction.cc:677
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:112
int const char size_t
Definition: stub_liblog.cc:86
Http1::TeChunkedParser * bodyParser
Definition: ModXact.h:302
bool wantsPreview(const SBuf &urlPath, size_t &wantedSize) const
Definition: ServiceRep.cc:331
void setOutcome(const XactOutcome &xo)
Definition: Xaction.cc:585
Definition: MemBuf.h:23
void stopConsumingFrom(RefCount< BodyPipe > &)
Definition: BodyPipe.cc:118
bool doneWithIo() const
Definition: Xaction.cc:559
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:55
bool parseCharBuf(const char *buf, ssize_t end)
Definition: Message.cc:148
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:127
void addLastRequestChunk(MemBuf &buf)
Definition: ModXact.cc:372
AccessLogEntry::Pointer alMaster
Master transaction AccessLogEntry.
Definition: ModXact.h:372
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:98
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
virtual void reset()
Definition: HttpReply.cc:58
AccessLogEntry & al
short for *alep
Definition: Xaction.h:149
AccessLogEntry::Pointer alep
icap.log entry
Definition: Xaction.h:148
virtual void fillPendingStatus(MemBuf &buf) const
Definition: ModXact.cc:1750
bool getByIdIfPresent(Http::HdrType id, String *result) const
Definition: HttpHeader.cc:911
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
bool doneSending() const
Definition: ModXact.cc:611
bool doneConsumingVirgin() const
Definition: ModXact.h:343
uint64_t bodySize() const
Definition: BodyPipe.cc:161
bool parse(const char *buf, const size_t sz, bool eol, Http::StatusCode *error)
Definition: Message.cc:80
void consume(size_t size)
Definition: BodyPipe.cc:309
void makeRequestHeaders(MemBuf &buf)
Definition: ModXact.cc:1391
void addEntry(HttpHeaderEntry *e)
Definition: HttpHeader.cc:751
virtual void finalizeLogInfo()
Definition: Xaction.cc:640
const ServiceConfig & cfg() const
Definition: Service.h:51
bool expectHttpBody() const
whether ICAP response header indicates HTTP body presence
Definition: ModXact.cc:1126
void updateXxRecord(const char *name, const String &value)
sets or resets a cross-transactional database record
Definition: History.cc:104
void prepPartialBodyEchoing(uint64_t pos)
Definition: ModXact.cc:1025
virtual bool expectingBody(const HttpRequestMethod &, int64_t &) const =0
virtual void callException(const std::exception &e)
called when the job throws during an async call
Definition: ModXact.cc:668
virtual bool fillVirginHttpHeader(MemBuf &) const
Definition: ModXact.cc:1987
ChunkExtensionValueParser extensionParser
Definition: ModXact.h:322
const XactOutcome xoPartEcho
preserved virgin msg part (ICAP 206)
Definition: Elements.cc:24
void stopWriting(bool nicely)
Definition: ModXact.cc:489
bool readyForUob
got a 206 response and expect a use-origin-body
Definition: ModXact.h:336
BodyPipe::Pointer body_pipe
Definition: InOut.h:63
bool waitedForService
true if was queued at least once
Definition: ModXact.h:337
void openChunk(MemBuf &buf, size_t chunkSize, bool ieof)
Definition: ModXact.cc:379
Adaptation::Icap::ICAP::Method reqMethod
ICAP request method.
virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer)
Definition: ModXact.cc:1271
virtual void handleCommWrote(size_t size)
Definition: ModXact.cc:209
bool set() const
was set but may be invalid
Definition: CbcPointer.h:40
void stopSending(bool nicely)
Definition: ModXact.cc:617
size_type size() const
Definition: SquidString.h:72
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
Definition: MessageSizes.h:24
bool hasContent() const
Definition: MemBuf.h:54
MessageSizes clientRequestSz
counters for the original request received from client
Ip::Address indirect_client_addr
Definition: HttpRequest.h:152
bool expectHttpHeader() const
whether ICAP response header indicates HTTP header presence
Definition: ModXact.cc:1121
squidaio_request_t * head
Definition: aiops.cc:127
#define NULL
Definition: types.h:166
virtual void start()
called by AsyncStart; do not call directly
Definition: ModXact.cc:88
virtual void handleCommRead(size_t size)
Definition: ModXact.cc:570
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:554
int size
Definition: ModDevPoll.cc:77
bool needsMoreData() const
Definition: BodyPipe.h:119
A const & min(A const &lhs, A const &rhs)
void setCause(HttpRequest *r)
Definition: InOut.h:38
const char * rawContent() const
Definition: SBuf.cc:519
void updateNextServices(const String &services)
sets or resets next services for the Adaptation::Iterator to notice
Definition: History.cc:120
#define false
Definition: GnuRegex.c:233
Secure ICAP service.
Definition: Message.h:35
bool productionEnded() const
Definition: BodyPipe.h:113
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
Definition: HttpRequest.cc:400
#define base64_encode_len(length)
Definition: base64.h:169
bool gotEncapsulated(const char *section) const
Definition: ModXact.cc:1815
bool hasPotentialSpace() const
Definition: MemBuf.h:75
TrailerParser * trailerParser
Definition: ModXact.h:320
void terminate()
Definition: MemBuf.cc:250

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors