cgiparam.h 5.9 KB

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