proxygen
HTTPMessage.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 <boost/algorithm/string.hpp>
13 #include <folly/Format.h>
14 #include <folly/Range.h>
16 #include <string>
17 #include <vector>
18 
19 using folly::IOBuf;
20 using folly::Optional;
21 using folly::StringPiece;
22 using std::pair;
23 using std::string;
24 using std::unique_ptr;
25 
26 namespace {
27 const string kHeaderStr_ = "header.";
28 const string kQueryStr_ = "query.";
29 const string kCookieStr = "cookie.";
30 
37 std::locale defaultLocale;
38 }
39 
40 namespace proxygen {
41 
44 
45 const pair<uint8_t, uint8_t> HTTPMessage::kHTTPVersion10(1, 0);
46 const pair<uint8_t, uint8_t> HTTPMessage::kHTTPVersion11(1, 1);
47 
49  // Some code paths end up recyling a single HTTPMessage instance for multiple
50  // requests, and adding their own per-hop headers each time. In that case, we
51  // don't want to accumulate these headers.
53 
54  if (!trailersAllowed_) {
55  // Because stripPerHopHeaders can be called multiple times, don't
56  // let subsequent instances clear this flag
58  }
59 
61 }
62 
65  seqNo_(-1),
66  localIP_(),
67  versionStr_("1.0"),
68  fields_(),
69  version_(1,0),
71  parsedCookies_(false), parsedQueryParams_(false),
72  chunked_(false), upgraded_(false), wantsKeepalive_(true),
73  trailersAllowed_(false), secure_(false),
75 }
76 
78 }
79 
81  startTime_(message.startTime_),
82  seqNo_(message.seqNo_),
83  dstAddress_(message.dstAddress_),
84  dstIP_(message.dstIP_),
85  dstPort_(message.dstPort_),
86  localIP_(message.localIP_),
87  versionStr_(message.versionStr_),
88  fields_(message.fields_),
89  cookies_(message.cookies_),
90  queryParams_(message.queryParams_),
91  version_(message.version_),
92  headers_(message.headers_),
94  sslVersion_(message.sslVersion_),
95  sslCipher_(message.sslCipher_),
96  protoStr_(message.protoStr_),
97  pri_(message.pri_),
98  h2Pri_(message.h2Pri_),
101  chunked_(message.chunked_),
102  upgraded_(message.upgraded_),
105  secure_(message.secure_),
107  if (message.trailers_) {
108  trailers_ = std::make_unique<HTTPHeaders>(*message.trailers_);
109  }
110 }
111 
130  pri_(message.pri_),
140 }
141 
143  if (&message == this) {
144  return *this;
145  }
146  startTime_ = message.startTime_;
147  seqNo_ = message.seqNo_;
148  dstAddress_ = message.dstAddress_;
149  dstIP_ = message.dstIP_;
150  dstPort_ = message.dstPort_;
151  localIP_ = message.localIP_;
152  versionStr_ = message.versionStr_;
153  fields_ = message.fields_;
154  cookies_ = message.cookies_;
155  queryParams_ = message.queryParams_;
156  version_ = message.version_;
157  headers_ = message.headers_;
159  sslVersion_ = message.sslVersion_;
160  sslCipher_ = message.sslCipher_;
161  protoStr_ = message.protoStr_;
162  pri_ = message.pri_;
163  h2Pri_ = message.h2Pri_;
164  parsedCookies_ = message.parsedCookies_;
166  chunked_ = message.chunked_;
167  upgraded_ = message.upgraded_;
170  secure_ = message.secure_;
172 
173  if (message.trailers_) {
174  trailers_ = std::make_unique<HTTPHeaders>(*message.trailers_);
175  } else {
176  trailers_.reset();
177  }
178  return *this;
179 }
180 
182  if (&message == this) {
183  return *this;
184  }
185  startTime_ = message.startTime_;
186  seqNo_ = message.seqNo_;
187  dstAddress_ = std::move(message.dstAddress_);
188  dstIP_ = std::move(message.dstIP_);
189  dstPort_ = message.dstPort_;
190  localIP_ = std::move(message.localIP_);
191  versionStr_ = std::move(message.versionStr_);
192  fields_ = std::move(message.fields_);
193  cookies_ = std::move(message.cookies_);
194  queryParams_ = std::move(message.queryParams_);
195  version_ = message.version_;
196  headers_ = std::move(message.headers_);
197  strippedPerHopHeaders_ = std::move(message.strippedPerHopHeaders_);
198  sslVersion_ = message.sslVersion_;
199  sslCipher_ = message.sslCipher_;
200  protoStr_ = message.protoStr_;
201  pri_ = message.pri_;
202  h2Pri_ = message.h2Pri_;
203  parsedCookies_ = message.parsedCookies_;
204  parsedQueryParams_ = message.parsedQueryParams_;
205  chunked_ = message.chunked_;
206  upgraded_ = message.upgraded_;
207  wantsKeepalive_ = message.wantsKeepalive_;
208  trailersAllowed_ = message.trailersAllowed_;
209  secure_ = message.secure_;
210  upgradeWebsocket_ = message.upgradeWebsocket_;
211 
212  trailers_ = std::move(message.trailers_);
213  return *this;
214 }
215 
217  Request& req = request();
218  req.method_ = method;
219 }
220 
222  VLOG(9) << "setMethod: " << method;
223  Request& req = request();
225  if (result) {
226  req.method_ = *result;
227  } else {
228  req.method_ = method.str();
229  auto& storedMethod = boost::get<std::string>(req.method_);
230  std::transform(storedMethod.begin(), storedMethod.end(),
231  storedMethod.begin(), ::toupper);
232  }
233 }
234 
236  const auto& req = request();
237  if (req.method_.which() == 2) {
238  return boost::get<HTTPMethod>(req.method_);
239  }
240  return folly::none;
241 }
242 
247  const auto& req = request();
248  if (req.method_.which() == 1) {
249  return boost::get<std::string>(req.method_);
250  } else if (req.method_.which() == 2) {
251  return methodToString(boost::get<HTTPMethod>(req.method_));
252  }
253  return empty_string;
254 }
255 
257  version_.first = maj;
258  version_.second = min;
259  versionStr_ = folly::to<string>(maj, ".", min);
260 }
261 
262 const pair<uint8_t, uint8_t>& HTTPMessage::getHTTPVersion() const {
263  return version_;
264 }
265 
269  if (value.length() > 0) {
270  int64_t max_forwards = 0;
271  try {
272  max_forwards = folly::to<int64_t>(value);
273  } catch (const std::range_error& ex) {
274  return 400;
275  }
276 
277  if (max_forwards < 0) {
278  return 400;
279  } else if (max_forwards == 0) {
280  return 501;
281  } else {
283  folly::to<string>(max_forwards - 1));
284  }
285  }
286  }
287  return 0;
288 }
289 
291  return version_ == kHTTPVersion10;
292 }
293 
295  return version_ == kHTTPVersion11;
296 }
297 
298 namespace {
299 struct FormattedDate {
300  time_t lastTime{0};
301  string date;
302 
303  string formatDate() {
304  const auto now = std::chrono::system_clock::to_time_t(
306 
307  if (now != lastTime) {
308  char buff[1024];
309  tm timeTupple;
310  gmtime_r(&now, &timeTupple);
311 
312  strftime(buff, 1024, "%a, %d %b %Y %H:%M:%S %Z", &timeTupple);
313  date = std::string(buff);
314  lastTime = now;
315  }
316  return date;
317  }
318 };
319 }
320 
322  struct DateTag {};
324  return obj.formatDate();
325 }
326 
330  getDstAddress().getFamily() == AF_INET6
331  ? '[' + getDstIP() + ']' : getDstIP());
332  }
333 }
334 
336  response().status_ = status;
337  response().statusStr_ = folly::to<string>(status);
338 }
339 
341  return response().status_;
342 }
343 
345  request().pushStatus_ = status;
346  request().pushStatusStr_ = folly::to<string>(status);
347 }
348 
350  return request().pushStatusStr_;
351 }
352 
354  return request().pushStatus_;
355 }
356 
357 void
358 HTTPMessage::constructDirectResponse(const pair<uint8_t,uint8_t>& version,
359  const int statusCode,
360  const string& statusMsg,
361  int contentLength) {
362  setStatusCode(statusCode);
363  setStatusMessage(statusMsg);
364  constructDirectResponse(version, contentLength);
365 }
366 
367 void
368 HTTPMessage::constructDirectResponse(const pair<uint8_t,uint8_t>& version,
369  int contentLength) {
370  setHTTPVersion(version.first, version.second);
371 
372  headers_.set(HTTP_HEADER_CONTENT_LENGTH, folly::to<string>(contentLength));
373 
375  headers_.add(HTTP_HEADER_CONTENT_TYPE, "text/plain");
376  }
377  setIsChunked(false);
378  setIsUpgraded(false);
379 }
380 
382  DCHECK(!parsedCookies_);
383  parsedCookies_ = true;
384 
386  [&](const string& headerval) {
387  splitNameValuePieces(headerval, ';', '=',
388  [this](StringPiece cookieName, StringPiece cookieValue) {
389  cookies_.emplace(cookieName, cookieValue);
390  });
391 
392  return false; // continue processing "cookie" headers
393  });
394 }
395 
397  cookies_.clear();
398  parsedCookies_ = false;
399 }
400 
401 const StringPiece HTTPMessage::getCookie(const string& name) const {
402  // clear previous parsed cookies. They might store raw pointers to a vector
403  // in headers_, which can resize on add()
404  // Parse the cookies if we haven't done so yet
405  unparseCookies();
406  if (!parsedCookies_) {
407  parseCookies();
408  }
409 
410  auto it = cookies_.find(name);
411  if (it == cookies_.end()) {
412  return StringPiece();
413  } else {
414  return it->second;
415  }
416 }
417 
419  DCHECK(!parsedQueryParams_);
420  const Request& req = request();
421 
422  parsedQueryParams_ = true;
423  if (req.query_.empty()) {
424  return;
425  }
426 
427  splitNameValue(req.query_, '&', '=',
428  [this] (string&& paramName, string&& paramValue) {
429 
430  auto it = queryParams_.find(paramName);
431  if (it == queryParams_.end()) {
432  queryParams_.emplace(std::move(paramName), std::move(paramValue));
433  } else {
434  // We have some unit tests that make sure we always return the last
435  // value when there are duplicate parameters. I don't think this really
436  // matters, but for now we might as well maintain the same behavior.
437  it->second = std::move(paramValue);
438  }
439  });
440 }
441 
443  queryParams_.clear();
444  parsedQueryParams_ = false;
445 }
446 
447 const string* HTTPMessage::getQueryParamPtr(const string& name) const {
448  // Parse the query parameters if we haven't done so yet
449  if (!parsedQueryParams_) {
451  }
452 
453  auto it = queryParams_.find(name);
454  if (it == queryParams_.end()) {
455  return nullptr;
456  }
457  return &it->second;
458 }
459 
460 bool HTTPMessage::hasQueryParam(const string& name) const {
461  return getQueryParamPtr(name) != nullptr;
462 }
463 
464 const string& HTTPMessage::getQueryParam(const string& name) const {
465  const string* ret = getQueryParamPtr(name);
466  return ret ? *ret : empty_string;
467 }
468 
470  return folly::to<int>(getQueryParam(name));
471 }
472 
473 int HTTPMessage::getIntQueryParam(const std::string& name, int defval) const {
474  try {
475  return getIntQueryParam(name);
476  } catch (const std::exception& ex) {
477  }
478 
479  return defval;
480 }
481 
483  auto val = getQueryParam(name);
484 
485  std::string result;
486  try {
488  } catch (const std::exception& ex) {
489  LOG(WARNING) << "Invalid escaped query param: " << folly::exceptionStr(ex);
490  }
491  return result;
492 }
493 
494 const std::map<std::string, std::string>& HTTPMessage::getQueryParams() const {
495  // Parse the query parameters if we haven't done so yet
496  if (!parsedQueryParams_) {
498  }
499  return queryParams_;
500 }
501 
503  ParseURL u(request().url_);
504 
505  if (u.valid()) {
506  // Recreate the URL by just changing the query string
507  request().url_ = createUrl(u.scheme(),
508  u.authority(),
509  u.path(),
510  query, // new query string
511  u.fragment());
512  request().query_ = query;
513  return true;
514  }
515 
516  VLOG(4) << "Error parsing URL during setQueryString: " << request().url_;
517  return false;
518 }
519 
521  // Parse the query parameters if we haven't done so yet
522  if (!parsedQueryParams_) {
524  }
525 
526  if (!queryParams_.erase(name)) {
527  // Query param was not found.
528  return false;
529  }
530 
531  auto query = createQueryString(queryParams_, request().query_.length());
532  return setQueryString(query);
533 }
534 
536  const std::string& value) {
537  // Parse the query parameters if we haven't done so yet
538  if (!parsedQueryParams_) {
540  }
541 
543  auto query = createQueryString(queryParams_, request().query_.length());
544  return setQueryString(query);
545 }
546 
548  const std::map<std::string, std::string>& params, uint32_t maxLength) {
549  std::string query;
550  query.reserve(maxLength);
551  for (auto it = params.begin(); it != params.end(); it++) {
552  if (it != params.begin()) {
553  query.append("&");
554  }
555  query.append(it->first + "=" + it->second);
556  }
557  query.shrink_to_fit();
558  return query;
559 }
560 
562  const folly::StringPiece authority,
563  const folly::StringPiece path,
564  const folly::StringPiece query,
565  const folly::StringPiece fragment) {
566  std::string url;
567  url.reserve(scheme.size() + authority.size() + path.size() + query.size() +
568  fragment.size() + 5); // 5 chars for ://,? and #
569  if (!scheme.empty()) {
570  folly::toAppend(scheme.str(), "://", &url);
571  }
572  folly::toAppend(authority, path, &url);
573  if (!query.empty()) {
574  folly::toAppend('?', query, &url);
575  }
576  if (!fragment.empty()) {
577  folly::toAppend('#', fragment, &url);
578  }
579  url.shrink_to_fit();
580  return url;
581 }
582 
584  const string& input,
585  char pairDelim,
586  char valueDelim,
587  std::function<void(StringPiece, StringPiece)> callback) {
588 
589  StringPiece sp(input);
590  while (!sp.empty()) {
591  size_t pairDelimPos = sp.find(pairDelim);
592  StringPiece keyValue;
593 
594  if (pairDelimPos == string::npos) {
595  keyValue = sp;
596  sp.advance(sp.size());
597  } else {
598  keyValue = sp.subpiece(0, pairDelimPos);
599  // Skip '&' char
600  sp.advance(pairDelimPos + 1);
601  }
602 
603  if (keyValue.empty()) {
604  continue;
605  }
606 
607  size_t valueDelimPos = keyValue.find(valueDelim);
608  if (valueDelimPos == string::npos) {
609  // Key only query param
610  callback(trim(keyValue), StringPiece());
611  } else {
612  auto name = keyValue.subpiece(0, valueDelimPos);
613  auto value = keyValue.subpiece(valueDelimPos + 1);
614  callback(trim(name), trim(value));
615  }
616  }
617 }
618 
620  // TODO: use a library function from boost?
621  for (; !sp.empty() && sp.front() == ' '; sp.pop_front()) {
622  }
623  for (; !sp.empty() && sp.back() == ' '; sp.pop_back()) {
624  }
625  return sp;
626 }
627 
629  const string& input,
630  char pairDelim,
631  char valueDelim,
632  std::function<void(string&&, string&&)> callback) {
633 
634  folly::StringPiece sp(input);
635  while (!sp.empty()) {
636  size_t pairDelimPos = sp.find(pairDelim);
637  folly::StringPiece keyValue;
638 
639  if (pairDelimPos == string::npos) {
640  keyValue = sp;
641  sp.advance(sp.size());
642  } else {
643  keyValue = sp.subpiece(0, pairDelimPos);
644  // Skip '&' char
645  sp.advance(pairDelimPos + 1);
646  }
647 
648  if (keyValue.empty()) {
649  continue;
650  }
651 
652  size_t valueDelimPos = keyValue.find(valueDelim);
653  if (valueDelimPos == string::npos) {
654  // Key only query param
655  string name = keyValue.str();
656  string value;
657 
658  boost::trim(name, defaultLocale);
659  callback(std::move(name), std::move(value));
660  } else {
661  string name = keyValue.subpiece(0, valueDelimPos).str();
662  string value = keyValue.subpiece(valueDelimPos + 1).str();
663 
664  boost::trim(name, defaultLocale);
665  boost::trim(value, defaultLocale);
666  callback(std::move(name), std::move(value));
667  }
668  }
669 }
670 
671 std::ostream& operator<<(std::ostream& os, const HTTPMessage& msg) {
672  msg.describe(os);
673  return os;
674 }
675 
676 void HTTPMessage::dumpMessage(int vlogLevel) const {
677  VLOG(vlogLevel) << *this;
678 }
679 
680 void HTTPMessage::describe(std::ostream& os) const {
681  os << ", chunked: " << chunked_
682  << ", upgraded: " << upgraded_
683  << ", Fields for message:" << std::endl;
684 
685  // Common fields to both requests and responses.
686  std::vector<std::pair<const char*, const std::string*>> fields {{
687  {"local_ip", &localIP_},
688  {"version", &versionStr_},
689  {"dst_ip", &dstIP_},
690  {"dst_port", &dstPort_},
691  }};
692 
693  if (fields_.type() == typeid(Request)) {
694  // Request fields.
695  const Request& req = request();
696  fields.push_back(make_pair("client_ip", &req.clientIP_));
697  fields.push_back(make_pair("client_port", &req.clientPort_));
698  fields.push_back(make_pair("method", &getMethodString()));
699  fields.push_back(make_pair("path", &req.path_));
700  fields.push_back(make_pair("query", &req.query_));
701  fields.push_back(make_pair("url", &req.url_));
702  fields.push_back(make_pair("push_status", &req.pushStatusStr_));
703  } else if (fields_.type() == typeid(Response)) {
704  // Response fields.
705  const Response& resp = response();
706  fields.push_back(make_pair("status", &resp.statusStr_));
707  fields.push_back(make_pair("status_msg", &resp.statusMsg_));
708  }
709 
710  for (auto field : fields) {
711  if (!field.second->empty()) {
712  os << " " << field.first
713  << ":" << stripCntrlChars(*field.second) << std::endl;
714  }
715  }
716 
717  headers_.forEach([&] (const string& h, const string& v) {
718  os << " " << stripCntrlChars(h) << ": "
719  << stripCntrlChars(v) << std::endl;
720  });
721  if (strippedPerHopHeaders_.size() > 0) {
722  os << "Per-Hop Headers" << std::endl;
723  strippedPerHopHeaders_.forEach([&] (const string& h, const string& v) {
724  os << " " << stripCntrlChars(h) << ": "
725  << stripCntrlChars(v) << std::endl;
726  });
727  }
728 }
729 
730 void
731 HTTPMessage::atomicDumpMessage(int vlogLevel) const {
732  std::lock_guard<std::mutex> g(mutexDump_);
733  dumpMessage(vlogLevel);
734 }
735 
736 void HTTPMessage::dumpMessageToSink(google::LogSink* logSink) const {
737  LOG_TO_SINK(logSink, INFO) << *this;
738 }
739 
741  if (version_.first < 1) {
742  return false;
743  }
744 
745  // RFC 2616 isn't explicitly clear about whether "close" is case-sensitive.
746  // Section 2.1 states that literal tokens in the BNF are case-insensitive
747  // unless stated otherwise. The "close" token isn't explicitly mentioned
748  // in the BNF, but other header fields such as the character set and
749  // content coding are explicitly called out as being case insensitive.
750  //
751  // We'll treat the "close" token case-insensitively. This is the most
752  // conservative approach, since disabling keepalive when it was requested
753  // is better than enabling keepalive for a client that didn't expect it.
754  //
755  // Note that we only perform ASCII lowering here. This is good enough,
756  // since the token we are looking for is ASCII.
757  if (checkForHeaderToken(HTTP_HEADER_CONNECTION, "close", false)) {
758  // The Connection header contained a "close" token, so keepalive
759  // is disabled.
760  return false;
761  }
762 
763  const std::string kKeepAliveConnToken = "keep-alive";
764  if (version_ == kHTTPVersion10) {
765  // HTTP 1.0 persistent connections require a Connection: Keep-Alive
766  // header to be present for the connection to be persistent.
768  HTTP_HEADER_CONNECTION, kKeepAliveConnToken.c_str(), false) ||
771  kKeepAliveConnToken.c_str(),
772  false)) {
773  return true;
774  }
775  return false;
776  }
777 
778  // It's a keepalive connection.
779  return true;
780 }
781 
783  char const* token,
784  bool caseSensitive) const {
785  return doHeaderTokenCheck(headers_, headerCode, token, caseSensitive);
786 }
787 
789  const HTTPHeaderCode headerCode,
790  char const* token,
791  bool caseSensitive) const {
792  StringPiece tokenPiece(token);
793  string lowerToken;
794  if (!caseSensitive) {
795  lowerToken = token;
796  boost::to_lower(lowerToken, defaultLocale);
797  tokenPiece.reset(lowerToken);
798  }
799 
800  // Search through all of the headers with this name.
801  // forEachValueOfHeader will return true iff it was "broken" prematurely
802  // with "return true" in the lambda-function
803  return headers.forEachValueOfHeader(headerCode, [&] (const string& value) {
804  string lower;
805  // Use StringPiece, since it implements a faster find() than std::string
806  StringPiece headerValue;
807  if (caseSensitive) {
808  headerValue.reset(value);
809  } else {
810  // TODO: We only perform ASCII lowering right now. Technically the
811  // headers could contain data in other encodings, if encoded according
812  // to RFC 2047 (encoded strings will start with "=?").
813  lower = value;
814  boost::to_lower(lower, defaultLocale);
815  headerValue.reset(lower);
816  }
817 
818  // Look for the specified token
819  size_t idx = 0;
820  size_t end = headerValue.size();
821  while (idx < end) {
822  idx = headerValue.find(tokenPiece, idx);
823  if (idx == string::npos) {
824  break;
825  }
826 
827  // Search backwards to make sure we found the value at the beginning
828  // of a token.
829  bool at_token_start = false;
830  size_t prev = idx;
831  while (true) {
832  if (prev == 0) {
833  at_token_start = true;
834  break;
835  }
836  --prev;
837  char c = headerValue[prev];
838  if (c == ',') {
839  at_token_start = true;
840  break;
841  }
842  if (!isLWS(c)) {
843  // not at a token start
844  break;
845  }
846  }
847  if (!at_token_start) {
848  idx += 1;
849  continue;
850  }
851 
852  // Search forwards to see if we found the value at the end of a token
853  bool at_token_end = false;
854  size_t next = idx + tokenPiece.size();
855  while (true) {
856  if (next >= end) {
857  at_token_end = true;
858  break;
859  }
860  char c = headerValue[next];
861  if (c == ',') {
862  at_token_end = true;
863  break;
864  }
865  if (!isLWS(c)) {
866  // not at a token end
867  break;
868  }
869  ++next;
870  }
871  if (at_token_end) {
872  // We found the token we're looking for
873  return true;
874  }
875 
876  idx += 1;
877  }
878  return false; // keep processing
879  });
880 }
881 
883  switch (status) {
884  case 100: return "Continue";
885  case 101: return "Switching Protocols";
886  case 200: return "OK";
887  case 201: return "Created";
888  case 202: return "Accepted";
889  case 203: return "Non-Authoritative Information";
890  case 204: return "No Content";
891  case 205: return "Reset Content";
892  case 206: return "Partial Content";
893  case 300: return "Multiple Choices";
894  case 301: return "Moved Permanently";
895  case 302: return "Found";
896  case 303: return "See Other";
897  case 304: return "Not Modified";
898  case 305: return "Use Proxy";
899  case 307: return "Temporary Redirect";
900  case 400: return "Bad Request";
901  case 401: return "Unauthorized";
902  case 402: return "Payment Required";
903  case 403: return "Forbidden";
904  case 404: return "Not Found";
905  case 405: return "Method Not Allowed";
906  case 406: return "Not Acceptable";
907  case 407: return "Proxy Authentication Required";
908  case 408: return "Request Timeout";
909  case 409: return "Conflict";
910  case 410: return "Gone";
911  case 411: return "Length Required";
912  case 412: return "Precondition Failed";
913  case 413: return "Request Entity Too Large";
914  case 414: return "Request-URI Too Long";
915  case 415: return "Unsupported Media Type";
916  case 416: return "Requested Range Not Satisfiable";
917  case 417: return "Expectation Failed";
918  case 418: return "I'm a teapot";
919  case 500: return "Internal Server Error";
920  case 501: return "Not Implemented";
921  case 502: return "Bad Gateway";
922  case 503: return "Service Unavailable";
923  case 504: return "Gateway Timeout";
924  case 505: return "HTTP Version Not Supported";
925  }
926 
927  // Note: Some Microsoft clients behave badly if the reason string
928  // is left empty. Therefore return a non-empty string here.
929  return "-";
930 }
931 
932 } // proxygen
std::string authority() const
Definition: ParseURL.h:44
static void splitNameValuePieces(const std::string &input, char pairDelim, char valueDelim, std::function< void(folly::StringPiece, folly::StringPiece)> callback)
folly::Optional< HTTPMethod > stringToMethod(folly::StringPiece method)
Definition: HTTPMethod.cpp:37
HTTPHeaders strippedPerHopHeaders_
Definition: HTTPMessage.h:808
bool isLWS(char c)
Definition: HTTPHeaders.h:31
Definition: test.c:42
std::unique_ptr< HTTPHeaders > trailers_
Definition: HTTPMessage.h:810
std::string stripCntrlChars(const Str &str)
Definition: HTTPMessage.h:842
*than *hazptr_holder h
Definition: Hazptr.h:116
spdy::GoawayStatusCode statusCode
Definition: SPDYCodec.cpp:110
bool exists(folly::StringPiece name) const
Definition: HTTPHeaders.cpp:86
void atomicDumpMessage(int verbosity) const
std::string str() const
Definition: Range.h:591
HTTPMessage & operator=(const HTTPMessage &message)
static const std::pair< uint8_t, uint8_t > kHTTPVersion10
Definition: HTTPMessage.h:229
std::ostream & operator<<(std::ostream &os, const HeaderTable &table)
bool isHTTP1_1() const
Map field(FieldType Class::*field)
Definition: Base.h:641
static folly::StringPiece trim(folly::StringPiece sp)
static std::string createQueryString(const std::map< std::string, std::string > &params, uint32_t maxSize)
void uriUnescape(StringPiece str, String &out, UriEscapeMode mode)
Definition: String-inl.h:201
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
const folly::SocketAddress & getDstAddress() const
Definition: HTTPMessage.h:132
uint16_t getStatusCode() const
fbstring exceptionStr(const std::exception &e)
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
size_type find(const_range_type str) const
Definition: Range.h:721
void advance(size_type n)
Definition: Range.h:672
const std::string * protoStr_
Definition: HTTPMessage.h:814
STL namespace.
bool doHeaderTokenCheck(const HTTPHeaders &headers_, const HTTPHeaderCode headerCode, char const *token, bool caseSensitive) const
constexpr size_type size() const
Definition: Range.h:431
double val
Definition: String.cpp:273
static std::string formatDateHeader()
void stripPerHopHeaders(HTTPHeaders &strippedHeaders)
boost::variant< boost::blank, std::string, HTTPMethod > method_
Definition: HTTPMessage.h:737
requires E e noexcept(noexcept(s.error(std::move(e))))
PUSHMI_INLINE_VAR constexpr detail::transform_fn transform
Definition: transform.h:158
#define nullptr
Definition: http_parser.c:41
static void splitNameValue(const std::string &input, char pairDelim, char valueDelim, std::function< void(std::string &&, std::string &&)> callback)
void setPushStatusCode(const uint16_t status)
string date
void constructDirectResponse(const std::pair< uint8_t, uint8_t > &version, const int statusCode, const std::string &statusMsg, int contentLength=0)
void dumpMessageToSink(google::LogSink *logSink) const
bool computeKeepalive() const
ProtocolVersion version
bool forEachValueOfHeader(folly::StringPiece name, LAMBDA func) const
Definition: HTTPHeaders.h:355
void setIsChunked(bool chunked)
Definition: HTTPMessage.h:79
const char * name
Definition: http_parser.c:437
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
const folly::StringPiece getCookie(const std::string &name) const
const std::string & getQueryParam(const std::string &name) const
constexpr bool empty() const
Definition: Range.h:443
bool checkForHeaderToken(const HTTPHeaderCode headerCode, char const *token, bool caseSensitive) const
constexpr Params params[]
LogLevel min
Definition: LogLevel.cpp:30
const std::string & methodToString(HTTPMethod method)
Definition: HTTPMethod.cpp:46
WebSocketUpgrade upgradeWebsocket_
Definition: HTTPMessage.h:831
folly::Optional< HTTPPriority > h2Pri_
Definition: HTTPMessage.h:816
void parseCookies() const
const char * sslCipher_
Definition: HTTPMessage.h:813
const std::string * getQueryParamPtr(const std::string &name) const
std::pair< uint8_t, uint8_t > version_
Definition: HTTPMessage.h:806
std::map< folly::StringPiece, folly::StringPiece > cookies_
Definition: HTTPMessage.h:802
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
uint16_t getPushStatusCode() const
folly::StringPiece path() const
Definition: ParseURL.h:68
static const std::pair< uint8_t, uint8_t > kHTTPVersion11
Definition: HTTPMessage.h:230
Range subpiece(size_type first, size_type length=npos) const
Definition: Range.h:686
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
int getIntQueryParam(const std::string &name) const
std::string versionStr_
Definition: HTTPMessage.h:757
static const char *const value
Definition: Conv.cpp:50
static const int8_t kMaxPriority
Definition: HTTPMessage.h:574
bool setQueryParam(const std::string &name, const std::string &value)
static std::string createUrl(const folly::StringPiece scheme, const folly::StringPiece authority, const folly::StringPiece path, const folly::StringPiece query, const folly::StringPiece fragment)
void toAppend(char value, Tgt *result)
Definition: Conv.h:406
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
void setIsUpgraded(bool upgraded)
Definition: HTTPMessage.h:85
std::string dstPort_
Definition: HTTPMessage.h:754
const std::string & getPushStatusStr() const
bool setQueryString(const std::string &query)
std::string localIP_
Definition: HTTPMessage.h:756
void setMethod(HTTPMethod method)
boost::variant< boost::blank, Request, Response > fields_
Definition: HTTPMessage.h:759
size_t size() const
bool valid() const
Definition: ParseURL.h:80
std::string getDecodedQueryParam(const std::string &name) const
void describe(std::ostream &os) const
const std::string empty_string
Definition: HTTPHeaders.cpp:23
FOLLY_EXPORT static FOLLY_ALWAYS_INLINE T & get()
std::mutex mutex
bool removeQueryParam(const std::string &name)
const char * string
Definition: Conv.cpp:212
folly::SocketAddress dstAddress_
Definition: HTTPMessage.h:752
g_t g(f_t)
bool hasQueryParam(const std::string &name) const
void parseQueryParams() const
std::chrono::time_point< ClockType > getCurrentTime()
Definition: Time.h:41
const std::string & getMethodString() const
void setHTTPVersion(uint8_t major, uint8_t minor)
Response & response()
Definition: HTTPMessage.h:779
bool isHTTP1_0() const
std::map< std::string, std::string > queryParams_
Definition: HTTPMessage.h:804
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
static const char * getDefaultReason(uint16_t status)
folly::Optional< HTTPMethod > getMethod() const
Range< const char * > StringPiece
const std::map< std::string, std::string > & getQueryParams() const
char c
static std::mutex mutexDump_
Definition: HTTPMessage.h:829
void dumpMessage(int verbosity) const
folly::StringPiece scheme() const
Definition: ParseURL.h:40
void unparseCookies() const
HTTPHeaders headers_
Definition: HTTPMessage.h:807
constexpr None none
Definition: Optional.h:87
void reset(Iter start, size_type size)
Definition: Range.h:421
const std::string & getDstIP() const
Definition: HTTPMessage.h:136
time_t lastTime
const std::pair< uint8_t, uint8_t > & getHTTPVersion() const
def next(obj)
Definition: ast.py:58
folly::StringPiece fragment() const
Definition: ParseURL.h:76
void setStatusCode(uint16_t status)