Stream.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 #include "squid.h"
10 #include "client_side_request.h"
11 #include "http/Stream.h"
12 #include "HttpHdrContRange.h"
13 #include "HttpHeaderTools.h"
14 #include "Store.h"
15 #include "TimeOrTag.h"
16 #if USE_DELAY_POOLS
17 #include "acl/FilledChecklist.h"
18 #include "ClientInfo.h"
19 #include "fde.h"
20 #include "MessageDelayPools.h"
21 #endif
22 
24  clientConnection(aConn),
25  http(aReq),
26  reply(nullptr),
27  writtenToSocket(0),
28  mayUseConnection_(false),
29  connRegistered_(false)
30 {
31  assert(http != nullptr);
32  memset(reqbuf, '\0', sizeof (reqbuf));
33  flags.deferred = 0;
34  flags.parsed_ok = 0;
35  deferredparams.node = nullptr;
36  deferredparams.rep = nullptr;
37 }
38 
40 {
41  if (auto node = getTail()) {
42  if (auto ctx = dynamic_cast<Http::Stream *>(node->data.getRaw())) {
43  /* We are *always* the tail - prevent recursive free */
44  assert(this == ctx);
45  node->data = nullptr;
46  }
47  }
48  httpRequestFree(http);
49 }
50 
51 void
53 {
54  assert(!connRegistered_);
55  assert(getConn());
56  connRegistered_ = true;
57  getConn()->add(this);
58 }
59 
60 bool
62 {
63  return http->out.size == 0;
64 }
65 
66 void
68 {
69  const StoreEntry *entry = http->storeEntry();
70  debugs(33, 5, clientConnection << ", sz " << size <<
71  ", off " << (http->out.size + size) << ", len " <<
72  (entry ? entry->objectLen() : 0));
73 
74  http->out.size += size;
75 
76  switch (socketState()) {
77 
78  case STREAM_NONE:
79  pullData();
80  break;
81 
82  case STREAM_COMPLETE: {
83  debugs(33, 5, clientConnection << " Stream complete, keepalive is " <<
84  http->request->flags.proxyKeepalive);
85  // XXX: This code assumes we are done with the transaction, but we may
86  // still be receiving request body. TODO: Extend stopSending() instead.
87  ConnStateData *c = getConn();
88  if (!http->request->flags.proxyKeepalive)
89  clientConnection->close();
90  finished();
91  c->kick();
92  }
93  return;
94 
96  initiateClose("STREAM_UNPLANNED_COMPLETE");
97  return;
98 
99  case STREAM_FAILED:
100  initiateClose("STREAM_FAILED");
101  return;
102 
103  default:
104  fatal("Hit unreachable code in Http::Stream::writeComplete\n");
105  }
106 }
107 
108 void
110 {
111  debugs(33, 5, reply << " written " << http->out.size << " into " << clientConnection);
112 
113  /* More data will be coming from the stream. */
114  StoreIOBuffer readBuffer;
115  /* XXX: Next requested byte in the range sequence */
116  /* XXX: length = getmaximumrangelenfgth */
117  readBuffer.offset = getNextRangeOffset();
118  readBuffer.length = HTTP_REQBUF_SZ;
119  readBuffer.data = reqbuf;
120  /* we may note we have reached the end of the wanted ranges */
121  clientStreamRead(getTail(), http, readBuffer);
122 }
123 
124 bool
126 {
127  return http->multipartRangeRequest();
128 }
129 
130 int64_t
132 {
133  debugs (33, 5, "range: " << http->request->range <<
134  "; http offset " << http->out.offset <<
135  "; reply " << reply);
136 
137  // XXX: This method is called from many places, including pullData() which
138  // may be called before prepareReply() [on some Squid-generated errors].
139  // Hence, we may not even know yet whether we should honor/do ranges.
140 
141  if (http->request->range) {
142  /* offset in range specs does not count the prefix of an http msg */
143  /* check: reply was parsed and range iterator was initialized */
144  assert(http->range_iter.valid);
145  /* filter out data according to range specs */
146  assert(canPackMoreRanges());
147  {
148  assert(http->range_iter.currentSpec());
149  /* offset of still missing data */
150  int64_t start = http->range_iter.currentSpec()->offset +
151  http->range_iter.currentSpec()->length -
152  http->range_iter.debt();
153  debugs(33, 3, "clientPackMoreRanges: in: offset: " << http->out.offset);
154  debugs(33, 3, "clientPackMoreRanges: out:"
155  " start: " << start <<
156  " spec[" << http->range_iter.pos - http->request->range->begin() << "]:" <<
157  " [" << http->range_iter.currentSpec()->offset <<
158  ", " << http->range_iter.currentSpec()->offset +
159  http->range_iter.currentSpec()->length << "),"
160  " len: " << http->range_iter.currentSpec()->length <<
161  " debt: " << http->range_iter.debt());
162  if (http->range_iter.currentSpec()->length != -1)
163  assert(http->out.offset <= start); /* we did not miss it */
164 
165  return start;
166  }
167 
168  } else if (const auto cr = reply ? reply->contentRange() : nullptr) {
169  /* request does not have ranges, but reply does */
170  /* TODO: should use range_iter_pos on reply, as soon as reply->content_range
171  * becomes HttpHdrRange rather than HttpHdrRangeSpec.
172  */
173  if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition)
174  return http->out.offset + cr->spec.offset;
175  }
176 
177  return http->out.offset;
178 }
179 
187 bool
189 {
191  if (!http->range_iter.debt()) {
192  debugs(33, 5, "At end of current range spec for " << clientConnection);
193 
194  if (http->range_iter.pos != http->range_iter.end)
195  ++http->range_iter.pos;
196 
197  http->range_iter.updateSpec();
198  }
199 
200  assert(!http->range_iter.debt() == !http->range_iter.currentSpec());
201 
202  /* paranoid sync condition */
203  /* continue condition: need_more_data */
204  debugs(33, 5, "returning " << (http->range_iter.currentSpec() ? true : false));
205  return http->range_iter.currentSpec() ? true : false;
206 }
207 
211 {
212  switch (clientStreamStatus(getTail(), http)) {
213 
214  case STREAM_NONE:
215  /* check for range support ending */
216  if (http->request->range) {
217  /* check: reply was parsed and range iterator was initialized */
218  assert(http->range_iter.valid);
219  /* filter out data according to range specs */
220 
221  if (!canPackMoreRanges()) {
222  debugs(33, 5, "Range request at end of returnable " <<
223  "range sequence on " << clientConnection);
224  // we got everything we wanted from the store
225  return STREAM_COMPLETE;
226  }
227  } else if (reply && reply->contentRange()) {
228  /* reply has content-range, but Squid is not managing ranges */
229  const int64_t &bytesSent = http->out.offset;
230  const int64_t &bytesExpected = reply->contentRange()->spec.length;
231 
232  debugs(33, 7, "body bytes sent vs. expected: " <<
233  bytesSent << " ? " << bytesExpected << " (+" <<
234  reply->contentRange()->spec.offset << ")");
235 
236  // did we get at least what we expected, based on range specs?
237 
238  // this Content-Range does not tell us how many bytes to expect
239  if (bytesExpected == HttpHdrRangeSpec::UnknownPosition)
240  return STREAM_NONE;
241 
242  if (bytesSent == bytesExpected) // got everything
243  return STREAM_COMPLETE;
244 
245  if (bytesSent > bytesExpected) // Error: Sent more than expected
247  }
248 
249  return STREAM_NONE;
250 
251  case STREAM_COMPLETE:
252  return STREAM_COMPLETE;
253 
256 
257  case STREAM_FAILED:
258  return STREAM_FAILED;
259  }
260 
261  fatal ("unreachable code\n");
262  return STREAM_NONE;
263 }
264 
265 void
267 {
268  prepareReply(rep);
269  assert(rep);
270  MemBuf *mb = rep->pack();
271 
272  // dump now, so we do not output any body.
273  debugs(11, 2, "HTTP Client " << clientConnection);
274  debugs(11, 2, "HTTP Client REPLY:\n---------\n" << mb->buf << "\n----------");
275 
276  /* Save length of headers for persistent conn checks */
277  http->out.headers_sz = mb->contentSize();
278 #if HEADERS_LOG
279  headersLog(0, 0, http->request->method, rep);
280 #endif
281 
282  if (bodyData.data && bodyData.length) {
283  if (multipartRangeRequest())
284  packRange(bodyData, mb);
285  else if (http->request->flags.chunkedReply) {
286  packChunk(bodyData, *mb);
287  } else {
288  size_t length = lengthToSend(bodyData.range());
289  noteSentBodyBytes(length);
290  mb->append(bodyData.data, length);
291  }
292  }
293 #if USE_DELAY_POOLS
294  for (const auto &pool: MessageDelayPools::Instance()->pools) {
295  if (pool->access) {
296  std::unique_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(pool->access, http));
297  chl->reply = rep;
298  HTTPMSGLOCK(chl->reply);
299  const auto answer = chl->fastCheck();
300  if (answer.allowed()) {
301  writeQuotaHandler = pool->createBucket();
302  fd_table[clientConnection->fd].writeQuotaHandler = writeQuotaHandler;
303  break;
304  } else {
305  debugs(83, 4, "Response delay pool " << pool->poolName <<
306  " skipped because ACL " << answer);
307  }
308  }
309  }
310 #endif
311 
312  getConn()->write(mb);
313  delete mb;
314 }
315 
316 void
318 {
319  if (!multipartRangeRequest() && !http->request->flags.chunkedReply) {
320  size_t length = lengthToSend(bodyData.range());
321  noteSentBodyBytes(length);
322  getConn()->write(bodyData.data, length);
323  return;
324  }
325 
326  MemBuf mb;
327  mb.init();
328  if (multipartRangeRequest())
329  packRange(bodyData, &mb);
330  else
331  packChunk(bodyData, mb);
332 
333  if (mb.contentSize())
334  getConn()->write(&mb);
335  else
336  writeComplete(0);
337 }
338 
339 size_t
341 {
342  // the size of available range can always fit into a size_t type
343  size_t maximum = available.size();
344 
345  if (!http->request->range)
346  return maximum;
347 
348  assert(canPackMoreRanges());
349 
350  if (http->range_iter.debt() == -1)
351  return maximum;
352 
353  assert(http->range_iter.debt() > 0);
354 
355  /* TODO this + the last line could be a range intersection calculation */
356  if (available.start < http->range_iter.currentSpec()->offset)
357  return 0;
358 
359  return min(http->range_iter.debt(), static_cast<int64_t>(maximum));
360 }
361 
362 void
364 {
365  debugs(33, 7, bytes << " body bytes");
366  http->out.offset += bytes;
367 
368  if (!http->request->range)
369  return;
370 
371  if (http->range_iter.debt() != -1) {
372  http->range_iter.debt(http->range_iter.debt() - bytes);
373  assert (http->range_iter.debt() >= 0);
374  }
375 
376  /* debt() always stops at -1, below that is a bug */
377  assert(http->range_iter.debt() >= -1);
378 }
379 
381 static bool
383 {
385 
386  /* check for parsing failure */
387  if (!spec.valid)
388  return false;
389 
390  /* got an ETag? */
391  if (spec.tag.str) {
392  ETag rep_tag = rep->header.getETag(Http::HdrType::ETAG);
393  debugs(33, 3, "ETags: " << spec.tag.str << " and " <<
394  (rep_tag.str ? rep_tag.str : "<none>"));
395 
396  if (!rep_tag.str)
397  return false; // entity has no etag to compare with!
398 
399  if (spec.tag.weak || rep_tag.weak) {
400  debugs(33, DBG_IMPORTANT, "Weak ETags are not allowed in If-Range: " <<
401  spec.tag.str << " ? " << rep_tag.str);
402  return false; // must use strong validator for sub-range requests
403  }
404 
405  return etagIsStrongEqual(rep_tag, spec.tag);
406  }
407 
408  /* got modification time? */
409  if (spec.time >= 0)
410  return !http->storeEntry()->modifiedSince(spec.time);
411 
412  assert(0); /* should not happen */
413  return false;
414 }
415 
416 // seems to be something better suited to Server logic
418 void
420 {
421  HttpHeader *hdr = rep ? &rep->header : nullptr;
422  const char *range_err = nullptr;
423  HttpRequest *request = http->request;
424  assert(request->range);
425  /* check if we still want to do ranges */
426  int64_t roffLimit = request->getRangeOffsetLimit();
427  auto contentRange = rep ? rep->contentRange() : nullptr;
428 
429  if (!rep)
430  range_err = "no [parse-able] reply";
431  else if ((rep->sline.status() != Http::scOkay) && (rep->sline.status() != Http::scPartialContent))
432  range_err = "wrong status code";
433  else if (rep->sline.status() == Http::scPartialContent)
434  range_err = "too complex response"; // probably contains what the client needs
435  else if (rep->sline.status() != Http::scOkay)
436  range_err = "wrong status code";
437  else if (hdr->has(Http::HdrType::CONTENT_RANGE)) {
438  Must(!contentRange); // this is a 200, not 206 response
439  range_err = "meaningless response"; // the status code or the header is wrong
440  }
441  else if (rep->content_length < 0)
442  range_err = "unknown length";
443  else if (rep->content_length != http->storeEntry()->mem().baseReply().content_length)
444  range_err = "INCONSISTENT length"; /* a bug? */
445 
446  /* hits only - upstream CachePeer determines correct behaviour on misses,
447  * and client_side_reply determines hits candidates
448  */
449  else if (http->loggingTags().isTcpHit() &&
450  http->request->header.has(Http::HdrType::IF_RANGE) &&
451  !clientIfRangeMatch(http, rep))
452  range_err = "If-Range match failed";
453 
454  else if (!http->request->range->canonize(rep))
455  range_err = "canonization failed";
456  else if (http->request->range->isComplex())
457  range_err = "too complex range header";
458  else if (!http->loggingTags().isTcpHit() && http->request->range->offsetLimitExceeded(roffLimit))
459  range_err = "range outside range_offset_limit";
460 
461  /* get rid of our range specs on error */
462  if (range_err) {
463  /* XXX We do this here because we need canonisation etc. However, this current
464  * code will lead to incorrect store offset requests - the store will have the
465  * offset data, but we won't be requesting it.
466  * So, we can either re-request, or generate an error
467  */
468  http->request->ignoreRange(range_err);
469  } else {
470  /* XXX: TODO: Review, this unconditional set may be wrong. */
472 
473  // before range_iter accesses
474  const auto actual_clen = http->prepPartialResponseGeneration();
475 
476  const int spec_count = http->request->range->specs.size();
477 
478  debugs(33, 3, "range spec count: " << spec_count <<
479  " virgin clen: " << rep->content_length);
480  assert(spec_count > 0);
481  /* append appropriate header(s) */
482  if (spec_count == 1) {
483  const auto singleSpec = *http->request->range->begin();
484  assert(singleSpec);
485  httpHeaderAddContRange(hdr, *singleSpec, rep->content_length);
486  } else {
487  /* multipart! */
488  /* delete old Content-Type, add ours */
491  "multipart/byteranges; boundary=\"" SQUIDSTRINGPH "\"",
492  SQUIDSTRINGPRINT(http->range_iter.boundary));
493  }
494 
495  /* replace Content-Length header */
496  assert(actual_clen >= 0);
498  hdr->putInt64(Http::HdrType::CONTENT_LENGTH, actual_clen);
499  debugs(33, 3, "actual content length: " << actual_clen);
500  }
501 }
502 
505 {
506  if (http->client_stream.tail)
507  return static_cast<clientStreamNode *>(http->client_stream.tail->data);
508 
509  return nullptr;
510 }
511 
514 {
515  return static_cast<clientStreamNode *>(http->client_stream.tail->prev->data);
516 }
517 
520 {
521  assert(http && http->getConn());
522  return http->getConn();
523 }
524 
526 void
528 {
529  if (http) {
530  http->updateError(error);
531  http->al->cache.code.err.update(lte);
532  }
533 }
534 
535 void
537 {
538  CodeContext::Reset(clientConnection);
539  ConnStateData *conn = getConn();
540 
541  /* we can't handle any more stream data - detach */
542  clientStreamDetach(getTail(), http);
543 
544  assert(connRegistered_);
545  connRegistered_ = false;
546  conn->pipeline.popMe(Http::StreamPointer(this));
547 }
548 
550 void
551 Http::Stream::initiateClose(const char *reason)
552 {
553  debugs(33, 4, clientConnection << " because " << reason);
554  getConn()->stopSending(reason); // closes ASAP
555 }
556 
557 void
559 {
560  debugs(33, 2, "Deferring request " << http->uri);
561  assert(flags.deferred == 0);
562  flags.deferred = 1;
563  deferredparams.node = node;
564  deferredparams.rep = rep;
565  deferredparams.queuedBuffer = receivedData;
566 }
567 
568 void
570 {
571  reply = rep;
572  if (http->request->range)
573  buildRangeHeader(rep);
574 }
575 
580 void
582 {
583  const uint64_t length =
584  static_cast<uint64_t>(lengthToSend(bodyData.range()));
585  noteSentBodyBytes(length);
586 
587  mb.appendf("%" PRIX64 "\r\n", length);
588  mb.append(bodyData.data, length);
589  mb.append("\r\n", 2);
590 }
591 
596 void
598 {
599  HttpHdrRangeIter * i = &http->range_iter;
600  Range<int64_t> available(source.range());
601  char const *buf = source.data;
602 
603  while (i->currentSpec() && available.size()) {
604  const size_t copy_sz = lengthToSend(available);
605  if (copy_sz) {
606  // intersection of "have" and "need" ranges must not be empty
607  assert(http->out.offset < i->currentSpec()->offset + i->currentSpec()->length);
608  assert(http->out.offset + (int64_t)available.size() > i->currentSpec()->offset);
609 
610  /*
611  * put boundary and headers at the beginning of a range in a
612  * multi-range
613  */
614  if (http->multipartRangeRequest() && i->debt() == i->currentSpec()->length) {
616  &http->storeEntry()->mem().freshestReply(),
617  i->currentSpec(), /* current range */
618  i->boundary, /* boundary, the same for all */
619  mb);
620  }
621 
622  // append content
623  debugs(33, 3, "appending " << copy_sz << " bytes");
624  noteSentBodyBytes(copy_sz);
625  mb->append(buf, copy_sz);
626 
627  // update offsets
628  available.start += copy_sz;
629  buf += copy_sz;
630  }
631 
632  if (!canPackMoreRanges()) {
633  debugs(33, 3, "Returning because !canPackMoreRanges.");
634  if (i->debt() == 0)
635  // put terminating boundary for multiparts
637  return;
638  }
639 
640  int64_t nextOffset = getNextRangeOffset();
641  assert(nextOffset >= http->out.offset);
642  int64_t skip = nextOffset - http->out.offset;
643  /* adjust for not to be transmitted bytes */
644  http->out.offset = nextOffset;
645 
646  if (available.size() <= (uint64_t)skip)
647  return;
648 
649  available.start += skip;
650  buf += skip;
651 
652  if (copy_sz == 0)
653  return;
654  }
655 }
656 
657 void
659 {
660  clientConnection->close();
661 }
662 
bool etagIsStrongEqual(const ETag &tag1, const ETag &tag2)
whether etags are strong-equal
Definition: ETag.cc:49
#define true
Definition: GnuRegex.c:234
#define false
Definition: GnuRegex.c:233
void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, int64_t)
void httpHeaderPutStrf(HttpHeader *hdr, Http::HdrType id, const char *fmt,...)
int size
Definition: ModDevPoll.cc:75
#define SQUIDSTRINGPH
Definition: SquidString.h:21
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:22
static bool clientIfRangeMatch(ClientHttpRequest *http, HttpReply *rep)
Definition: Stream.cc:382
#define Must(condition)
Definition: TextException.h:71
int conn
the current server connection FD
Definition: Transport.cc:26
void error(char *format,...)
#define assert(EX)
Definition: assert.h:19
HttpRequest *const request
StoreEntry * storeEntry() const
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:75
void kick()
try to make progress on a transaction or read more I/O
Definition: client_side.cc:907
Definition: ETag.h:18
int weak
true if it is a weak validator
Definition: ETag.h:21
const char * str
quoted-string
Definition: ETag.h:20
a transaction problem
Definition: Error.h:18
const HttpHdrRangeSpec * currentSpec() const
int64_t debt() const
static int64_t const UnknownPosition
TimeOrTag getTimeOrTag(Http::HdrType id) const
Definition: HttpHeader.cc:1359
ETag getETag(Http::HdrType id) const
Definition: HttpHeader.cc:1346
int delById(Http::HdrType id)
Definition: HttpHeader.cc:695
void putInt64(Http::HdrType id, int64_t number)
Definition: HttpHeader.cc:1034
int has(Http::HdrType id) const
Definition: HttpHeader.cc:991
Http::StatusLine sline
Definition: HttpReply.h:56
MemBuf * pack() const
Definition: HttpReply.cc:110
const HttpHdrContRange * contentRange() const
Definition: HttpReply.cc:342
HttpHeader header
Definition: Message.h:75
int64_t content_length
Definition: Message.h:84
void set(const AnyP::ProtocolVersion &newVersion, Http::StatusCode newStatus, const char *newReason=NULL)
Definition: StatusLine.cc:35
AnyP::ProtocolVersion version
breakdown of protocol version label: (HTTP/ICY) and (0.9/1.0/1.1)
Definition: StatusLine.h:62
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
clientStreamNode * node
Definition: Stream.h:151
void sendStartOfMessage(HttpReply *, StoreIOBuffer bodyData)
send an HTTP reply message headers and maybe some initial payload
Definition: Stream.cc:266
void deferRecipientForLater(clientStreamNode *, HttpReply *, StoreIOBuffer receivedData)
Definition: Stream.cc:558
DeferredParams deferredparams
Definition: Stream.h:156
size_t lengthToSend(Range< int64_t > const &available) const
Definition: Stream.cc:340
bool canPackMoreRanges() const
Definition: Stream.cc:188
struct Http::Stream::@77 flags
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:52
void packChunk(const StoreIOBuffer &bodyData, MemBuf &)
Definition: Stream.cc:581
ConnStateData * getConn() const
Definition: Stream.cc:519
clientStream_status_t socketState()
Adapt stream status to account for Range cases.
Definition: Stream.cc:210
void sendBody(StoreIOBuffer bodyData)
send some HTTP reply message payload
Definition: Stream.cc:317
void buildRangeHeader(HttpReply *)
add Range headers (if any) to the given HTTP reply message
Definition: Stream.cc:419
char reqbuf[HTTP_REQBUF_SZ]
Definition: Stream.h:134
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:513
void packRange(StoreIOBuffer const &, MemBuf *)
Definition: Stream.cc:597
void initiateClose(const char *reason)
terminate due to a send/write error (may continue reading)
Definition: Stream.cc:551
void doClose()
Definition: Stream.cc:658
int64_t getNextRangeOffset() const
Definition: Stream.cc:131
bool multipartRangeRequest() const
Definition: Stream.cc:125
bool startOfOutput() const
whether the reply has started being sent
Definition: Stream.cc:61
void noteSentBodyBytes(size_t)
Definition: Stream.cc:363
void finished()
cleanup when the transaction has finished. may destroy 'this'
Definition: Stream.cc:536
void writeComplete(size_t size)
update stream state after a write, may initiate more I/O
Definition: Stream.cc:67
void prepareReply(HttpReply *)
Definition: Stream.cc:569
clientStreamNode * getTail() const
Definition: Stream.cc:504
Stream(const Comm::ConnectionPointer &aConn, ClientHttpRequest *aReq)
construct with HTTP/1.x details
Definition: Stream.cc:23
void noteIoError(const Error &, const LogTagsErrors &)
update state to reflect I/O error
Definition: Stream.cc:527
void pullData()
get more data to send
Definition: Stream.cc:109
ClientHttpRequest * http
Definition: Stream.h:132
Definition: MemBuf.h:24
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
char * buf
Definition: MemBuf.h:134
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
static MessageDelayPools * Instance()
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
Definition: Range.h:19
C start
Definition: Range.h:24
S size() const
Definition: Range.h:61
bool modifiedSince(const time_t ims, const int imslen=-1) const
Definition: store.cc:1798
int64_t objectLen() const
Definition: Store.h:255
int64_t offset
Definition: StoreIOBuffer.h:55
Range< int64_t > range() const
Definition: StoreIOBuffer.h:42
ETag tag
Definition: TimeOrTag.h:20
time_t time
Definition: TimeOrTag.h:21
int valid
Definition: TimeOrTag.h:22
ACLFilledChecklist * clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
void httpRequestFree(void *data)
Definition: client_side.cc:488
void clientPackTermBound(String boundary, MemBuf *mb)
put terminating boundary for multiparts to the buffer
Definition: client_side.cc:715
void clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec *spec, String boundary, MemBuf *mb)
append a "part" HTTP header (as in a multi-part/range reply) to the buffer
Definition: client_side.cc:722
A const & min(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
clientStream_status_t
Definition: enums.h:125
@ STREAM_COMPLETE
Definition: enums.h:127
@ STREAM_UNPLANNED_COMPLETE
Definition: enums.h:132
@ STREAM_NONE
Definition: enums.h:126
@ STREAM_FAILED
Definition: enums.h:137
void fatal(const char *message)
Definition: fatal.cc:28
#define fd_table
Definition: fde.h:189
clientStream_status_t clientStreamStatus(clientStreamNode *thisObject, ClientHttpRequest *http)
void clientStreamRead(clientStreamNode *thisObject, ClientHttpRequest *http, StoreIOBuffer readBuffer)
void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http)
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
#define HTTP_REQBUF_SZ
Definition: forward.h:14
@ scOkay
Definition: StatusCode.h:26
@ scPartialContent
Definition: StatusCode.h:32
@ CONTENT_LENGTH
Definition: parse.c:104
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
#define PRIX64
Definition: types.h:130

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors