proxygen
HTTPHeaders.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  */
10 #define PROXYGEN_HTTPHEADERS_IMPL
12 
14 
15 #include <glog/logging.h>
16 
17 using std::bitset;
18 using std::string;
19 using std::vector;
20 
21 namespace proxygen {
22 
23 const string empty_string;
25 
27  static bitset<256> perHopHeaderCodes{
28  [] {
29  bitset<256> bs;
30  bs[HTTP_HEADER_CONNECTION] = true;
31  bs[HTTP_HEADER_KEEP_ALIVE] = true;
35  bs[HTTP_HEADER_TE] = true;
36  bs[HTTP_HEADER_TRAILER] = true;
38  bs[HTTP_HEADER_UPGRADE] = true;
39  return bs;
40  }()
41  };
42  return perHopHeaderCodes;
43 }
44 
46  deletedCount_(0) {
50 }
51 
53  CHECK(name.size());
54  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(), name.size());
55  codes_.push_back(code);
57  ? new std::string(name.data(), name.size())
59  headerValues_.emplace_back(value.data(), value.size());
60 }
61 
63  for (auto& p : l) {
64  if (p.first.type_ == HTTPHeaderName::CODE) {
65  add(p.first.code_, std::string(p.second.data(), p.second.size()));
66  }
67  else {
68  add(p.first.name_, std::string(p.second.data(), p.second.size()));
69  }
70  }
71 }
72 
74  add(name, value);
75 }
76 
77 void HTTPHeaders::addFromCodec(const char* str, size_t len, string&& value) {
78  const HTTPHeaderCode code = HTTPCommonHeaders::hash(str, len);
79  codes_.push_back(code);
81  ? new string(str, len)
84 }
85 
87  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(),
88  name.size());
89  if (code != HTTP_HEADER_OTHER) {
90  return exists(code);
91  } else {
92  ITERATE_OVER_STRINGS(name, { return true; });
93  return false;
94  }
95 }
96 
98  if (codes_.data() == nullptr) {
99  return false;
100  }
101  return memchr((void*)codes_.data(), code, codes_.size()) != nullptr;
102 }
103 
105  size_t count = 0;
106  ITERATE_OVER_CODES(code, {
107  (void)pos;
108  ++count;
109  });
110  return count;
111 }
112 
114  size_t count = 0;
115  forEachValueOfHeader(name, [&] (folly::StringPiece /*value*/) -> bool {
116  ++count;
117  return false;
118  });
119  return count;
120 }
121 
123  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(),
124  name.size());
125  if (code != HTTP_HEADER_OTHER) {
126  return remove(code);
127  } else {
128  bool removed = false;
129  ITERATE_OVER_STRINGS(name, {
130  delete headerNames_[pos];
131  codes_[pos] = HTTP_HEADER_NONE;
132  removed = true;
133  ++deletedCount_;
134  });
135  return removed;
136  }
137 }
138 
140  bool removed = false;
141  ITERATE_OVER_CODES(code, {
142  codes_[pos] = HTTP_HEADER_NONE;
143  removed = true;
144  ++deletedCount_;
145  });
146  return removed;
147 }
148 
150  for (size_t i = 0; i < codes_.size(); ++i) {
151  if (codes_[i] == HTTP_HEADER_OTHER) {
152  delete headerNames_[i];
153  }
154  }
155 }
156 
159 }
160 
162  codes_(hdrs.codes_),
166  for (size_t i = 0; i < codes_.size(); ++i) {
167  if (codes_[i] == HTTP_HEADER_OTHER) {
168  headerNames_[i] = new string(*hdrs.headerNames_[i]);
169  }
170  }
171 }
172 
174  codes_(std::move(hdrs.codes_)),
178  hdrs.removeAll();
179 }
180 
182  if (this != &hdrs) {
184  codes_ = hdrs.codes_;
185  headerNames_ = hdrs.headerNames_;
188  for (size_t i = 0; i < codes_.size(); ++i) {
189  if (codes_[i] == HTTP_HEADER_OTHER) {
190  headerNames_[i] = new string(*hdrs.headerNames_[i]);
191  }
192  }
193  }
194  return *this;
195 }
196 
198  if (this != &hdrs) {
199  codes_ = std::move(hdrs.codes_);
200  headerNames_ = std::move(hdrs.headerNames_);
201  headerValues_ = std::move(hdrs.headerValues_);
202  deletedCount_ = hdrs.deletedCount_;
203 
204  hdrs.removeAll();
205  }
206 
207  return *this;
208 }
209 
212 
213  codes_.clear();
216  deletedCount_ = 0;
217 }
218 
219 size_t HTTPHeaders::size() const {
220  return codes_.size() - deletedCount_;
221 }
222 
223 bool
225  HTTPHeaders& strippedHeaders) {
226  bool transferred = false;
227  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(),
228  name.size());
229  if (code == HTTP_HEADER_OTHER) {
230  ITERATE_OVER_STRINGS(name, {
231  strippedHeaders.codes_.push_back(HTTP_HEADER_OTHER);
232  // in the next line, ownership of pointer goes to strippedHeaders
233  strippedHeaders.headerNames_.push_back(headerNames_[pos]);
234  strippedHeaders.headerValues_.push_back(headerValues_[pos]);
235  codes_[pos] = HTTP_HEADER_NONE;
236  transferred = true;
237  ++deletedCount_;
238  });
239  } else { // code != HTTP_HEADER_OTHER
240  ITERATE_OVER_CODES(code, {
241  strippedHeaders.codes_.push_back(code);
242  strippedHeaders.headerNames_.push_back(headerNames_[pos]);
243  strippedHeaders.headerValues_.push_back(headerValues_[pos]);
244  codes_[pos] = HTTP_HEADER_NONE;
245  transferred = true;
246  ++deletedCount_;
247  });
248  }
249  return transferred;
250 }
251 
252 void
254  int len;
256  (const string& stdStr) -> bool {
257  // Remove all headers specified in Connection header
258  // look for multiple values separated by commas
259  char const* str = stdStr.c_str();
260 
261  // skip leading whitespace
262  while (isLWS(*str)) str++;
263 
264  while (*str != 0) {
265  char const* pos = strchr(str, ',');
266  if (pos == nullptr) {
267  // last (or only) token, done
268 
269  // count chars in the token
270  len = 0;
271  while (str[len] != 0 && !isLWS(str[len])) len++;
272  if (len > 0) {
273  string hdr(str, len);
274  if (transferHeaderIfPresent(hdr, strippedHeaders)) {
275  VLOG(3) << "Stripped connection-named hop-by-hop header " << hdr;
276  }
277  }
278  break;
279  }
280  len = pos - str;
281  // strip trailing whitespace
282  while (len > 0 && isLWS(str[len - 1])) len--;
283  if (len > 0) {
284  // non-empty token
285  string hdr(str, len);
286  if (transferHeaderIfPresent(hdr, strippedHeaders)) {
287  VLOG(3) << "Stripped connection-named hop-by-hop header " << hdr;
288  }
289  } // else empty token, no-op
290  str = pos + 1;
291 
292  // skip whitespace
293  while (isLWS(*str)) str++;
294  }
295  return false; // continue processing "connection" headers
296  });
297 
298  // Strip hop-by-hop headers
299  auto& perHopHeaders = perHopHeaderCodes();
300  for (size_t i = 0; i < codes_.size(); ++i) {
301  if (perHopHeaders[codes_[i]]) {
302  strippedHeaders.codes_.push_back(codes_[i]);
303  strippedHeaders.headerNames_.push_back(headerNames_[i]);
304  strippedHeaders.headerValues_.push_back(headerValues_[i]);
306  ++deletedCount_;
307  VLOG(5) << "Stripped hop-by-hop header " << *headerNames_[i];
308  }
309  }
310 }
311 
312 void HTTPHeaders::copyTo(HTTPHeaders& hdrs) const {
313  for (size_t i = 0; i < codes_.size(); ++i) {
314  if (codes_[i] != HTTP_HEADER_NONE) {
315  hdrs.codes_.push_back(codes_[i]);
317  new string(*headerNames_[i]) : headerNames_[i]);
319  }
320  }
321 }
322 
323 }
FB_EXPORT ~HTTPHeaders()
void addFromCodec(const char *str, size_t len, std::string &&value)
Definition: HTTPHeaders.cpp:77
bool isLWS(char c)
Definition: HTTPHeaders.h:31
static const std::string COMBINE_SEPARATOR
Definition: HTTPHeaders.h:92
bool remove(folly::StringPiece name)
bool exists(folly::StringPiece name) const
Definition: HTTPHeaders.cpp:86
bool transferHeaderIfPresent(folly::StringPiece name, HTTPHeaders &dest)
std::initializer_list< std::pair< HTTPHeaderName, folly::StringPiece >> headers_initializer_list
Definition: HTTPHeaders.h:86
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static std::bitset< 256 > & perHopHeaderCodes()
Definition: HTTPHeaders.cpp:26
void reserve(size_type n)
Definition: FBVector.h:1003
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
size_t getNumberOfValues(HTTPHeaderCode code) const
void stripPerHopHeaders(HTTPHeaders &strippedHeaders)
FB_EXPORT HTTPHeaders()
Definition: HTTPHeaders.cpp:45
requires E e noexcept(noexcept(s.error(std::move(e))))
T * data() noexcept
Definition: FBVector.h:1135
static const size_t kInitialVectorReserve
Definition: HTTPHeaders.h:281
void push_back(const T &value)
Definition: FBVector.h:1156
bool forEachValueOfHeader(folly::StringPiece name, LAMBDA func) const
Definition: HTTPHeaders.h:355
const char * name
Definition: http_parser.c:437
void copyTo(HTTPHeaders &hdrs) const
constexpr Iter data() const
Definition: Range.h:446
#define ITERATE_OVER_CODES(Code, Block)
Definition: HTTPHeaders.h:315
#define ITERATE_OVER_STRINGS(String, Block)
Definition: HTTPHeaders.h:329
static const std::string * getPointerToHeaderName(HTTPHeaderCode code, HTTPCommonHeaderTableType type=TABLE_CAMELCASE)
static const char *const value
Definition: Conv.cpp:50
folly::fbvector< HTTPHeaderCode > codes_
Definition: HTTPHeaders.h:265
void emplace_back(Args &&...args)
Definition: FBVector.h:1147
FB_EXPORT HTTPHeaders & operator=(const HTTPHeaders &)
int * count
size_t size() const
folly::fbvector< const std::string * > headerNames_
Definition: HTTPHeaders.h:271
const std::string empty_string
Definition: HTTPHeaders.cpp:23
const char * string
Definition: Conv.cpp:212
void clear() noexcept
Definition: FBVector.h:1188
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
static FB_EXPORT HTTPHeaderCode hash(const char *name, size_t len)
size_type size() const noexcept
Definition: FBVector.h:964
folly::fbvector< std::string > headerValues_
Definition: HTTPHeaders.h:273
void rawAdd(const std::string &name, const std::string &value)
Definition: HTTPHeaders.cpp:73