proxygen
HTTP1xCodec.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 
12 #include <folly/Memory.h>
13 #include <folly/Random.h>
14 #include <folly/ssl/OpenSSLHash.h>
19 
20 using folly::IOBuf;
21 using folly::IOBufQueue;
22 using folly::StringPiece;
23 using std::string;
24 using std::unique_ptr;
25 
26 namespace {
27 
28 static const std::string kChunked = "chunked";
29 const char CRLF[] = "\r\n";
30 
38 unsigned u64toa(uint64_t value, void* dst) {
39  // Write backwards.
40  char* next = (char*)dst;
41  char* start = next;
42  do {
43  *next++ = '0' + (value % 10);
44  value /= 10;
45  } while (value != 0);
46  unsigned length = next - start;
47 
48  // Reverse in-place.
49  next--;
50  while (next > start) {
51  char swap = *next;
52  *next = *start;
53  *start = swap;
54  next--;
55  start++;
56  }
57  return length;
58 }
59 
60 void
61 appendUint(IOBufQueue& queue, size_t& len, uint64_t value) {
62  char buf[32];
63  size_t encodedLen = u64toa(value, buf);
64  queue.append(buf, encodedLen);
65  len += encodedLen;
66 }
67 
68 #define appendLiteral(queue, len, str) (len) += (sizeof(str) - 1); \
69  (queue).append(str, sizeof(str) - 1)
70 
71 void
72 appendString(IOBufQueue& queue, size_t& len, StringPiece str) {
73  queue.append(str.data(), str.size());
74  len += str.size();
75 }
76 
77 } // anonymous namespace
78 
79 namespace proxygen {
80 
81 HTTP1xCodec::HTTP1xCodec(TransportDirection direction, bool forceUpstream1_1)
82  : callback_(nullptr),
83  ingressTxnID_(0),
84  egressTxnID_(0),
85  currentIngressBuf_(nullptr),
86  headerParseState_(HeaderParseState::kParsingHeaderIdle),
87  transportDirection_(direction),
88  keepaliveRequested_(KeepaliveRequested::UNSET),
89  forceUpstream1_1_(forceUpstream1_1),
90  parserActive_(false),
91  pendingEOF_(false),
92  parserPaused_(false),
93  parserError_(false),
94  requestPending_(false),
95  responsePending_(false),
96  egressChunked_(false),
97  inChunk_(false),
98  lastChunkWritten_(false),
99  keepalive_(true),
100  disableKeepalivePending_(false),
101  connectRequest_(false),
102  headRequest_(false),
103  expectNoResponseBody_(false),
104  mayChunkEgress_(false),
105  is1xxResponse_(false),
106  inRecvLastChunk_(false),
107  ingressUpgrade_(false),
108  ingressUpgradeComplete_(false),
109  egressUpgrade_(false),
110  nativeUpgrade_(false),
111  headersComplete_(false) {
112  switch (direction) {
115  break;
118  break;
119  default:
120  LOG(FATAL) << "Unknown transport direction.";
121  }
122  parser_.data = this;
123 }
124 
126  // This code used to throw a parse error there were unterminated headers
127  // being parsed. None of the cases where this can happen relied on the parse
128  // error.
129 }
130 
134  return ++ingressTxnID_;
135  } else {
136  return ++egressTxnID_;
137  }
138 }
139 
140 void
142  if ((paused == parserPaused_) || parserError_) {
143  // If we're bailing early, we better be paused already
144  DCHECK(parserError_ ||
145  (HTTP_PARSER_ERRNO(&parser_) == HPE_PAUSED) == paused);
146  return;
147  }
148  if (paused) {
149  if (HTTP_PARSER_ERRNO(&parser_) == HPE_OK) {
151  }
152  } else {
154  }
155  parserPaused_ = paused;
156 }
157 
159  static http_parser_settings parserSettings = [] {
171  return st;
172  }();
173  return &parserSettings;
174 }
175 
176 size_t
178  if (parserError_) {
179  return 0;
180  } else if (ingressUpgradeComplete_) {
181  callback_->onBody(ingressTxnID_, buf.clone(), 0);
182  return buf.computeChainDataLength();
183  } else {
184  // Callers responsibility to prevent calling onIngress from a callback
185  CHECK(!parserActive_);
186  parserActive_ = true;
187  currentIngressBuf_ = &buf;
189  parser_.http_major == 0 && parser_.http_minor == 9) {
190  // HTTP/0.9 responses have no header block, so create a fake 200 response
191  // and put the codec in upgrade mode
192  onMessageBegin();
193  msg_->setStatusCode(200);
195  parserActive_ = false;
197  return onIngress(buf);
198  }
199  size_t bytesParsed = http_parser_execute(&parser_,
201  (const char*)buf.data(),
202  buf.length());
203  // in case we parsed a section of the headers but we're not done parsing
204  // the headers we need to keep accounting of it for total header size
205  if (!headersComplete_) {
206  headerSize_.uncompressed += bytesParsed;
207  }
208  parserActive_ = false;
211  if (parserError_) {
212  onParserError();
213  }
215  // we currently are storing a chunk of header name via pointers in
216  // currentHeaderNameStringPiece_, but the currentIngressBuf_ is about to
217  // vanish and so we need to copy over that data to currentHeaderName_
220  }
221  currentIngressBuf_ = nullptr;
222  if (pendingEOF_) {
223  onIngressEOF();
224  pendingEOF_ = false;
225  }
226  return bytesParsed;
227  }
228 }
229 
230 void
232  if (parserError_) {
233  return;
234  }
235  if (parserActive_) {
236  pendingEOF_ = true;
237  return;
238  }
241  return;
242  }
243  parserActive_ = true;
244  if (http_parser_execute(&parser_, getParserSettings(), nullptr, 0) != 0) {
245  parserError_ = true;
246  } else {
249  }
250  parserActive_ = false;
251  if (parserError_) {
252  onParserError();
253  }
254 }
255 
256 void
257 HTTP1xCodec::onParserError(const char* what) {
258  inRecvLastChunk_ = false;
259  http_errno parser_errno = HTTP_PARSER_ERRNO(&parser_);
261  what ? what : folly::to<std::string>(
262  "Error parsing message: ",
263  http_errno_description(parser_errno)
264  ));
265  // generate a string of parsed headers so that we can pass it to callback
266  if (msg_) {
267  error.setPartialMsg(std::move(msg_));
268  }
269  // store the ingress buffer
270  if (currentIngressBuf_) {
272  }
275  error.setHttpStatusCode(400);
276  } // else we've already egressed a response for this txn, don't attempt a 400
277  // See http_parser.h for what these error codes mean
278  if (parser_errno == HPE_INVALID_EOF_STATE) {
280  } else if (parser_errno == HPE_HEADER_OVERFLOW ||
281  parser_errno == HPE_INVALID_CONSTANT ||
282  (parser_errno >= HPE_INVALID_VERSION &&
283  parser_errno <= HPE_HUGE_CONTENT_LENGTH)) {
285  } else if (parser_errno == HPE_INVALID_CHUNK_SIZE ||
286  parser_errno == HPE_HUGE_CHUNK_SIZE) {
288  } else {
290  }
292 }
293 
294 bool
297  websockAcceptKey_.empty();
298 }
299 
300 bool
303 }
304 
305 void
307  appendLiteral(writeBuf, len, "Date: ");
308  appendString(writeBuf, len, HTTPMessage::formatDateHeader());
309  appendLiteral(writeBuf, len, CRLF);
310 }
311 
312 constexpr folly::StringPiece kUpgradeToken = "websocket";
314 // websocket/http1.1 draft.
315 constexpr folly::StringPiece
316  kWSMagicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
317 
320  std::array<unsigned char, 16> arr;
321  folly::Random::secureRandom(arr.data(), arr.size());
322  return Base64::encode(folly::ByteRange(arr.data(), arr.size()));
323 }
324 
328  digest.hash_init(EVP_sha1());
329  digest.hash_update(folly::StringPiece(key));
330  digest.hash_update(kWSMagicString);
331  std::array<unsigned char, 20> arr;
332  folly::MutableByteRange accept(arr.data(), arr.size());
333  digest.hash_final(accept);
334  return Base64::encode(accept);
335 }
336 
338  size_t& len,
339  bool upstream) {
340  if (upstream) {
341  appendLiteral(writeBuf, len, "Upgrade: ");
342  appendString(writeBuf, len, kUpgradeToken.str());
343  appendLiteral(writeBuf, len, CRLF);
344  upgradeHeader_ = kUpgradeToken.str();
345 
346  auto key = generateWebsocketKey();
347  appendLiteral(writeBuf, len, "Sec-WebSocket-Key: ");
348  appendString(writeBuf, len, key);
349  appendLiteral(writeBuf, len, CRLF);
350  DCHECK(websockAcceptKey_.empty());
352  } else {
353  appendLiteral(writeBuf, len, "Upgrade: ");
354  appendString(writeBuf, len, kUpgradeToken.str());
355  appendLiteral(writeBuf, len, CRLF);
356 
357  appendLiteral(writeBuf, len, "Sec-WebSocket-Accept: ");
358  appendString(writeBuf, len, websockAcceptKey_);
359  appendLiteral(writeBuf, len, CRLF);
360  }
361 }
362 
363 void
365  StreamID txn,
366  const HTTPMessage& msg,
367  bool eom,
368  HTTPHeaderSize* size) {
370  keepalive_ = false;
371  }
372  const bool upstream = (transportDirection_ == TransportDirection::UPSTREAM);
373  const bool downstream = !upstream;
374  if (upstream) {
375  DCHECK_EQ(txn, egressTxnID_);
376  requestPending_ = true;
377  responsePending_ = true;
381  } else {
382  // In HTTP, transactions must be egressed sequentially -- no out of order
383  // responses. So txn must be egressTxnID_ + 1. Furthermore, we shouldn't
384  // ever egress a response before we see a request, so txn can't
385  // be > ingressTxnID_
386  if ((txn != egressTxnID_ + 1 &&
387  !(txn == egressTxnID_ && is1xxResponse_)) ||
388  (txn > ingressTxnID_)) {
389  LOG(DFATAL) << "Out of order, duplicate or premature HTTP response";
390  }
391  if (!is1xxResponse_) {
392  ++egressTxnID_;
393  }
395 
399  }
400 
401  int statusCode = 0;
402  StringPiece statusMessage;
403  if (downstream) {
404  statusCode = msg.getStatusCode();
405  statusMessage = msg.getStatusMessage();
406  // If a response to a websocket upgrade is being sent out, it must be 101.
407  // This is required since the application may not have changed the status,
408  // particularly when proxying between a H2 hop and a H1 hop.
409  if (msg.isEgressWebsocketUpgrade()) {
410  statusCode = 101;
411  statusMessage = HTTPMessage::getDefaultReason(101);
412  }
413  if (connectRequest_ && (statusCode >= 200 && statusCode < 300)) {
414  // Set egress upgrade flag if we are sending a 200 response
415  // to a CONNECT request we received earlier.
416  egressUpgrade_ = true;
417  } else if (statusCode == 101) {
418  // Set the upgrade flags if we upgraded after the request from client.
419  ingressUpgrade_ = true;
420  egressUpgrade_ = true;
421  }
422  else if (connectRequest_ && ingressUpgrade_) {
423  // Disable upgrade when rejecting CONNECT request
424  ingressUpgrade_ = false;
425 
426  // This codec/session is no longer useful as we might have
427  // forwarded some data before receiving the 200.
428  keepalive_ = false;
429  }
430  } else {
432  // Sending a CONNECT request or a websocket upgrade request to an upstream
433  // server. This is used to determine the chunked setting below.
434  egressUpgrade_ = true;
435  }
436  }
437 
439  lastChunkWritten_ = false;
440  std::pair<uint8_t, uint8_t> version = msg.getHTTPVersion();
441  if (version > HTTPMessage::kHTTPVersion11) {
442  version = HTTPMessage::kHTTPVersion11;
443  }
444 
445  size_t len = 0;
446  switch (transportDirection_) {
448  DCHECK_NE(statusCode, 0);
449  if (version.first == 0 && version.second == 9) {
450  return;
451  }
452  appendLiteral(writeBuf, len, "HTTP/");
453  appendUint(writeBuf, len, version.first);
454  appendLiteral(writeBuf, len, ".");
455  appendUint(writeBuf, len, version.second);
456  appendLiteral(writeBuf, len, " ");
457  appendUint(writeBuf, len, statusCode);
458  appendLiteral(writeBuf, len, " ");
459  appendString(writeBuf, len, statusMessage);
460  break;
463  version = HTTPMessage::kHTTPVersion11;
464  }
465  if (msg.isEgressWebsocketUpgrade()) {
466  appendString(writeBuf, len, methodToString(HTTPMethod::GET));
467  } else {
468  appendString(writeBuf, len, msg.getMethodString());
469  }
470  appendLiteral(writeBuf, len, " ");
471  appendString(writeBuf, len, msg.getURL());
472  appendLiteral(writeBuf, len, " HTTP/");
473  appendUint(writeBuf, len, version.first);
474  appendLiteral(writeBuf, len, ".");
475  appendUint(writeBuf, len, version.second);
476  mayChunkEgress_ = (version.first == 1) && (version.second >= 1);
477  if (!upgradeHeader_.empty()) {
478  LOG(DFATAL) << "Attempted to pipeline HTTP request with pending upgrade";
479  upgradeHeader_.clear();
480  }
481  break;
482  }
483 
484  if (keepalive_ &&
485  (!msg.wantsKeepalive() ||
486  version.first < 1 ||
487  (downstream && version == HTTPMessage::kHTTPVersion10 &&
489  // Disable keepalive if
490  // - the message asked to turn it off
491  // - it's HTTP/0.9
492  // - this is a response to a 1.0 request that didn't say keep-alive
493  keepalive_ = false;
494  }
496  appendLiteral(writeBuf, len, CRLF);
497  if (version.first == 0 && version.second == 9) {
498  parser_.http_major = 0;
499  parser_.http_minor = 9;
500  return;
501  }
502  const string* deferredContentLength = nullptr;
503  bool hasTransferEncodingChunked = false;
504  bool hasDateHeader = false;
505  bool hasUpgradeHeader = false;
506  std::vector<StringPiece> connectionTokens;
507  size_t lastConnectionToken = 0;
508  bool egressWebsocketUpgrade = msg.isEgressWebsocketUpgrade();
509  bool hasUpgradeTokeninConnection = false;
510  msg.getHeaders().forEachWithCode([&] (HTTPHeaderCode code,
511  const string& header,
512  const string& value) {
513  if (code == HTTP_HEADER_CONTENT_LENGTH) {
514  // Write the Content-Length last (t1071703)
515  deferredContentLength = &value;
516  return; // continue
517  } else if (code == HTTP_HEADER_CONNECTION && (!is1xxResponse_ ||
518  egressWebsocketUpgrade)) {
519  static const string kClose = "close";
520  static const string kKeepAlive = "keep-alive";
521  folly::split(',', value, connectionTokens);
522  for (auto curConnectionToken = lastConnectionToken;
523  curConnectionToken < connectionTokens.size();
524  curConnectionToken++) {
525  auto token = trimWhitespace(connectionTokens[curConnectionToken]);
526  if (caseInsensitiveEqual(token, "upgrade")) {
527  hasUpgradeTokeninConnection = true;
528  }
529  if (caseInsensitiveEqual(token, kClose)) {
530  keepalive_ = false;
531  } else if (!caseInsensitiveEqual(token, kKeepAlive)) {
532  connectionTokens[lastConnectionToken++] = token;
533  } // else eat the keep-alive token
534  }
535  connectionTokens.resize(lastConnectionToken);
536  // We'll generate a new Connection header based on the keepalive_ state
537  return;
538  } else if (code == HTTP_HEADER_UPGRADE && txn == 1) {
539  hasUpgradeHeader = true;
540  if (upstream) {
541  // save in case we get a 101 Switching Protocols
543  }
544  } else if (!hasTransferEncodingChunked &&
546  if (!caseInsensitiveEqual(value, kChunked)) {
547  return;
548  }
549  hasTransferEncodingChunked = true;
550  if (!mayChunkEgress_) {
551  return;
552  }
553  } else if (!hasDateHeader && code == HTTP_HEADER_DATE) {
554  hasDateHeader = true;
555  } else if (egressWebsocketUpgrade &&
557  // will generate our own key per hop, not client's.
558  return;
559  } else if (egressWebsocketUpgrade &&
561  // will generate our own accept per hop, not client's.
562  return;
563  }
564  size_t lineLen = header.length() + value.length() + 4; // 4 for ": " + CRLF
565  auto writable = writeBuf.preallocate(lineLen,
566  std::max(lineLen, size_t(2000)));
567  char* dst = (char*)writable.first;
568  memcpy(dst, header.data(), header.length());
569  dst += header.length();
570  *dst++ = ':';
571  *dst++ = ' ';
572  memcpy(dst, value.data(), value.length());
573  dst += value.length();
574  *dst++ = '\r';
575  *dst = '\n';
576  DCHECK_EQ(size_t(++dst - (char*)writable.first), lineLen);
577  writeBuf.postallocate(lineLen);
578  len += lineLen;
579  });
580  bool bodyCheck =
581  (downstream && keepalive_ && !expectNoResponseBody_ && !egressUpgrade_) ||
582  // auto chunk POSTs and any request that came to us chunked
583  (upstream && ((msg.getMethod() == HTTPMethod::POST) || egressChunked_));
584  // TODO: 400 a 1.0 POST with no content-length
585  // clear egressChunked_ if the header wasn't actually set
586  egressChunked_ &= hasTransferEncodingChunked;
587  if (bodyCheck && !egressChunked_ && !deferredContentLength) {
588  // On a connection that would otherwise be eligible for keep-alive,
589  // we're being asked to send a response message with no Content-Length,
590  // no chunked encoding, and no special circumstances that would eliminate
591  // the need for a response body. If the client supports chunking, turn
592  // on chunked encoding now. Otherwise, turn off keepalives on this
593  // connection.
594  if (!hasTransferEncodingChunked && mayChunkEgress_) {
595  appendLiteral(writeBuf, len, "Transfer-Encoding: chunked\r\n");
596  egressChunked_ = true;
597  } else {
598  keepalive_ = false;
599  }
600  }
601  if (downstream && !hasDateHeader) {
602  addDateHeader(writeBuf, len);
603  }
604 
605  // websocket headers
606  if (msg.isEgressWebsocketUpgrade()) {
607  if (!hasUpgradeHeader && txn == 1) {
608  // upgradeHeader_ is set in serializeWwebsocketHeader for requests.
609  serializeWebsocketHeader(writeBuf, len, upstream);
610  if (!hasUpgradeTokeninConnection) {
611  connectionTokens.push_back(kUpgradeConnectionToken);
612  lastConnectionToken++;
613  }
614  } else {
615  LOG(ERROR) << folly::to<string>("Not serializing headers. "
616  "Upgrade headers present/txn: ",
617  hasUpgradeHeader, txn);
618  }
619  }
620 
621  if (!is1xxResponse_ || upstream || !connectionTokens.empty()) {
622  // We don't seem to add keep-alive/close and let the application add any
623  // for 1xx responses.
624  appendLiteral(writeBuf, len, "Connection: ");
625  if (connectionTokens.size() > 0) {
626  appendString(writeBuf, len, folly::join(", ", connectionTokens));
627  }
628  if (!is1xxResponse_) {
629  if (connectionTokens.size() > 0) {
630  appendString(writeBuf, len, ", ");
631  }
632  if (keepalive_) {
633  appendLiteral(writeBuf, len, "keep-alive");
634  } else {
635  appendLiteral(writeBuf, len, "close");
636  }
637  }
638  appendLiteral(writeBuf, len, "\r\n");
639  }
640 
641  if (deferredContentLength) {
642  appendLiteral(writeBuf, len, "Content-Length: ");
643  appendString(writeBuf, len, *deferredContentLength);
644  appendLiteral(writeBuf, len, CRLF);
645  }
646  appendLiteral(writeBuf, len, CRLF);
647  if (eom) {
648  len += generateEOM(writeBuf, txn);
649  }
650 
651  if (size) {
652  size->compressed = 0;
653  size->uncompressed = len;
654  }
655 }
656 
658  StreamID txn,
659  unique_ptr<IOBuf> chain,
660  folly::Optional<uint8_t> /*padding*/,
661  bool eom) {
662  DCHECK_EQ(txn, egressTxnID_);
663  if (!chain) {
664  return 0;
665  }
666  size_t buflen = chain->computeChainDataLength();
667  size_t totLen = buflen;
668  if (totLen == 0) {
669  if (eom) {
670  totLen += generateEOM(writeBuf, txn);
671  }
672  return totLen;
673  }
674 
675  if (egressChunked_ && !inChunk_) {
676  char chunkLenBuf[32];
677  int rc = snprintf(chunkLenBuf, sizeof(chunkLenBuf), "%zx\r\n", buflen);
678  CHECK_GT(rc, 0);
679  CHECK_LT(size_t(rc), sizeof(chunkLenBuf));
680 
681  writeBuf.append(chunkLenBuf, rc);
682  totLen += rc;
683 
684  writeBuf.append(std::move(chain));
685  writeBuf.append("\r\n", 2);
686  totLen += 2;
687  } else {
688  writeBuf.append(std::move(chain));
689  }
690  if (eom) {
691  totLen += generateEOM(writeBuf, txn);
692  }
693 
694  return totLen;
695 }
696 
698  StreamID /*txn*/,
699  size_t length) {
700  // TODO: Format directly into the IOBuf, rather than copying after the fact.
701  // IOBufQueue::append() currently forces us to copy.
702 
703  CHECK(length) << "use sendEOM to terminate the message using the "
704  << "standard zero-length chunk. Don't "
705  << "send zero-length chunks using this API.";
706  if (egressChunked_) {
707  CHECK(!inChunk_);
708  inChunk_ = true;
709  char chunkLenBuf[32];
710  int rc = snprintf(chunkLenBuf, sizeof(chunkLenBuf), "%zx\r\n", length);
711  CHECK_GT(rc, 0);
712  CHECK_LT(size_t(rc), sizeof(chunkLenBuf));
713 
714  writeBuf.append(chunkLenBuf, rc);
715  return rc;
716  }
717 
718  return 0;
719 }
720 
722  StreamID /*txn*/) {
723  if (egressChunked_ && inChunk_) {
724  inChunk_ = false;
725  writeBuf.append("\r\n", 2);
726  return 2;
727  }
728 
729  return 0;
730 }
731 
732 size_t
734  StreamID txn,
735  const HTTPHeaders& trailers) {
736  DCHECK_EQ(txn, egressTxnID_);
737  size_t len = 0;
738  if (egressChunked_) {
739  CHECK(!inChunk_);
740  appendLiteral(writeBuf, len, "0\r\n");
741  lastChunkWritten_ = true;
742  trailers.forEach([&] (const string& trailer, const string& value) {
743  appendString(writeBuf, len, trailer);
744  appendLiteral(writeBuf, len, ": ");
745  appendString(writeBuf, len, value);
746  appendLiteral(writeBuf, len, CRLF);
747  });
748  }
749  return len;
750 }
751 
753  DCHECK_EQ(txn, egressTxnID_);
754  size_t len = 0;
755  if (egressChunked_) {
756  CHECK(!inChunk_);
758  lastChunkWritten_ = true;
759  } else {
760  // appending a 0\r\n only if it's not a HEAD and downstream request
761  if (!lastChunkWritten_) {
762  lastChunkWritten_ = true;
763  if (!(headRequest_ &&
765  appendLiteral(writeBuf, len, "0\r\n");
766  }
767  }
768  appendLiteral(writeBuf, len, CRLF);
769  }
770  }
771  switch (transportDirection_) {
773  responsePending_ = false;
774  break;
776  requestPending_ = false;
777  break;
778  }
779  return len;
780 }
781 
783  StreamID /*txn*/,
784  ErrorCode /*statusCode*/) {
785  // statusCode ignored for HTTP/1.1
786  // We won't be able to send anything else on the transport after this.
788  return 0;
789 }
790 
792  IOBufQueue&,
793  StreamID,
794  ErrorCode,
795  std::unique_ptr<folly::IOBuf>) {
796  // statusCode ignored for HTTP/1.1
797  // We won't be able to send anything else on the transport after this.
799  return 0;
800 }
801 
802 void HTTP1xCodec::setAllowedUpgradeProtocols(std::list<std::string> protocols) {
804  for (const auto& proto: protocols) {
805  allowedNativeUpgrades_ += folly::to<string>(proto, ",");
806  }
807  if (!allowedNativeUpgrades_.empty()) {
809  }
810 }
811 
813  return allowedNativeUpgrades_;
814 }
815 
816 int
818  headersComplete_ = false;
821  msg_.reset(new HTTPMessage());
822  trailers_.reset();
824  requestPending_ = true;
825  responsePending_ = true;
826  }
827  // If there was a 1xx on this connection, don't increment the ingress txn id
829  !is1xxResponse_) {
830  ++ingressTxnID_;
831  }
833  is1xxResponse_ = false;
834  }
836  return 0;
837 }
838 
839 int
840 HTTP1xCodec::onURL(const char* buf, size_t len) {
841  url_.append(buf, len);
842  return 0;
843 }
844 
845 int
846 HTTP1xCodec::onReason(const char* buf, size_t len) {
847  reason_.append(buf, len);
848  return 0;
849 }
850 
852  if (LIKELY(currentHeaderName_.empty())) {
856  } else {
857  hdrs.add(currentHeaderName_,
859  currentHeaderName_.clear();
860  }
862  currentHeaderValue_.clear();
863 }
864 
865 int
866 HTTP1xCodec::onHeaderField(const char* buf, size_t len) {
868  pushHeaderNameAndValue(msg_->getHeaders());
870  if (!trailers_) {
871  trailers_.reset(new HTTPHeaders());
872  }
874  }
875 
877 
878  // we're already parsing a header name
879  if (currentHeaderName_.empty()) {
880  // but we've been keeping it in currentHeaderNameStringPiece_ until now
881  if (currentHeaderNameStringPiece_.end() == buf) {
882  // the header name we are currently reading is contiguous in memory,
883  // and so we just adjust the right end of our StringPiece;
884  // this is likely because onIngress() hasn't been called since we got
885  // the previous chunk (otherwise currentHeaderName_ would be nonempty)
887  } else {
888  // this is just for safety - if for any reason there is a discontinuity
889  // even though we are during the same onIngress() call,
890  // we fall back to currentHeaderName_
893  currentHeaderName_.append(buf, len);
894  }
895  } else {
896  // we had already fallen back to currentHeaderName_ before
897  currentHeaderName_.append(buf, len);
898  }
899 
900  } else {
901  // we're not yet parsing a header name - this is the first chunk
902  // (typically, there is only one)
904 
907  } else {
909  }
910  }
911  return 0;
912 }
913 
914 int
915 HTTP1xCodec::onHeaderValue(const char* buf, size_t len) {
916  if (isParsingHeaders()) {
918  } else {
920  }
921  currentHeaderValue_.append(buf, len);
922  return 0;
923 }
924 
925 int
928  pushHeaderNameAndValue(msg_->getHeaders());
929  }
930 
931  // discard messages with folded or multiple valued Transfer-Encoding headers
932  // ex : "chunked , zorg\r\n" or "\r\n chunked \r\n" (t12767790)
933  HTTPHeaders& hdrs = msg_->getHeaders();
934  const std::string& headerVal =
935  hdrs.getSingleOrEmpty(HTTP_HEADER_TRANSFER_ENCODING);
936  if (!headerVal.empty() && !caseInsensitiveEqual(headerVal, kChunked)) {
937  LOG(ERROR) << "Invalid Transfer-Encoding header. Value =" << headerVal;
938  return -1;
939  }
940 
941  // discard messages with multiple content-length headers (t12767790)
942  if (hdrs.getNumberOfValues(HTTP_HEADER_CONTENT_LENGTH) > 1) {
943  // Only reject the message if the Content-Length headers have different
944  // values
946  bool error = hdrs.forEachValueOfHeader(
947  HTTP_HEADER_CONTENT_LENGTH, [&] (folly::StringPiece value) -> bool {
948  if (!contentLen.hasValue()) {
949  contentLen = value;
950  return false;
951  }
952  return (contentLen.value() != value);
953  });
954 
955  if (error) {
956  LOG(ERROR) << "Invalid message, multiple Content-Length headers";
957  return -1;
958  }
959  }
960 
961  // Update the HTTPMessage with the values parsed from the header
962  msg_->setHTTPVersion(parser_.http_major, parser_.http_minor);
963  msg_->setIsChunked((parser_.flags & F_CHUNKED));
964 
966  // Set the method type
967  msg_->setMethod(http_method_str(static_cast<http_method>(parser_.method)));
968 
969  connectRequest_ = (msg_->getMethod() == HTTPMethod::CONNECT);
970 
971  // If this is a headers-only request, we shouldn't send
972  // an entity-body in the response.
973  headRequest_ = (msg_->getMethod() == HTTPMethod::HEAD);
974 
975  ParseURL parseUrl = msg_->setURL(std::move(url_));
976  url_.clear();
977 
978  if (parseUrl.hasHost()) {
979  // RFC 2616 5.2.1 states "If Request-URI is an absoluteURI, the host
980  // is part of the Request-URI. Any Host header field value in the
981  // request MUST be ignored."
982  auto hostAndPort = parseUrl.hostAndPort();
983  VLOG(4) << "Adding inferred host header: " << hostAndPort;
984  msg_->getHeaders().set(HTTP_HEADER_HOST, hostAndPort);
985  }
986 
987  // If the client sent us an HTTP/1.x with x >= 1, we may send
988  // chunked responses.
989  mayChunkEgress_ = ((parser_.http_major == 1) && (parser_.http_minor >= 1));
990  } else {
991  msg_->setStatusCode(parser_.status_code);
992  msg_->setStatusMessage(std::move(reason_));
993  reason_.clear();
994  }
995 
996  auto g = folly::makeGuard([this] {
997  // Always clear the outbound upgrade header after we receive a response
999  parser_.status_code != 100) {
1000  upgradeHeader_.clear();
1001  }
1002  });
1005  if (connectRequest_ &&
1006  (parser_.status_code >= 200 && parser_.status_code < 300)) {
1007  // Enable upgrade if this is a 200 response to a CONNECT
1008  // request we sent earlier
1009  ingressUpgrade_ = true;
1010  } else if (parser_.status_code == 101) {
1011  // Set the upgrade flags if the server has upgraded.
1012  const std::string& serverUpgrade =
1013  msg_->getHeaders().getSingleOrEmpty(HTTP_HEADER_UPGRADE);
1014  if (serverUpgrade.empty() ||
1015  upgradeHeader_.empty()) {
1016  LOG(ERROR) << "Invalid 101 response, empty upgrade headers";
1017  return -1;
1018  }
1020  serverUpgrade,
1021  false /* client mode */);
1022  if (result) {
1023  ingressUpgrade_ = true;
1024  egressUpgrade_ = true;
1025  if (result->first != CodecProtocol::HTTP_1_1) {
1026  bool success = callback_->onNativeProtocolUpgrade(
1027  ingressTxnID_, result->first, result->second, *msg_);
1028  if (success) {
1029  nativeUpgrade_ = true;
1030  msg_->setIsUpgraded(ingressUpgrade_);
1031  return 1; // no message body if successful
1032  }
1033  } else if (result->second == getCodecProtocolString(result->first)) {
1034  // someone upgraded to http/1.1? Reset upgrade flags
1035  ingressUpgrade_ = false;
1036  egressUpgrade_ = false;
1037  }
1038  // else, there's some non-native upgrade
1039  } else {
1040  LOG(ERROR) << "Invalid 101 response, client/server upgrade mismatch "
1041  "client=" << upgradeHeader_ << " server=" << serverUpgrade;
1042  return -1;
1043  }
1044  } else if (parser_.upgrade || parser_.flags & F_UPGRADE) {
1045  // Ignore upgrade header for upstream response messages with status code
1046  // different from 101 in case if it was not a response to CONNECT.
1047  parser_.upgrade = false;
1048  parser_.flags &= ~F_UPGRADE;
1049  }
1050  }
1051  else {
1052  if (connectRequest_) {
1053  // Enable upgrade by default for the CONNECT requests.
1054  // If we locally reject CONNECT, we will disable this flag while
1055  // sending the reject response. If we forward the req to upstream proxy,
1056  // we will start forwarding data to the proxy without waiting for
1057  // the response from the proxy server.
1058  ingressUpgrade_ = true;
1059  } else if (!allowedNativeUpgrades_.empty() && ingressTxnID_ == 1) {
1060  upgradeHeader_ = msg_->getHeaders().getSingleOrEmpty(HTTP_HEADER_UPGRADE);
1061  if (!upgradeHeader_.empty() && !allowedNativeUpgrades_.empty()) {
1064  true /* server mode */);
1065  if (result && result->first != CodecProtocol::HTTP_1_1) {
1066  nativeUpgrade_ = true;
1067  upgradeResult_ = *result;
1068  // unfortunately have to copy because msg_ is passed to
1069  // onHeadersComplete
1070  upgradeRequest_ = std::make_unique<HTTPMessage>(*msg_);
1071  }
1072  }
1073  }
1074  }
1075  msg_->setIsUpgraded(ingressUpgrade_);
1076 
1077  const std::string& upgrade = hdrs.getSingleOrEmpty(HTTP_HEADER_UPGRADE);
1078  if (kUpgradeToken.equals(upgrade, folly::AsciiCaseInsensitive())) {
1079  msg_->setIngressWebsocketUpgrade();
1081  // response.
1082  const std::string& accept = hdrs.getSingleOrEmpty(
1084  if (accept != websockAcceptKey_) {
1085  LOG(ERROR) << "Mismatch in expected ws accept key: " <<
1086  "upstream: " << accept << " expected: " << websockAcceptKey_;
1087  return -1;
1088  }
1089  } else {
1090  // request.
1091  auto key = hdrs.getSingleOrEmpty(HTTP_HEADER_SEC_WEBSOCKET_KEY);
1092  DCHECK(websockAcceptKey_.empty());
1094  }
1095  }
1096 
1097  bool msgKeepalive = msg_->computeKeepalive();
1098  if (!msgKeepalive) {
1099  keepalive_ = false;
1100  }
1102  // Remember whether this was an HTTP 1.0 request with keepalive enabled
1103  if (msgKeepalive && msg_->isHTTP1_0() &&
1107  } else {
1109  }
1110  }
1111 
1112  // Determine whether the HTTP parser should ignore any headers
1113  // that indicate the presence of a message body. This is needed,
1114  // for example, if the message is a response to a request with
1115  // method==HEAD.
1116  bool ignoreBody;
1118  ignoreBody = false;
1119  } else {
1120  is1xxResponse_ = msg_->is1xxResponse();
1121  if (expectNoResponseBody_) {
1122  ignoreBody = true;
1123  } else {
1124  ignoreBody = RFC2616::responseBodyMustBeEmpty(msg_->getStatusCode());
1125  }
1126  }
1127 
1128  headersComplete_ = true;
1129  headerSize_.uncompressed += len;
1130  msg_->setIngressHeaderSize(headerSize_);
1131 
1132  if (userAgent_.empty()) {
1133  userAgent_ = msg_->getHeaders().getSingleOrEmpty(HTTP_HEADER_USER_AGENT);
1134  }
1136 
1137  // 1 is a magic value that tells the http_parser not to expect a
1138  // message body even if the message header implied the presence
1139  // of one (e.g., via a Content-Length)
1140  return (ignoreBody) ? 1 : 0;
1141 }
1142 
1143 int
1144 HTTP1xCodec::onBody(const char* buf, size_t len) {
1145  DCHECK(!isParsingHeaders());
1146  DCHECK(!inRecvLastChunk_);
1147  CHECK_NOTNULL(currentIngressBuf_);
1148  const char* dataStart = (const char*)currentIngressBuf_->data();
1149  const char* dataEnd = dataStart + currentIngressBuf_->length();
1150  DCHECK_GE(buf, dataStart);
1151  DCHECK_LE(buf + len, dataEnd);
1152  unique_ptr<IOBuf> clone(currentIngressBuf_->cloneOne());
1153  clone->trimStart(buf - dataStart);
1154  clone->trimEnd(dataEnd - (buf + len));
1155  DCHECK_EQ(len, clone->computeChainDataLength());
1156  callback_->onBody(ingressTxnID_, std::move(clone), 0);
1157  return 0;
1158 }
1159 
1161  if (len > 0) {
1163  } else {
1164  VLOG(5) << "Suppressed onChunkHeader callback for final zero length "
1165  << "chunk";
1166  inRecvLastChunk_ = true;
1167  }
1168  return 0;
1169 }
1170 
1172  if (inRecvLastChunk_) {
1173  inRecvLastChunk_ = false;
1174  } else {
1176  }
1177  return 0;
1178 }
1179 
1181  DCHECK(!isParsingHeaders());
1182  DCHECK(!inRecvLastChunk_);
1184  if (!trailers_) {
1185  trailers_.reset(new HTTPHeaders());
1186  }
1188  }
1189 
1191  if (trailers_) {
1193  }
1194 
1195  switch (transportDirection_) {
1197  {
1198  requestPending_ = false;
1199  if (upgradeRequest_) {
1202  *upgradeRequest_);
1203  upgradeRequest_.reset();
1204  }
1205  // else there was no match, OR we upgraded to http/1.1 OR someone specified
1206  // a non-native protocol in the setAllowedUpgradeProtocols. No-ops
1207  break;
1208  }
1211  }
1212 
1213  // For downstream, always call onMessageComplete. If native upgrade,
1214  // pass upgrade=false. Else pass ingressUpgrade_.
1215  // For upstream, call onMessagComplete if not native upgrade.
1216  if (!nativeUpgrade_) {
1219  // native upgrade and downstream.
1221  }
1222  // else we suppressed onHeadersComplete, suppress onMessageComplete also.
1223  // The new codec will handle these callbacks with the real message
1224 
1225  if (ingressUpgrade_) {
1226  ingressUpgradeComplete_ = true;
1227  // If upgrade is complete, any pending data should not be parsed.
1228  // It must be forwarded directly to the handler.
1229  setParserPaused(true);
1230  }
1231 
1232  return 0;
1233 }
1234 
1235 int
1237  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1238  DCHECK(codec != nullptr);
1239  DCHECK_EQ(&codec->parser_, parser);
1240 
1241  try {
1242  return codec->onMessageBegin();
1243  } catch (const std::exception& ex) {
1244  codec->onParserError(ex.what());
1245  return 1;
1246  }
1247 }
1248 
1249 int
1250 HTTP1xCodec::onUrlCB(http_parser* parser, const char* buf, size_t len) {
1251  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1252  DCHECK(codec != nullptr);
1253  DCHECK_EQ(&codec->parser_, parser);
1254 
1255  try {
1256  return codec->onURL(buf, len);
1257  } catch (const std::exception& ex) {
1258  codec->onParserError(ex.what());
1259  return 1;
1260  }
1261 }
1262 
1263 int
1264 HTTP1xCodec::onReasonCB(http_parser* parser, const char* buf, size_t len) {
1265  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1266  DCHECK(codec != nullptr);
1267  DCHECK_EQ(&codec->parser_, parser);
1268 
1269  try {
1270  return codec->onReason(buf, len);
1271  } catch (const std::exception& ex) {
1272  codec->onParserError(ex.what());
1273  return 1;
1274  }
1275 }
1276 
1277 int
1278 HTTP1xCodec::onHeaderFieldCB(http_parser* parser, const char* buf, size_t len) {
1279  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1280  DCHECK(codec != nullptr);
1281  DCHECK_EQ(&codec->parser_, parser);
1282 
1283  try {
1284  return codec->onHeaderField(buf, len);
1285  } catch (const std::exception& ex) {
1286  codec->onParserError(ex.what());
1287  return 1;
1288  }
1289 }
1290 
1291 int
1292 HTTP1xCodec::onHeaderValueCB(http_parser* parser, const char* buf, size_t len) {
1293  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1294  DCHECK(codec != nullptr);
1295  DCHECK_EQ(&codec->parser_, parser);
1296 
1297  try {
1298  return codec->onHeaderValue(buf, len);
1299  } catch (const std::exception& ex) {
1300  codec->onParserError(ex.what());
1301  return 1;
1302  }
1303 }
1304 
1306  const char* /*buf*/,
1307  size_t len) {
1308  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1309  DCHECK(codec != nullptr);
1310  DCHECK_EQ(&codec->parser_, parser);
1311 
1312  try {
1313  return codec->onHeadersComplete(len);
1314  } catch (const std::exception& ex) {
1315  codec->onParserError(ex.what());
1316  return 3;
1317  }
1318 }
1319 
1320 int
1321 HTTP1xCodec::onBodyCB(http_parser* parser, const char* buf, size_t len) {
1322  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1323  DCHECK(codec != nullptr);
1324  DCHECK_EQ(&codec->parser_, parser);
1325 
1326  try {
1327  return codec->onBody(buf, len);
1328  } catch (const std::exception& ex) {
1329  // Note: http_parser appears to completely ignore the return value from the
1330  // on_body() callback. There seems to be no way to abort parsing after an
1331  // error in on_body().
1332  //
1333  // We handle this by checking if error_ is set after each call to
1334  // http_parser_execute().
1335  codec->onParserError(ex.what());
1336  return 1;
1337  }
1338 }
1339 
1341  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1342  DCHECK(codec != nullptr);
1343  DCHECK_EQ(&codec->parser_, parser);
1344 
1345  try {
1346  return codec->onChunkHeader(parser->content_length);
1347  } catch (const std::exception& ex) {
1348  codec->onParserError(ex.what());
1349  return 1;
1350  }
1351 }
1352 
1354  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1355  DCHECK(codec != nullptr);
1356  DCHECK_EQ(&codec->parser_, parser);
1357 
1358  try {
1359  return codec->onChunkComplete();
1360  } catch (const std::exception& ex) {
1361  codec->onParserError(ex.what());
1362  return 1;
1363  }
1364 }
1365 
1366 int
1368  HTTP1xCodec* codec = static_cast<HTTP1xCodec*>(parser->data);
1369  DCHECK(codec != nullptr);
1370  DCHECK_EQ(&codec->parser_, parser);
1371 
1372  try {
1373  return codec->onMessageComplete();
1374  } catch (const std::exception& ex) {
1375  codec->onParserError(ex.what());
1376  return 1;
1377  }
1378 }
1379 
1381  return npn.length() == 8 && (npn == "http/1.0" || npn == "http/1.1");
1382 }
1383 
1384 } // proxygen
std::pair< CodecProtocol, std::string > upgradeResult_
Definition: HTTP1xCodec.h:173
void addFromCodec(const char *str, size_t len, std::string &&value)
Definition: HTTPHeaders.cpp:77
size_t generateTrailers(folly::IOBufQueue &writeBuf, StreamID txn, const HTTPHeaders &trailers) override
int onBody(const char *buf, size_t len)
void setHttpStatusCode(uint32_t statusCode)
Definition: HTTPException.h:86
std::string currentHeaderValue_
Definition: HTTP1xCodec.h:163
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
unsigned char flags
Definition: http_parser.h:215
bool responseBodyMustBeEmpty(unsigned status)
Definition: RFC2616.cpp:54
TransportDirection transportDirection_
Definition: HTTP1xCodec.h:171
spdy::GoawayStatusCode statusCode
Definition: SPDYCodec.cpp:110
std::unique_ptr< HTTPMessage > msg_
Definition: HTTP1xCodec.h:158
void serializeWebsocketHeader(folly::IOBufQueue &writeBuf, size_t &len, bool upstream)
virtual void onError(StreamID stream, const HTTPException &error, bool newTxn=false)=0
void setCurrentIngressBuf(std::unique_ptr< folly::IOBuf > buf)
bool isBusy() const override
virtual void onMessageBegin(StreamID stream, HTTPMessage *msg)=0
constexpr folly::StringPiece kUpgradeToken
http_data_cb on_header_field
Definition: http_parser.h:249
bool caseInsensitiveEqual(folly::StringPiece s, folly::StringPiece t)
Definition: UtilInl.h:17
static const std::pair< uint8_t, uint8_t > kHTTPVersion10
Definition: HTTPMessage.h:229
void hash_init(const EVP_MD *md)
Definition: OpenSSLHash.h:49
unsigned short http_minor
Definition: http_parser.h:225
const std::string & getAllowedUpgradeProtocols()
std::unique_ptr< HTTPMessage > upgradeRequest_
Definition: HTTP1xCodec.h:159
LogLevel max
Definition: LogLevel.cpp:31
static std::enable_if< std::is_integral< T >::value &&!std::is_same< T, bool >::value, T >::type secureRandom()
Definition: Random.h:112
virtual void onChunkHeader(StreamID, size_t)
Definition: HTTPCodec.h:148
void setAllowedUpgradeProtocols(std::list< std::string > protocols)
#define appendLiteral(queue, len, str)
Definition: HTTP1xCodec.cpp:68
const std::string & getStatusMessage() const
Definition: HTTPMessage.h:245
HeaderParseState headerParseState_
Definition: HTTP1xCodec.h:170
std::string userAgent_
Definition: HTTP1xCodec.h:165
virtual void onMessageComplete(StreamID stream, bool upgrade)=0
uint16_t getStatusCode() const
void generateHeader(folly::IOBufQueue &writeBuf, StreamID txn, const HTTPMessage &msg, bool eom=false, HTTPHeaderSize *size=nullptr) override
std::string upgradeHeader_
Definition: HTTP1xCodec.h:167
virtual void onTrailersComplete(StreamID stream, std::unique_ptr< HTTPHeaders > trailers)=0
static int onChunkHeaderCB(http_parser *parser)
static bool supportsNextProtocol(const std::string &npn)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len)
Definition: http_parser.c:602
#define LIKELY(x)
Definition: Likely.h:47
void advance(size_type n)
Definition: Range.h:672
folly::StringPiece currentHeaderNameStringPiece_
Definition: HTTP1xCodec.h:162
CodecFactory codec
int onHeaderValue(const char *buf, size_t len)
void setPartialMsg(std::unique_ptr< HTTPMessage > partialMsg)
constexpr size_type size() const
Definition: Range.h:431
bool hasHost() const
Definition: ParseURL.h:48
const uint8_t * data() const
Definition: IOBuf.h:499
void setProxygenError(ProxygenError proxygenError)
Definition: Exception.h:46
static std::string formatDateHeader()
bool is1xxResponse() const
Definition: HTTPMessage.h:316
http_data_cb on_body
Definition: http_parser.h:252
static int onMessageCompleteCB(http_parser *parser)
std::unique_ptr< IOBuf > clone() const
Definition: IOBuf.cpp:527
static int onHeaderValueCB(http_parser *parser, const char *buf, size_t len)
std::string generateWebsocketKey() const
static int onMessageBeginCB(http_parser *parser)
std::string hostAndPort() const
Definition: ParseURL.h:60
static http_parser * parser
Definition: test.c:40
http_data_cb on_url
Definition: http_parser.h:248
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
#define nullptr
Definition: http_parser.c:41
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
Definition: String-inl.h:382
static int onHeadersCompleteCB(http_parser *parser, const char *buf, size_t len)
std::pair< void *, std::size_t > preallocate(std::size_t min, std::size_t newAllocationSize, std::size_t max=std::numeric_limits< std::size_t >::max())
Definition: IOBufQueue.h:356
std::string currentHeaderName_
Definition: HTTP1xCodec.h:161
unsigned short status_code
Definition: http_parser.h:226
static int onChunkCompleteCB(http_parser *parser)
static int onUrlCB(http_parser *parser, const char *buf, size_t len)
HTTPCodec::Callback * callback_
Definition: HTTP1xCodec.h:153
ProtocolVersion version
const char * http_method_str(enum http_method m)
Definition: http_parser.c:2159
void clear()
Definition: Range.h:411
void http_parser_pause(http_parser *parser, int paused)
Definition: http_parser.c:2431
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
constexpr bool empty() const
Definition: Range.h:443
void hash_final(MutableByteRange out)
Definition: OpenSSLHash.h:62
void writeBuf(const Buf &buf, folly::io::Appender &out)
#define HTTP_PARSER_ERRNO(p)
Definition: http_parser.h:202
HTTPHeaderSize headerSize_
Definition: HTTP1xCodec.h:169
const std::string & methodToString(HTTPMethod method)
Definition: HTTPMethod.cpp:46
bool getIsChunked() const
Definition: HTTPMessage.h:80
void hash_update(ByteRange data)
Definition: OpenSSLHash.h:53
folly::Optional< std::pair< CodecProtocol, std::string > > checkForProtocolUpgrade(const std::string &clientUpgrade, const std::string &serverUpgrade, bool serverMode)
static const std::pair< uint8_t, uint8_t > kHTTPVersion11
Definition: HTTPMessage.h:230
std::size_t length() const
Definition: IOBuf.h:533
const std::string & getCodecProtocolString(CodecProtocol proto)
unsigned char method
Definition: http_parser.h:227
const char * http_errno_description(enum http_errno err)
Definition: http_parser.c:2186
unsigned short http_major
Definition: http_parser.h:224
void addDateHeader(folly::IOBufQueue &writeBuf, size_t &len)
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
http_data_cb on_headers_complete
Definition: http_parser.h:251
bool isReusable() const override
size_t onIngress(const folly::IOBuf &buf) override
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
static int onReasonCB(http_parser *parser, const char *buf, size_t len)
std::unique_ptr< IOBuf > cloneOne() const
Definition: IOBuf.cpp:531
http_data_cb on_reason
Definition: http_parser.h:254
static int onBodyCB(http_parser *parser, const char *buf, size_t len)
static const char *const value
Definition: Conv.cpp:50
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
constexpr folly::StringPiece kWSMagicString
bool isParsingHeaderOrTrailerName() const
Definition: HTTP1xCodec.h:123
void http_parser_init(http_parser *parser, enum http_parser_type t)
Definition: http_parser.c:2166
auto start
bool isParsingHeaders() const
Definition: HTTP1xCodec.h:117
int onHeaderField(const char *buf, size_t len)
constexpr Iter end() const
Definition: Range.h:455
int onHeadersComplete(size_t len)
http_data_cb on_header_value
Definition: http_parser.h:250
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
void onParserError(const char *what=nullptr)
constexpr Iter begin() const
Definition: Range.h:452
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
std::string allowedNativeUpgrades_
Definition: HTTP1xCodec.h:168
virtual void onHeadersComplete(StreamID stream, std::unique_ptr< HTTPMessage > msg)=0
void * data
Definition: http_parser.h:242
const char * string
Definition: Conv.cpp:212
g_t g(f_t)
http_errno
Definition: http_parser.h:196
StringPiece trimWhitespace(StringPiece sp)
Definition: String.h:568
const std::string & getMethodString() const
void setParserPaused(bool paused) override
std::string websockAcceptKey_
Definition: HTTP1xCodec.h:103
int onReason(const char *buf, size_t len)
void pushHeaderNameAndValue(HTTPHeaders &hdrs)
uint64_t StreamID
Definition: HTTPCodec.h:49
size_t generateRstStream(folly::IOBufQueue &writeBuf, StreamID txn, ErrorCode statusCode) override
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
Definition: String-inl.h:498
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
constexpr folly::StringPiece kUpgradeConnectionToken
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
KeepaliveRequested keepaliveRequested_
Definition: HTTP1xCodec.h:172
folly::Function< void()> callback_
static int onHeaderFieldCB(http_parser *parser, const char *buf, size_t len)
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
virtual void onChunkComplete(StreamID)
Definition: HTTPCodec.h:156
static const char * getDefaultReason(uint16_t status)
folly::Optional< HTTPMethod > getMethod() const
std::string generateWebsocketAccept(const std::string &acceptKey) const
Range< const char * > StringPiece
StreamID createStream() override
const std::string & getURL() const
Definition: HTTPMessage.h:205
size_t generateEOM(folly::IOBufQueue &writeBuf, StreamID txn) override
int onURL(const char *buf, size_t len)
void postallocate(std::size_t n)
Definition: IOBufQueue.h:380
std::unique_ptr< HTTPHeaders > trailers_
Definition: HTTP1xCodec.h:160
virtual void onBody(StreamID stream, std::unique_ptr< folly::IOBuf > chain, uint16_t padding)=0
const folly::IOBuf * currentIngressBuf_
Definition: HTTP1xCodec.h:157
size_t generateGoaway(folly::IOBufQueue &writeBuf, StreamID lastStream, ErrorCode statusCode, std::unique_ptr< folly::IOBuf > debugData=nullptr) override
static std::string encode(folly::ByteRange buffer)
Definition: Base64.cpp:80
int onChunkHeader(size_t len)
void forEachWithCode(LAMBDA func) const
Definition: HTTPHeaders.h:346
int64_t content_length
Definition: http_parser.h:221
bool isEgressWebsocketUpgrade() const
Definition: HTTPMessage.h:72
HTTP1xCodec(TransportDirection direction, bool forceUpstream1_1=false)
Definition: HTTP1xCodec.cpp:81
void onIngressEOF() override
http_cb on_message_complete
Definition: http_parser.h:253
static const http_parser_settings * getParserSettings()
void reset(Iter start, size_type size)
Definition: Range.h:421
size_t generateChunkHeader(folly::IOBufQueue &writeBuf, StreamID txn, size_t length) override
size_t generateBody(folly::IOBufQueue &writeBuf, StreamID txn, std::unique_ptr< folly::IOBuf > chain, folly::Optional< uint8_t > padding, bool eom) override
bool wantsKeepalive() const
Definition: HTTPMessage.h:346
size_t generateChunkTerminator(folly::IOBufQueue &writeBuf, StreamID txn) override
virtual bool onNativeProtocolUpgrade(StreamID, CodecProtocol, const std::string &, HTTPMessage &)
Definition: HTTPCodec.h:271
const std::pair< uint8_t, uint8_t > & getHTTPVersion() const
def next(obj)
Definition: ast.py:58
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71