#pragma once #include #include #include #include #include #include class TCgiParameters: public TMultiMap { public: TCgiParameters() = default; explicit TCgiParameters(const TStringBuf cgiParamStr) { Scan(cgiParamStr); } TCgiParameters(std::initializer_list> il); void Flush() { erase(begin(), end()); } size_t EraseAll(const TStringBuf name); size_t NumOfValues(const TStringBuf name) const noexcept { return count(name); } TString operator()() const { return Print(); } void Scan(const TStringBuf cgiParStr, bool form = true); void ScanAdd(const TStringBuf cgiParStr); void ScanAddUnescaped(const TStringBuf cgiParStr); void ScanAddAllUnescaped(const TStringBuf cgiParStr); void ScanAddAll(const TStringBuf cgiParStr); /// Returns the string representation of all the stored parameters /** * @note The returned string has format =&=&... * @note Names and values in the returned string are CGI-escaped. */ TString Print() const; char* Print(char* res) const; Y_PURE_FUNCTION size_t PrintSize() const noexcept; /** The same as Print* except that RFC-3986 reserved characters are escaped. * @param safe - set of characters to be skipped in escaping */ TString QuotedPrint(const char* safe = "/") const; Y_PURE_FUNCTION auto Range(const TStringBuf name) const noexcept { return IterateValues(MakeIteratorRange(equal_range(name))); } Y_PURE_FUNCTION const_iterator Find(const TStringBuf name, size_t numOfValue = 0) const noexcept; Y_PURE_FUNCTION bool Has(const TStringBuf name, const TStringBuf value) const noexcept; Y_PURE_FUNCTION bool Has(const TStringBuf name) const noexcept { const auto pair = equal_range(name); return pair.first != pair.second; } /// Returns value by name /** * @note The returned value is CGI-unescaped. */ Y_PURE_FUNCTION const TString& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept; void InsertEscaped(const TStringBuf name, const TStringBuf value); #if !defined(__GLIBCXX__) template inline void InsertUnescaped(TName&& name, TValue&& value) { // TStringBuf use as TName or TValue is C++17 actually. // There is no pair constructor available in C++14 when required type // is not implicitly constructible from given type. // But libc++ pair allows this with C++14. emplace(std::forward(name), std::forward(value)); } #else template inline void InsertUnescaped(TName&& name, TValue&& value) { emplace(TString(name), TString(value)); } #endif // replace all values for a given key with new values template void ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd); void ReplaceUnescaped(const TStringBuf key, std::initializer_list values) { ReplaceUnescaped(key, values.begin(), values.end()); } void ReplaceUnescaped(const TStringBuf key, const TStringBuf value) { ReplaceUnescaped(key, {value}); } // join multiple values into a single one using a separator // if val is a [possibly empty] non-NULL string, append it as well void JoinUnescaped(const TStringBuf key, char sep, TStringBuf val = TStringBuf()); bool Erase(const TStringBuf name, size_t numOfValue = 0); bool Erase(const TStringBuf name, const TStringBuf val); bool ErasePattern(const TStringBuf name, const TStringBuf pat); inline const char* FormField(const TStringBuf name, size_t numOfValue = 0) const { const_iterator it = Find(name, numOfValue); if (it == end()) { return nullptr; } return it->second.data(); } inline TStringBuf FormFieldBuf(const TStringBuf name, size_t numOfValue = 0) const { const_iterator it = Find(name, numOfValue); if (it == end()) { return nullptr; } return it->second.data(); } }; template void TCgiParameters::ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd) { const auto oldRange = equal_range(key); auto current = oldRange.first; // reuse as many existing nodes as possible (probably none) for (; valuesBegin != valuesEnd && current != oldRange.second; ++valuesBegin, ++current) { current->second = *valuesBegin; } // if there were more nodes than we need to insert then erase remaining ones for (; current != oldRange.second; erase(current++)) { } // if there were less nodes than we need to insert then emplace the rest of the range if (valuesBegin != valuesEnd) { const TString keyStr = TString(key); for (; valuesBegin != valuesEnd; ++valuesBegin) { emplace_hint(oldRange.second, keyStr, TString(*valuesBegin)); } } } /** TQuickCgiParam is a faster non-editable version of TCgiParameters. * Care should be taken when replacing: * - note that the result of Get() is invalidated when TQuickCgiParam object is destroyed. */ class TQuickCgiParam: public TMultiMap { public: TQuickCgiParam() = default; explicit TQuickCgiParam(const TStringBuf cgiParamStr); Y_PURE_FUNCTION bool Has(const TStringBuf name, const TStringBuf value) const noexcept; Y_PURE_FUNCTION bool Has(const TStringBuf name) const noexcept { const auto pair = equal_range(name); return pair.first != pair.second; } Y_PURE_FUNCTION const TStringBuf& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept; private: TString UnescapeBuf; };