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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors