proxygen
HTTPHeaders.h
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 #pragma once
11 
12 #include <folly/FBVector.h>
13 #include <folly/Range.h>
17 
18 #include <bitset>
19 #include <cstring>
20 #include <string>
21 #include <initializer_list>
22 
23 namespace proxygen {
24 
25 extern const std::string empty_string;
26 
31 inline bool isLWS(char c) {
32  // Technically \r and \n are only allowed in LWS if they appear together.
33  if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
34  return true;
35  }
36  return false;
37 }
38 
68 class HTTPHeaders {
69  public:
70  struct HTTPHeaderName {
71  enum Type { CODE, STRING };
72  union {
75  };
77  /* implicit */ HTTPHeaderName(HTTPHeaderCode code)
78  : code_(code), type_(CODE) {}
79  /* implicit */ HTTPHeaderName(const char* name)
80  : name_(name), type_(STRING) {}
82  : name_(name), type_(STRING) {}
83  };
84 
85  using headers_initializer_list = std::initializer_list<
86  std::pair<HTTPHeaderName,folly::StringPiece>>;
87 
88  /*
89  * separator used to concatenate multiple values of the same header
90  * check out sections 4.2 and 14.45 from rfc2616
91  */
93 
99  FB_EXPORT HTTPHeaders& operator= (HTTPHeaders&&);
100 
106  template <typename T> // T = string
107  void add(folly::StringPiece name, T&& value);
108  template <typename T> // T = string
109  void add(HTTPHeaderCode code, T&& value);
111  void rawAdd(const std::string& name, const std::string& value);
112 
113  void addFromCodec(const char* str, size_t len, std::string&& value);
114 
119  void set(folly::StringPiece name, const std::string& value) {
120  // this could be somewhat optimized but probably not an issue yet
121  remove(name);
122  add(name, value);
123  }
124  void set(HTTPHeaderCode code, const std::string& value) {
125  remove(code);
126  add(code, value);
127  }
128  void rawSet(const std::string& name, const std::string& value) {
129  set(name, value);
130  }
131 
135  bool exists(folly::StringPiece name) const;
136  bool exists(HTTPHeaderCode code) const;
137  bool rawExists(std::string& name) const {
138  return exists(name);
139  }
140 
144  template <typename T>
145  std::string combine(const T& header,
146  const std::string& separator=COMBINE_SEPARATOR) const;
147 
157  template <typename LAMBDA> // (const string &, const string &) -> void
158  inline void forEach(LAMBDA func) const;
159 
172  template <typename LAMBDA>
173  inline void forEachWithCode(LAMBDA func) const;
174 
189  template <typename LAMBDA> // (const string &, const string &) -> bool
190  inline bool removeByPredicate(LAMBDA func);
191 
197  template <typename T> // either uint8_t or string
198  const std::string & getSingleOrEmpty(const T& nameOrCode) const;
199  const std::string rawGet(const std::string& header) const {
200  return getSingleOrEmpty(header);
201  }
202 
206  size_t getNumberOfValues(HTTPHeaderCode code) const;
207  size_t getNumberOfValues(folly::StringPiece name) const;
208 
221  template <typename LAMBDA> // const string & -> bool
222  inline bool forEachValueOfHeader(folly::StringPiece name, LAMBDA func) const;
223  template <typename LAMBDA> // const string & -> bool
224  inline bool forEachValueOfHeader(HTTPHeaderCode code, LAMBDA func) const;
225 
230  bool remove(folly::StringPiece name);
231  bool remove(HTTPHeaderCode code);
232  void rawRemove(const std::string& name) {
233  remove(name);
234  }
235 
239  void removeAll();
240 
245  void stripPerHopHeaders(HTTPHeaders& strippedHeaders);
246 
250  size_t size() const;
251 
255  void copyTo(HTTPHeaders& hdrs) const;
256 
261  static std::bitset<256>& perHopHeaderCodes();
262 
263  private:
264  // vector storing the 1-byte hashes of header names
266 
272 
274 
276 
281  static const size_t kInitialVectorReserve = 16;
282 
289 
290  // deletes the strings in headerNames_ that we own
291  void disposeOfHeaderNames();
292 };
293 
294 // Implementation follows - it has to be in the .h because of the templates
295 
296 template <typename T> // T = string
298  assert(name.size());
299  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(), name.size());
300  codes_.push_back(code);
302  ? new std::string(name.data(), name.size())
304  headerValues_.emplace_back(std::forward<T>(value));
305 }
306 
307 template <typename T> // T = string
309  codes_.push_back(code);
311  headerValues_.emplace_back(std::forward<T>(value));
312 }
313 
314 // iterate over the positions (in vector) of all headers with given code
315 #define ITERATE_OVER_CODES(Code, Block) \
316  { \
317  const HTTPHeaderCode* ptr = codes_.data(); \
318  while (ptr) { \
319  ptr = (HTTPHeaderCode*)memchr( \
320  (void*)ptr, (Code), codes_.size() - (ptr - codes_.data())); \
321  if (ptr == nullptr) \
322  break; \
323  const size_t pos = ptr - codes_.data(); \
324  {Block} ptr++; \
325  } \
326  }
327 
328 // iterate over the positions of all headers with given name
329 #define ITERATE_OVER_STRINGS(String, Block) \
330  ITERATE_OVER_CODES(HTTP_HEADER_OTHER, { \
331  if (caseInsensitiveEqual((String), *headerNames_[pos])) { \
332  {Block} \
333  } \
334 })
335 
336 template <typename LAMBDA> // (const string &, const string &) -> void
337 void HTTPHeaders::forEach(LAMBDA func) const {
338  for (size_t i = 0; i < codes_.size(); ++i) {
339  if (codes_[i] != HTTP_HEADER_NONE) {
340  func(*headerNames_[i], headerValues_[i]);
341  }
342  }
343 }
344 
345 template <typename LAMBDA>
346 void HTTPHeaders::forEachWithCode(LAMBDA func) const {
347  for (size_t i = 0; i < codes_.size(); ++i) {
348  if (codes_[i] != HTTP_HEADER_NONE) {
349  func(codes_[i], *headerNames_[i], headerValues_[i]);
350  }
351  }
352 }
353 
354 template <typename LAMBDA> // const string & -> bool
356  LAMBDA func) const {
357  const HTTPHeaderCode code = HTTPCommonHeaders::hash(name.data(), name.size());
358  if (code != HTTP_HEADER_OTHER) {
359  return forEachValueOfHeader(code, func);
360  } else {
361  ITERATE_OVER_STRINGS(name, {
362  if (func(headerValues_[pos])) {
363  return true;
364  }
365  });
366  return false;
367  }
368 }
369 
370 template <typename LAMBDA> // const string & -> bool
372  LAMBDA func) const {
373  ITERATE_OVER_CODES(code, {
374  if (func(headerValues_[pos])) {
375  return true;
376  }
377  });
378  return false;
379 }
380 
381 template <typename T>
383  const std::string& separator) const {
384  std::string combined = "";
385  forEachValueOfHeader(header, [&] (const std::string& value) -> bool {
386  if (combined.empty()) {
387  combined.append(value);
388  } else {
389  combined.append(separator).append(value);
390  }
391  return false;
392  });
393  return combined;
394 }
395 
396 // LAMBDA: (HTTPHeaderCode, const string&, const string&) -> bool
397 template <typename LAMBDA>
399  bool removed = false;
400  for (size_t i = 0; i < codes_.size(); ++i) {
401  if (codes_[i] == HTTP_HEADER_NONE ||
402  !func(codes_[i], *headerNames_[i], headerValues_[i])) {
403  continue;
404  }
405 
406  if (codes_[i] == HTTP_HEADER_OTHER) {
407  delete headerNames_[i];
408  headerNames_[i] = nullptr;
409  }
410 
412  ++deletedCount_;
413  removed = true;
414  }
415 
416  return removed;
417 }
418 
419 template <typename T> // either uint8_t or string
420 const std::string & HTTPHeaders::getSingleOrEmpty(const T& nameOrCode) const {
421  const std::string* res = nullptr;
422  forEachValueOfHeader(nameOrCode, [&] (const std::string& value) -> bool {
423  if (res != nullptr) {
424  // a second value is found
425  res = nullptr;
426  return true; // stop processing
427  } else {
428  // the first value is found
429  res = &value;
430  return false;
431  }
432  });
433  if (res == nullptr) {
434  return empty_string;
435  } else {
436  return *res;
437  }
438 }
439 
440 #ifndef PROXYGEN_HTTPHEADERS_IMPL
441 #undef ITERATE_OVER_CODES
442 #undef ITERATE_OVER_STRINGS
443 #endif // PROXYGEN_HTTPHEADERS_IMPL
444 
445 }
#define FB_EXPORT
Definition: Export.h:26
const std::string rawGet(const std::string &header) const
Definition: HTTPHeaders.h:199
FB_EXPORT ~HTTPHeaders()
void addFromCodec(const char *str, size_t len, std::string &&value)
Definition: HTTPHeaders.cpp:77
#define T(v)
Definition: http_parser.c:233
bool isLWS(char c)
Definition: HTTPHeaders.h:31
static const std::string COMBINE_SEPARATOR
Definition: HTTPHeaders.h:92
bool exists(folly::StringPiece name) const
Definition: HTTPHeaders.cpp:86
bool rawExists(std::string &name) const
Definition: HTTPHeaders.h:137
bool transferHeaderIfPresent(folly::StringPiece name, HTTPHeaders &dest)
std::initializer_list< std::pair< HTTPHeaderName, folly::StringPiece >> headers_initializer_list
Definition: HTTPHeaders.h:86
HTTPHeaderName(folly::StringPiece name)
Definition: HTTPHeaders.h:81
static std::bitset< 256 > & perHopHeaderCodes()
Definition: HTTPHeaders.cpp:26
dest
Definition: upload.py:394
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
void rawRemove(const std::string &name)
Definition: HTTPHeaders.h:232
size_t getNumberOfValues(HTTPHeaderCode code) const
void stripPerHopHeaders(HTTPHeaders &strippedHeaders)
FB_EXPORT HTTPHeaders()
Definition: HTTPHeaders.cpp:45
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
static const size_t kInitialVectorReserve
Definition: HTTPHeaders.h:281
std::string combine(const T &header, const std::string &separator=COMBINE_SEPARATOR) const
Definition: HTTPHeaders.h:382
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
void rawSet(const std::string &name, const std::string &value)
Definition: HTTPHeaders.h:128
static const std::string * getPointerToHeaderName(HTTPHeaderCode code, HTTPCommonHeaderTableType type=TABLE_CAMELCASE)
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
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
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
FB_EXPORT HTTPHeaders & operator=(const HTTPHeaders &)
bool removeByPredicate(LAMBDA func)
Definition: HTTPHeaders.h:398
size_t size() const
folly::fbvector< const std::string * > headerNames_
Definition: HTTPHeaders.h:271
const std::string empty_string
Definition: HTTPHeaders.cpp:23
HTTPHeaderName(HTTPHeaderCode code)
Definition: HTTPHeaders.h:77
const char * string
Definition: Conv.cpp:212
const
Definition: upload.py:398
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
static FB_EXPORT HTTPHeaderCode hash(const char *name, size_t len)
Range< const char * > StringPiece
size_type size() const noexcept
Definition: FBVector.h:964
char c
folly::fbvector< std::string > headerValues_
Definition: HTTPHeaders.h:273
Definition: Traits.h:592
void forEachWithCode(LAMBDA func) const
Definition: HTTPHeaders.h:346
void rawAdd(const std::string &name, const std::string &value)
Definition: HTTPHeaders.cpp:73