qargs.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include "qargs.h"
  2. #include <string>
  3. #include <vector>
  4. namespace NUri {
  5. namespace NOnStackArgsList {
  6. struct TQArgNode {
  7. TStringBuf Name;
  8. TStringBuf Value;
  9. TStringBuf All;
  10. };
  11. const char* SkipDelimiter(const char* str, const char* end) {
  12. while (str != end)
  13. if (*str == '&')
  14. ++str;
  15. else
  16. break;
  17. return str;
  18. }
  19. /// return next pos or 0 if error
  20. const char* ExtractArgData(const char* pos, const char* end, TQArgNode& arg) {
  21. const char* nameStart = pos;
  22. const char* nextArg = strchr(pos, '&');
  23. const char* valueStart = strchr(pos, '=');
  24. if (valueStart && nextArg && valueStart < nextArg) // a=1& or a=&
  25. {
  26. arg.Name = TStringBuf(nameStart, valueStart - nameStart);
  27. arg.Value = TStringBuf(valueStart + 1, nextArg - valueStart - 1);
  28. arg.All = TStringBuf(nameStart, nextArg - nameStart);
  29. return nextArg;
  30. } else if (valueStart && nextArg && valueStart > nextArg) // a&b=2
  31. {
  32. arg.Name = TStringBuf(nameStart, nextArg - nameStart);
  33. arg.All = arg.Name;
  34. return nextArg;
  35. } else if (valueStart && !nextArg) // a=1 or a=
  36. {
  37. arg.Name = TStringBuf(nameStart, valueStart - nameStart);
  38. arg.Value = TStringBuf(valueStart + 1, end - valueStart - 1);
  39. arg.All = TStringBuf(nameStart, end - nameStart);
  40. return end;
  41. } else if (!valueStart && nextArg) // a&b
  42. {
  43. arg.Name = TStringBuf(nameStart, nextArg - nameStart);
  44. arg.All = arg.Name;
  45. return nextArg;
  46. } else { // a
  47. arg.Name = TStringBuf(nameStart, end - nameStart);
  48. arg.All = arg.Name;
  49. return end;
  50. }
  51. }
  52. }
  53. using namespace NOnStackArgsList;
  54. class TQueryArgProcessing::Pipeline {
  55. public:
  56. Pipeline(TQueryArgProcessing& parent, TUri& subject)
  57. : Parent(parent)
  58. , Subject(subject)
  59. , IsDirty(false)
  60. {
  61. }
  62. TQueryArg::EProcessed Process() {
  63. const TStringBuf& query = Subject.GetField(NUri::TField::FieldQuery);
  64. if (query.empty())
  65. return ProcessEmpty();
  66. const char* start = query.data();
  67. return Parse(start, start + query.length());
  68. }
  69. TQueryArg::EProcessed ProcessEmpty() {
  70. if (Parent.Flags & TQueryArg::FeatureRemoveEmptyQuery)
  71. Subject.FldClr(NUri::TField::FieldQuery);
  72. return TQueryArg::ProcessedOK;
  73. }
  74. TQueryArg::EProcessed Parse(const char* str, const char* end) {
  75. if (str != end)
  76. Nodes.reserve(8);
  77. while (str != end) {
  78. str = SkipDelimiter(str, end);
  79. TQArgNode current;
  80. str = ExtractArgData(str, end, current);
  81. if (!str)
  82. return TQueryArg::ProcessedMalformed;
  83. if (Parent.Flags & TQueryArg::FeatureFilter) {
  84. TQueryArg arg = {current.Name, current.Value};
  85. if (!Parent.Filter(arg, Parent.FilterData)) {
  86. IsDirty = true;
  87. continue;
  88. }
  89. }
  90. Nodes.push_back(current);
  91. }
  92. if (Parent.Flags & TQueryArg::FeatureSortByName) {
  93. std::stable_sort(Nodes.begin(), Nodes.end(), [](auto l, auto r) {
  94. return l.Name < r.Name;
  95. });
  96. IsDirty = true;
  97. }
  98. return FinalizeParsing();
  99. }
  100. TQueryArg::EProcessed FinalizeParsing() {
  101. if (!IsDirty)
  102. return TQueryArg::ProcessedOK;
  103. bool dirty = Render();
  104. bool rewrite = Parent.Flags & TQueryArg::FeatureRewriteDirty;
  105. if (dirty && rewrite)
  106. Subject.Rewrite();
  107. return (!dirty || rewrite) ? TQueryArg::ProcessedOK : TQueryArg::ProcessedDirty;
  108. }
  109. bool Render() {
  110. std::string& result = Parent.Buffer;
  111. result.clear();
  112. result.reserve(Subject.GetField(NUri::TField::FieldQuery).length());
  113. bool first = true;
  114. for (const auto& node: Nodes)
  115. {
  116. if (!first)
  117. result.append("&");
  118. result.append(node.All);
  119. first = false;
  120. }
  121. if (result.empty())
  122. return RenderEmpty();
  123. else
  124. return Subject.FldMemSet(NUri::TField::FieldQuery, result);
  125. }
  126. bool RenderEmpty() {
  127. if (Parent.Flags & TQueryArg::FeatureRemoveEmptyQuery)
  128. Subject.FldClr(NUri::TField::FieldQuery);
  129. return false;
  130. }
  131. private:
  132. TQueryArgProcessing& Parent;
  133. TUri& Subject;
  134. std::vector<TQArgNode> Nodes;
  135. bool IsDirty;
  136. };
  137. TQueryArgProcessing::TQueryArgProcessing(ui32 flags, TQueryArgFilter filter, void* filterData)
  138. : Flags(flags)
  139. , Filter(filter)
  140. , FilterData(filterData)
  141. {
  142. }
  143. TQueryArg::EProcessed TQueryArgProcessing::Process(TUri& uri) {
  144. Pipeline pipeline(*this, uri);
  145. return pipeline.Process();
  146. }
  147. }