cgiparam.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #pragma once
  2. #include <library/cpp/iterator/iterate_values.h>
  3. #include <util/generic/iterator_range.h>
  4. #include <util/generic/map.h>
  5. #include <util/generic/strbuf.h>
  6. #include <util/generic/string.h>
  7. #include <initializer_list>
  8. struct TStringLess {
  9. template <class T1, class T2>
  10. inline bool operator()(const T1& t1, const T2& t2) const noexcept {
  11. return TStringBuf(t1) < TStringBuf(t2);
  12. }
  13. };
  14. class TCgiParameters: public TMultiMap<TString, TString> {
  15. public:
  16. TCgiParameters() = default;
  17. explicit TCgiParameters(const TStringBuf cgiParamStr) {
  18. Scan(cgiParamStr);
  19. }
  20. TCgiParameters(std::initializer_list<std::pair<TString, TString>> il);
  21. void Flush() {
  22. erase(begin(), end());
  23. }
  24. size_t EraseAll(const TStringBuf name);
  25. size_t NumOfValues(const TStringBuf name) const noexcept {
  26. return count(name);
  27. }
  28. TString operator()() const {
  29. return Print();
  30. }
  31. void Scan(const TStringBuf cgiParStr, bool form = true);
  32. void ScanAdd(const TStringBuf cgiParStr);
  33. void ScanAddUnescaped(const TStringBuf cgiParStr);
  34. void ScanAddAllUnescaped(const TStringBuf cgiParStr);
  35. void ScanAddAll(const TStringBuf cgiParStr);
  36. /// Returns the string representation of all the stored parameters
  37. /**
  38. * @note The returned string has format <name1>=<value1>&<name2>=<value2>&...
  39. * @note Names and values in the returned string are CGI-escaped.
  40. */
  41. TString Print() const;
  42. char* Print(char* res) const;
  43. Y_PURE_FUNCTION
  44. size_t PrintSize() const noexcept;
  45. /** The same as Print* except that RFC-3986 reserved characters are escaped.
  46. * @param safe - set of characters to be skipped in escaping
  47. */
  48. TString QuotedPrint(const char* safe = "/") const;
  49. Y_PURE_FUNCTION
  50. auto Range(const TStringBuf name) const noexcept {
  51. return IterateValues(MakeIteratorRange(equal_range(name)));
  52. }
  53. Y_PURE_FUNCTION
  54. const_iterator Find(const TStringBuf name, size_t numOfValue = 0) const noexcept;
  55. Y_PURE_FUNCTION
  56. bool Has(const TStringBuf name, const TStringBuf value) const noexcept;
  57. Y_PURE_FUNCTION
  58. bool Has(const TStringBuf name) const noexcept {
  59. const auto pair = equal_range(name);
  60. return pair.first != pair.second;
  61. }
  62. /// Returns value by name
  63. /**
  64. * @note The returned value is CGI-unescaped.
  65. */
  66. Y_PURE_FUNCTION
  67. const TString& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept;
  68. void InsertEscaped(const TStringBuf name, const TStringBuf value);
  69. #if !defined(__GLIBCXX__)
  70. template <typename TName, typename TValue>
  71. inline void InsertUnescaped(TName&& name, TValue&& value) {
  72. // TStringBuf use as TName or TValue is C++17 actually.
  73. // There is no pair constructor available in C++14 when required type
  74. // is not implicitly constructible from given type.
  75. // But libc++ pair allows this with C++14.
  76. emplace(std::forward<TName>(name), std::forward<TValue>(value));
  77. }
  78. #else
  79. template <typename TName, typename TValue>
  80. inline void InsertUnescaped(TName&& name, TValue&& value) {
  81. emplace(TString(name), TString(value));
  82. }
  83. #endif
  84. // replace all values for a given key with new values
  85. template <typename TIter>
  86. void ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd);
  87. void ReplaceUnescaped(const TStringBuf key, std::initializer_list<TStringBuf> values) {
  88. ReplaceUnescaped(key, values.begin(), values.end());
  89. }
  90. void ReplaceUnescaped(const TStringBuf key, const TStringBuf value) {
  91. ReplaceUnescaped(key, {value});
  92. }
  93. // join multiple values into a single one using a separator
  94. // if val is a [possibly empty] non-NULL string, append it as well
  95. void JoinUnescaped(const TStringBuf key, char sep, TStringBuf val = TStringBuf());
  96. bool Erase(const TStringBuf name, size_t numOfValue = 0);
  97. bool Erase(const TStringBuf name, const TStringBuf val);
  98. inline const char* FormField(const TStringBuf name, size_t numOfValue = 0) const {
  99. const_iterator it = Find(name, numOfValue);
  100. if (it == end()) {
  101. return nullptr;
  102. }
  103. return it->second.data();
  104. }
  105. };
  106. template <typename TIter>
  107. void TCgiParameters::ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd) {
  108. const auto oldRange = equal_range(key);
  109. auto current = oldRange.first;
  110. // reuse as many existing nodes as possible (probably none)
  111. for (; valuesBegin != valuesEnd && current != oldRange.second; ++valuesBegin, ++current) {
  112. current->second = *valuesBegin;
  113. }
  114. // if there were more nodes than we need to insert then erase remaining ones
  115. for (; current != oldRange.second; erase(current++)) {
  116. }
  117. // if there were less nodes than we need to insert then emplace the rest of the range
  118. if (valuesBegin != valuesEnd) {
  119. const TString keyStr = TString(key);
  120. for (; valuesBegin != valuesEnd; ++valuesBegin) {
  121. emplace_hint(oldRange.second, keyStr, TString(*valuesBegin));
  122. }
  123. }
  124. }
  125. /** TQuickCgiParam is a faster non-editable version of TCgiParameters.
  126. * Care should be taken when replacing:
  127. * - note that the result of Get() is invalidated when TQuickCgiParam object is destroyed.
  128. */
  129. class TQuickCgiParam: public TMultiMap<TStringBuf, TStringBuf> {
  130. public:
  131. TQuickCgiParam() = default;
  132. explicit TQuickCgiParam(const TStringBuf cgiParamStr);
  133. Y_PURE_FUNCTION
  134. bool Has(const TStringBuf name, const TStringBuf value) const noexcept;
  135. Y_PURE_FUNCTION
  136. bool Has(const TStringBuf name) const noexcept {
  137. const auto pair = equal_range(name);
  138. return pair.first != pair.second;
  139. }
  140. Y_PURE_FUNCTION
  141. const TStringBuf& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept;
  142. private:
  143. TString UnescapeBuf;
  144. };