cgiparam.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #include "cgiparam.h"
  2. #include <library/cpp/string_utils/scan/scan.h>
  3. #include <library/cpp/string_utils/quote/quote.h>
  4. #include <util/generic/singleton.h>
  5. TCgiParameters::TCgiParameters(std::initializer_list<std::pair<TString, TString>> il) {
  6. for (const auto& item : il) {
  7. insert(item);
  8. }
  9. }
  10. const TString& TCgiParameters::Get(const TStringBuf name, size_t numOfValue) const noexcept {
  11. const auto it = Find(name, numOfValue);
  12. return end() == it ? Default<TString>() : it->second;
  13. }
  14. bool TCgiParameters::Erase(const TStringBuf name, size_t pos) {
  15. const auto pair = equal_range(name);
  16. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  17. if (0 == pos) {
  18. erase(it);
  19. return true;
  20. }
  21. }
  22. return false;
  23. }
  24. bool TCgiParameters::Erase(const TStringBuf name, const TStringBuf val) {
  25. const auto pair = equal_range(name);
  26. bool found = false;
  27. for (auto it = pair.first; it != pair.second;) {
  28. if (val == it->second) {
  29. it = erase(it);
  30. found = true;
  31. } else {
  32. ++it;
  33. }
  34. }
  35. return found;
  36. }
  37. size_t TCgiParameters::EraseAll(const TStringBuf name) {
  38. size_t num = 0;
  39. const auto pair = equal_range(name);
  40. for (auto it = pair.first; it != pair.second; erase(it++), ++num)
  41. ;
  42. return num;
  43. }
  44. void TCgiParameters::JoinUnescaped(const TStringBuf key, char sep, TStringBuf val) {
  45. const auto pair = equal_range(key);
  46. auto it = pair.first;
  47. if (it == pair.second) { // not found
  48. if (val.IsInited()) {
  49. emplace_hint(it, TString(key), TString(val));
  50. }
  51. } else {
  52. TString& dst = it->second;
  53. for (++it; it != pair.second; erase(it++)) {
  54. dst += sep;
  55. dst.AppendNoAlias(it->second.data(), it->second.size());
  56. }
  57. if (val.IsInited()) {
  58. dst += sep;
  59. dst += val;
  60. }
  61. }
  62. }
  63. static inline TString DoUnescape(const TStringBuf s) {
  64. TString res;
  65. res.reserve(CgiUnescapeBufLen(s.size()));
  66. res.ReserveAndResize(CgiUnescape(res.begin(), s).size());
  67. return res;
  68. }
  69. void TCgiParameters::InsertEscaped(const TStringBuf name, const TStringBuf value) {
  70. InsertUnescaped(DoUnescape(name), DoUnescape(value));
  71. }
  72. template <bool addAll, class F>
  73. static inline void DoScan(const TStringBuf s, F& f) {
  74. ScanKeyValue<addAll, '&', '='>(s, f);
  75. }
  76. struct TAddEscaped {
  77. TCgiParameters* C;
  78. inline void operator()(const TStringBuf key, const TStringBuf val) {
  79. C->InsertEscaped(key, val);
  80. }
  81. };
  82. void TCgiParameters::Scan(const TStringBuf query, bool form) {
  83. Flush();
  84. form ? ScanAdd(query) : ScanAddAll(query);
  85. }
  86. void TCgiParameters::ScanAdd(const TStringBuf query) {
  87. TAddEscaped f = {this};
  88. DoScan<false>(query, f);
  89. }
  90. void TCgiParameters::ScanAddUnescaped(const TStringBuf query) {
  91. auto f = [this](const TStringBuf key, const TStringBuf val) {
  92. this->InsertUnescaped(key, val);
  93. };
  94. DoScan<false>(query, f);
  95. }
  96. void TCgiParameters::ScanAddAllUnescaped(const TStringBuf query) {
  97. auto f = [this](const TStringBuf key, const TStringBuf val) {
  98. this->InsertUnescaped(key, val);
  99. };
  100. DoScan<true>(query, f);
  101. }
  102. void TCgiParameters::ScanAddAll(const TStringBuf query) {
  103. TAddEscaped f = {this};
  104. DoScan<true>(query, f);
  105. }
  106. TString TCgiParameters::Print() const {
  107. TString res;
  108. res.reserve(PrintSize());
  109. const char* end = Print(res.begin());
  110. res.ReserveAndResize(end - res.data());
  111. return res;
  112. }
  113. char* TCgiParameters::Print(char* res) const {
  114. if (empty()) {
  115. return res;
  116. }
  117. for (auto i = begin();;) {
  118. res = CGIEscape(res, i->first);
  119. *res++ = '=';
  120. res = CGIEscape(res, i->second);
  121. if (++i == end()) {
  122. break;
  123. }
  124. *res++ = '&';
  125. }
  126. return res;
  127. }
  128. size_t TCgiParameters::PrintSize() const noexcept {
  129. size_t res = size(); // for '&'
  130. for (const auto& i : *this) {
  131. res += CgiEscapeBufLen(i.first.size() + i.second.size()); // extra zero will be used for '='
  132. }
  133. return res;
  134. }
  135. TString TCgiParameters::QuotedPrint(const char* safe) const {
  136. if (empty()) {
  137. return TString();
  138. }
  139. TString res;
  140. res.ReserveAndResize(PrintSize());
  141. char* ptr = res.begin();
  142. for (auto i = begin();;) {
  143. ptr = Quote(ptr, i->first, safe);
  144. *ptr++ = '=';
  145. ptr = Quote(ptr, i->second, safe);
  146. if (++i == end()) {
  147. break;
  148. }
  149. *ptr++ = '&';
  150. }
  151. res.ReserveAndResize(ptr - res.data());
  152. return res;
  153. }
  154. TCgiParameters::const_iterator TCgiParameters::Find(const TStringBuf name, size_t pos) const noexcept {
  155. const auto pair = equal_range(name);
  156. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  157. if (0 == pos) {
  158. return it;
  159. }
  160. }
  161. return end();
  162. }
  163. bool TCgiParameters::Has(const TStringBuf name, const TStringBuf value) const noexcept {
  164. const auto pair = equal_range(name);
  165. for (auto it = pair.first; it != pair.second; ++it) {
  166. if (value == it->second) {
  167. return true;
  168. }
  169. }
  170. return false;
  171. }
  172. TQuickCgiParam::TQuickCgiParam(const TStringBuf cgiParamStr) {
  173. UnescapeBuf.reserve(CgiUnescapeBufLen(cgiParamStr.size()));
  174. char* buf = UnescapeBuf.begin();
  175. auto f = [this, &buf](const TStringBuf key, const TStringBuf val) {
  176. TStringBuf name = CgiUnescapeBuf(buf, key);
  177. buf += name.size() + 1;
  178. TStringBuf value = CgiUnescapeBuf(buf, val);
  179. buf += value.size() + 1;
  180. Y_ASSERT(buf <= UnescapeBuf.begin() + UnescapeBuf.capacity() + 1 /*trailing zero*/);
  181. emplace(name, value);
  182. };
  183. DoScan<false>(cgiParamStr, f);
  184. if (buf != UnescapeBuf.begin()) {
  185. UnescapeBuf.ReserveAndResize(buf - UnescapeBuf.begin() - 1 /*trailing zero*/);
  186. }
  187. }
  188. const TStringBuf& TQuickCgiParam::Get(const TStringBuf name, size_t pos) const noexcept {
  189. const auto pair = equal_range(name);
  190. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  191. if (0 == pos) {
  192. return it->second;
  193. }
  194. }
  195. return Default<TStringBuf>();
  196. }
  197. bool TQuickCgiParam::Has(const TStringBuf name, const TStringBuf value) const noexcept {
  198. const auto pair = equal_range(name);
  199. for (auto it = pair.first; it != pair.second; ++it) {
  200. if (value == it->second) {
  201. return true;
  202. }
  203. }
  204. return false;
  205. }