proxygen
proxygen::CodecUtil Class Reference

#include <CodecUtil.h>

Public Types

enum  CtlEscapeMode { COMPLIANT, STRICT }
 

Static Public Member Functions

static bool validateURL (folly::ByteRange url)
 
static bool validateMethod (folly::ByteRange method)
 
static bool validateHeaderName (folly::ByteRange name)
 
static bool validateHeaderValue (folly::ByteRange value, CtlEscapeMode mode)
 
static bool hasGzipAndDeflate (const std::string &value, bool &hasGzip, bool &hasDeflate)
 
static std::vector< compress::HeaderprepareMessageForCompression (const HTTPMessage &msg, std::vector< std::string > &temps)
 
static bool appendHeaders (const HTTPHeaders &inputHeaders, std::vector< compress::Header > &headers, HTTPHeaderCode headerToCheck)
 

Static Public Attributes

static const char http_tokens [256]
 

Detailed Description

Definition at line 23 of file CodecUtil.h.

Member Enumeration Documentation

RFC2616 allows certain control chars in header values if they are quoted and escaped. When mode is COMPLIANT, then this is allowed. When mode is STRICT, no escaped CTLs are allowed

Enumerator
COMPLIANT 
STRICT 

Definition at line 61 of file CodecUtil.h.

Member Function Documentation

bool proxygen::CodecUtil::appendHeaders ( const HTTPHeaders inputHeaders,
std::vector< compress::Header > &  headers,
HTTPHeaderCode  headerToCheck 
)
static

Definition at line 131 of file CodecUtil.cpp.

References proxygen::HTTPHeaders::forEachWithCode(), proxygen::HTTP_HEADER_CONNECTION, proxygen::HTTP_HEADER_HOST, proxygen::HTTP_HEADER_KEEP_ALIVE, proxygen::HTTP_HEADER_PROXY_CONNECTION, proxygen::HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, proxygen::HTTP_HEADER_SEC_WEBSOCKET_KEY, proxygen::HTTP_HEADER_TRANSFER_ENCODING, proxygen::HTTP_HEADER_UPGRADE, name, string, and value.

Referenced by proxygen::HTTP2Codec::generateTrailers(), prepareMessageForCompression(), and validateHeaderValue().

133  {
134  bool headerToCheckExists = false;
135  // Add the HTTP headers supplied by the caller, but skip
136  // any per-hop headers that aren't supported in HTTP/2.
137  inputHeaders.forEachWithCode([&](HTTPHeaderCode code,
138  const std::string& name,
139  const std::string& value) {
140  static const std::bitset<256> s_perHopHeaderCodes{[] {
141  std::bitset<256> bs;
142  // HTTP/1.x per-hop headers that have no meaning in HTTP/2
143  bs[HTTP_HEADER_CONNECTION] = true;
144  bs[HTTP_HEADER_HOST] = true;
145  bs[HTTP_HEADER_KEEP_ALIVE] = true;
146  bs[HTTP_HEADER_PROXY_CONNECTION] = true;
148  bs[HTTP_HEADER_UPGRADE] = true;
151  return bs;
152  }()};
153 
154  if (s_perHopHeaderCodes[code] || name.size() == 0 || name[0] == ':') {
155  DCHECK_GT(name.size(), 0) << "Empty header";
156  DCHECK_NE(name[0], ':') << "Invalid header=" << name;
157  return;
158  }
159  // Note this code will not drop headers named by Connection. That's the
160  // caller's job
161 
162  // see HTTP/2 spec, 8.1.2
163  DCHECK(name != "TE" || value == "trailers");
164  if ((name.size() > 0 && name[0] != ':') && code != HTTP_HEADER_HOST) {
165  headers.emplace_back(code, name, value);
166  }
167  if (code == headerToCheck) {
168  headerToCheckExists = true;
169  }
170  });
171 
172  return headerToCheckExists;
173 }
const char * name
Definition: http_parser.c:437
static const char *const value
Definition: Conv.cpp:50
const char * string
Definition: Conv.cpp:212
bool proxygen::CodecUtil::hasGzipAndDeflate ( const std::string value,
bool &  hasGzip,
bool &  hasDeflate 
)
static

Definition at line 61 of file CodecUtil.cpp.

References gmock_output_test::output, proxygen::RFC2616::parseQvalues(), string, and folly::pushmi::operators::transform.

Referenced by proxygen::SPDYCodec::parseHeaders(), and validateHeaderValue().

