aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/cgiparam/cgiparam.h
blob: 87d1ab0ad45b43dedc5407c04b85ac50fc21a8d5 (plain) (tree)
1
2
3
4
5
6
7
8
9
            
 

                                                
                             
                                
                                
 
                           

                                 
                                                                       


                                               
                                                          
       
                               
 
                                                           
                          
     
 
                                                                          
 

                              
 
                                           
 
                                                              
                           
 
                                
                       
 

                                                            
                                                         
                                                
 



                                                                                 
                          
                                 
                   
                                      
 



                                                                                
                   
                                                                   
     







                                                                                     

                                            


                                                 
                                                                                    
 
                                                                      
 
                         
                                                               


                                                                             
                                                                        
     




                                                               
 





                                                                                           
 
                                                                         
                                       

                                                               
                                                                      
                                                                                      
 
                                                             
                                                            
 
                                                                                      
                                                   
 
                          
                           
         
 
                                 
     
  





                                                                                                       
                                                                                              


                                                                                
                                                          

                                                                                         
                                            
                                                         
                                                                         
     






                                                                                           
                               

                                                          



                                                                           


                                            
                                                                                       


                        
#pragma once

#include <library/cpp/iterator/iterate_values.h>

#include <util/generic/iterator_range.h>
#include <util/generic/map.h>
#include <util/generic/strbuf.h>
#include <util/generic/string.h>

#include <initializer_list>

struct TStringLess {
    template <class T1, class T2>
    inline bool operator()(const T1& t1, const T2& t2) const noexcept {
        return TStringBuf(t1) < TStringBuf(t2);
    }
};

class TCgiParameters: public TMultiMap<TString, TString> {
public:
    TCgiParameters() = default;

    explicit TCgiParameters(const TStringBuf cgiParamStr) {
        Scan(cgiParamStr);
    }

    TCgiParameters(std::initializer_list<std::pair<TString, TString>> 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 <name1>=<value1>&<name2>=<value2>&...
     * @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 <typename TName, typename TValue>
    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<TName>(name), std::forward<TValue>(value));
    }
#else
    template <typename TName, typename TValue>
    inline void InsertUnescaped(TName&& name, TValue&& value) {
        emplace(TString(name), TString(value));
    }
#endif

    // replace all values for a given key with new values
    template <typename TIter>
    void ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd);

    void ReplaceUnescaped(const TStringBuf key, std::initializer_list<TStringBuf> 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);

    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();
    }
};

template <typename TIter>
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<TStringBuf, TStringBuf> {
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;
};