headers.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #include "headers.h"
  2. #include "stream.h"
  3. #include <util/generic/strbuf.h>
  4. #include <util/generic/yexception.h>
  5. #include <util/stream/output.h>
  6. #include <util/string/ascii.h>
  7. #include <util/string/cast.h>
  8. #include <util/string/strip.h>
  9. static inline TStringBuf Trim(const char* b, const char* e) noexcept {
  10. return StripString(TStringBuf(b, e));
  11. }
  12. static inline bool HeaderNameEqual(TStringBuf headerName, TStringBuf expectedName) noexcept {
  13. // Most headers names have distinct sizes.
  14. // Size comparison adds small overhead if all headers have the same size (~4% or lower with size = 4),
  15. // but significantly speeds up the case where sizes are different (~4.5x for expectedName.size() = 4 and headerName.size() = 5)
  16. return headerName.size() == expectedName.size() && AsciiCompareIgnoreCase(headerName, expectedName) == 0;
  17. }
  18. THttpInputHeader::THttpInputHeader(const TStringBuf header) {
  19. size_t pos = header.find(':');
  20. if (pos == TString::npos) {
  21. ythrow THttpParseException() << "can not parse http header(" << TString{header}.Quote() << ")";
  22. }
  23. Name_ = TString(header.cbegin(), header.cbegin() + pos);
  24. Value_ = ::ToString(Trim(header.cbegin() + pos + 1, header.cend()));
  25. }
  26. THttpInputHeader::THttpInputHeader(TString name, TString value)
  27. : Name_(std::move(name))
  28. , Value_(std::move(value))
  29. {
  30. }
  31. void THttpInputHeader::OutTo(IOutputStream* stream) const {
  32. typedef IOutputStream::TPart TPart;
  33. const TPart parts[] = {
  34. TPart(Name_),
  35. TPart(": ", 2),
  36. TPart(Value_),
  37. TPart::CrLf(),
  38. };
  39. stream->Write(parts, sizeof(parts) / sizeof(*parts));
  40. }
  41. THttpHeaders::THttpHeaders(IInputStream* stream) {
  42. TString header;
  43. TString line;
  44. bool rdOk = stream->ReadLine(header);
  45. while (rdOk && !header.empty()) {
  46. rdOk = stream->ReadLine(line);
  47. if (rdOk && ((line[0] == ' ') || (line[0] == '\t'))) {
  48. header += line;
  49. } else {
  50. AddHeader(THttpInputHeader(header));
  51. header = line;
  52. }
  53. }
  54. }
  55. bool THttpHeaders::HasHeader(const TStringBuf header) const {
  56. return FindHeader(header);
  57. }
  58. const THttpInputHeader* THttpHeaders::FindHeader(const TStringBuf header) const {
  59. for (const auto& hdr : Headers_) {
  60. if (HeaderNameEqual(hdr.Name(), header)) {
  61. return &hdr;
  62. }
  63. }
  64. return nullptr;
  65. }
  66. void THttpHeaders::RemoveHeader(const TStringBuf header) {
  67. for (auto h = Headers_.begin(); h != Headers_.end(); ++h) {
  68. if (HeaderNameEqual(h->Name(), header)) {
  69. Headers_.erase(h);
  70. return;
  71. }
  72. }
  73. }
  74. void THttpHeaders::AddOrReplaceHeader(const THttpInputHeader& header) {
  75. TStringBuf name = header.Name();
  76. for (auto& hdr : Headers_) {
  77. if (HeaderNameEqual(hdr.Name(), name)) {
  78. hdr = header;
  79. return;
  80. }
  81. }
  82. AddHeader(header);
  83. }
  84. void THttpHeaders::AddHeader(THttpInputHeader header) {
  85. Headers_.push_back(std::move(header));
  86. }
  87. void THttpHeaders::OutTo(IOutputStream* stream) const {
  88. for (TConstIterator header = Begin(); header != End(); ++header) {
  89. header->OutTo(stream);
  90. }
  91. }
  92. template <>
  93. void Out<THttpHeaders>(IOutputStream& out, const THttpHeaders& h) {
  94. h.OutTo(&out);
  95. }