62  {
64  output->clear();
65  hasGzip = false;
66  hasDeflate = false;
67  RFC2616::parseQvalues(value, *output);
68  for (const auto& encodingQ: *output) {
69  std::string lower(encodingQ.first.str());
70  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
71  // RFC says 3 sig figs
72  if (lower == "gzip" && encodingQ.second >= 0.001) {
73  hasGzip = true;
74  } else if (lower == "deflate" && encodingQ.second >= 0.001) {
75  hasDeflate = true;
76  }
77  }
78  return hasGzip && hasDeflate;
79 }
PUSHMI_INLINE_VAR constexpr detail::transform_fn transform
Definition: transform.h:158
static const char *const value
Definition: Conv.cpp:50
const char * string
Definition: Conv.cpp:212
bool parseQvalues(folly::StringPiece value, std::vector< TokenQPair > &output)
Definition: RFC2616.cpp:64
std::vector< compress::Header > proxygen::CodecUtil::prepareMessageForCompression ( const HTTPMessage msg,
std::vector< std::string > &  temps 
)
static

Definition at line 82 of file CodecUtil.cpp.

References appendHeaders(), proxygen::CONNECT, proxygen::HTTPMessage::formatDateHeader(), proxygen::HTTPMessage::getHeaders(), proxygen::HTTPMessage::getMethod(), proxygen::HTTPMessage::getMethodString(), proxygen::HTTPHeaders::getSingleOrEmpty(), proxygen::HTTPMessage::getStatusCode(), proxygen::HTTPMessage::getURL(), proxygen::HTTP_HEADER_COLON_AUTHORITY, proxygen::HTTP_HEADER_COLON_METHOD, proxygen::HTTP_HEADER_COLON_PATH, proxygen::HTTP_HEADER_COLON_PROTOCOL, proxygen::HTTP_HEADER_COLON_SCHEME, proxygen::HTTP_HEADER_COLON_STATUS, proxygen::HTTP_HEADER_DATE, proxygen::HTTP_HEADER_HOST, proxygen::HTTPMessage::isEgressWebsocketUpgrade(), proxygen::HTTPMessage::isRequest(), proxygen::HTTPMessage::isResponse(), proxygen::HTTPMessage::isSecure(), proxygen::headers::kHttp, proxygen::headers::kHttps, proxygen::headers::kStatus200, proxygen::headers::kWebsocketString, proxygen::methodToString(), and string.

Referenced by proxygen::HTTP2Codec::generateHeaderImpl(), and validateHeaderValue().

84  {
85  std::vector<compress::Header> allHeaders;
86  if (msg.isRequest()) {
87  if (msg.isEgressWebsocketUpgrade()) {
88  allHeaders.emplace_back(HTTP_HEADER_COLON_METHOD,
90  allHeaders.emplace_back(HTTP_HEADER_COLON_PROTOCOL,
92  } else {
93  const std::string& method = msg.getMethodString();
94  allHeaders.emplace_back(HTTP_HEADER_COLON_METHOD, method);
95  }
96 
97  if (msg.getMethod() != HTTPMethod::CONNECT ||
98  msg.isEgressWebsocketUpgrade()) {
99  const std::string& scheme =
100  (msg.isSecure() ? headers::kHttps : headers::kHttp);
101  const std::string& path = msg.getURL();
102  allHeaders.emplace_back(HTTP_HEADER_COLON_SCHEME, scheme);
103  allHeaders.emplace_back(HTTP_HEADER_COLON_PATH, path);
104  }
105  const HTTPHeaders& headers = msg.getHeaders();
106  const std::string& host = headers.getSingleOrEmpty(HTTP_HEADER_HOST);
107  if (!host.empty()) {
108  allHeaders.emplace_back(HTTP_HEADER_COLON_AUTHORITY, host);
109  }
110  } else {
111  temps.reserve(3); // must be large enough so that emplace does not resize
112  if (msg.isEgressWebsocketUpgrade()) {
113  temps.emplace_back(headers::kStatus200);
114  } else {
115  temps.emplace_back(folly::to<std::string>(msg.getStatusCode()));
116  }
117  allHeaders.emplace_back(HTTP_HEADER_COLON_STATUS, temps.back());
118  // HEADERS frames do not include a version or reason string.
119  }
120 
121  bool hasDateHeader =
122  appendHeaders(msg.getHeaders(), allHeaders, HTTP_HEADER_DATE);
123 
124  if (msg.isResponse() && !hasDateHeader) {
125  temps.emplace_back(HTTPMessage::formatDateHeader());
126  allHeaders.emplace_back(HTTP_HEADER_DATE, temps.back());
127  }
128  return allHeaders;
129 }
static std::string formatDateHeader()
const std::string & methodToString(HTTPMethod method)
Definition: HTTPMethod.cpp:46
const std::string kStatus200
const std::string kHttp
const char * string
Definition: Conv.cpp:212
static bool appendHeaders(const HTTPHeaders &inputHeaders, std::vector< compress::Header > &headers, HTTPHeaderCode headerToCheck)
Definition: CodecUtil.cpp:131
const std::string kWebsocketString
const std::string kHttps
static bool proxygen::CodecUtil::validateHeaderName ( folly::ByteRange  name)
inlinestatic

Definition at line 43 of file CodecUtil.h.

References folly::Range< Iter >::size(), and uint8_t.

Referenced by proxygen::HeaderDecodeInfo::onHeader(), and proxygen::SPDYCodec::parseHeaders().

43  {
44  if (name.size() == 0) {
45  return false;
46  }
47  for (auto p: name) {
48  if (p < 0x80 && http_tokens[(uint8_t)p] != p) {
49  return false;
50  }
51  }
52  return true;
53  }
constexpr size_type size() const
Definition: Range.h:431
static const char http_tokens[256]
Definition: CodecUtil.h:27
static bool proxygen::CodecUtil::validateHeaderValue ( folly::ByteRange  value,
CtlEscapeMode  mode 
)
inlinestatic

Definition at line 66 of file CodecUtil.h.

References appendHeaders(), folly::test::begin(), COMPLIANT, folly::test::end(), hasGzipAndDeflate(), prepareMessageForCompression(), quote, string, and value.

Referenced by proxygen::HeaderDecodeInfo::onHeader(), proxygen::SPDYCodec::parseHeaders(), and proxygen::HTTPRequestVerifier::setAuthority().

67  {
68  bool escape = false;
69  bool quote = false;
70  enum { lws_none,
71  lws_expect_nl,
72  lws_expect_ws1,
73  lws_expect_ws2 } state = lws_none;
74 
75  for (auto p = std::begin(value); p != std::end(value); ++p) {
76  if (escape) {
77  escape = false;
78  if (mode == COMPLIANT) {
79  // prev char escaped. Turn off escape and go to next char
80  // COMPLIANT mode only
81  assert(quote);
82  continue;
83  }
84  }
85  switch (state) {
86  case lws_none:
87  switch (*p) {
88  case '\\':
89  if (quote) {
90  escape = true;
91  }
92  break;
93  case '\"':
94  quote = !quote;
95  break;
96  case '\r':
97  state = lws_expect_nl;
98  break;
99  default:
100  if ((*p < 0x20 || *p == 0x7f) && *p != '\t') {
101  // unexpected ctl per rfc2616, HT OK
102  return false;
103  }
104  break;
105  }
106  break;
107  case lws_expect_nl:
108  if (*p != '\n') {
109  // unescaped \r must be LWS
110  return false;
111  }
112  state = lws_expect_ws1;
113  break;
114  case lws_expect_ws1:
115  if (*p != ' ' && *p != '\t') {
116  // unescaped \r\n must be LWS
117  return false;
118  }
119  state = lws_expect_ws2;
120  break;
121  case lws_expect_ws2:
122  if (*p != ' ' && *p != '\t') {
123  // terminated LWS
124  state = lws_none;
125  // check this char again
126  p--;
127  }
128  break;
129  }
130  }
131  // Unterminated quotes are OK, since the value can be* TEXT which treats
132  // the " like any other char.
133  // Unterminated escapes are bad because it will escape the next character
134  // when converting to HTTP
135  // Unterminated LWS (dangling \r or \r\n) is bad because it could
136  // prematurely terminate the headers when converting to HTTP
137  return !escape && (state == lws_none || state == lws_expect_ws2);
138  }
bool quote
Definition: Conv.cpp:213
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
folly::Optional< PskKeyExchangeMode > mode
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
state
Definition: http_parser.c:272
static bool proxygen::CodecUtil::validateMethod ( folly::ByteRange  method)
inlinestatic

Definition at line 33 of file CodecUtil.h.

Referenced by proxygen::SPDYCodec::parseHeaders(), proxygen::HTTPRequestVerifier::setMethod(), and proxygen::HTTPRequestVerifier::setScheme().

33  {
34  for (auto p: method) {
35  if (!isalpha(p)) {
36  // methods are all characters
37  return false;
38  }
39  }
40  return true;
41  }
static bool proxygen::CodecUtil::validateURL ( folly::ByteRange  url)
inlinestatic

Definition at line 29 of file CodecUtil.h.

References proxygen::validateURL().

Referenced by proxygen::SPDYCodec::parseHeaders(), and proxygen::HTTPRequestVerifier::setPath().

29  {
30  return proxygen::validateURL(url);
31  }
bool validateURL(folly::ByteRange url)
Definition: UtilInl.h:25

Member Data Documentation

const char proxygen::CodecUtil::http_tokens
static

Tokens as defined by rfc 2616. Also lowercases them. token = 1*<any char="" except="" ctls="" or="" separators>=""> separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT

Definition at line 27 of file CodecUtil.h.


The documentation for this class was generated from the following files: