diff options
| author | arcadia-devtools <[email protected]> | 2022-02-17 12:04:09 +0300 | 
|---|---|---|
| committer | arcadia-devtools <[email protected]> | 2022-02-17 12:04:09 +0300 | 
| commit | 2c8e314f8fff8633fe2cf026badfbf6180845ae0 (patch) | |
| tree | c3b650d13934ec1315e3660d60fd2275f09b03a7 | |
| parent | a49ae9d891c35087b242c854f69880fd9fecbddd (diff) | |
intermediate changes
ref:d5f945ecdc1f5af1ad57e12787c6b8ed1a9f0f12
18 files changed, 561 insertions, 182 deletions
| diff --git a/build/conf/compilers/msvc_compiler.conf b/build/conf/compilers/msvc_compiler.conf index b57425ab02e..3f3cffa5bcb 100644 --- a/build/conf/compilers/msvc_compiler.conf +++ b/build/conf/compilers/msvc_compiler.conf @@ -90,8 +90,7 @@ when ($CLANG_CL == "yes") {              -Wno-defaulted-function-deleted \              -Wno-deprecated-enum-enum-conversion \              -Wno-ambiguous-reversed-operator \ -            -Wno-deprecated-enum-float-conversion \ -            -Wno-pointer-to-int-cast +            -Wno-deprecated-enum-float-conversion      }      when ($IDE_MSVS == "yes") { diff --git a/build/conf/settings.conf b/build/conf/settings.conf index dbcdec23ef4..713f12b4dfc 100644 --- a/build/conf/settings.conf +++ b/build/conf/settings.conf @@ -3,6 +3,11 @@ JSON_CACHE_IS_ATTACHED=yes  USE_ADDINCL_WITHOUT_FOR_AS_ADDINCL_FOR_C=yes  LANGS_REQUIRE_BUILD_AND_SRC_ROOTS=c asm cython proto flatc swig ydl nlg +CHKPEERS_GLOBAL_SRCS=no +when ($AUTOCHECK == "yes") { +    CHKPEERS_GLOBAL_SRCS=yes +} +  # NOTE! Only foldable vars should be listed here  _FOLDABLE_VARS_=\      CL_WRAPPER \ diff --git a/library/cpp/case_insensitive_string/case_insensitive_char_traits.cpp b/library/cpp/case_insensitive_string/case_insensitive_char_traits.cpp new file mode 100644 index 00000000000..14e6d1d51f8 --- /dev/null +++ b/library/cpp/case_insensitive_string/case_insensitive_char_traits.cpp @@ -0,0 +1,34 @@ +#include "case_insensitive_char_traits.h" +#include "case_insensitive_string.h" + +#include <util/string/escape.h> + +int TCaseInsensitiveCharTraits::compare(const char* s1, const char* s2, std::size_t n) { +    while (n-- != 0) { +        if (to_upper(*s1) < to_upper(*s2)) { +            return -1; +        } +        if (to_upper(*s1) > to_upper(*s2)) { +            return 1; +        } +        ++s1; +        ++s2; +    } +    return 0; +} + +const char* TCaseInsensitiveCharTraits::find(const char* s, std::size_t n, char a) { +    auto const ua(to_upper(a)); +    while (n-- != 0) { +        if (to_upper(*s) == ua) +            return s; +        s++; +    } +    return nullptr; +} + +TCaseInsensitiveString EscapeC(const TCaseInsensitiveString& str) { +    const auto result = EscapeC(str.data(), str.size()); +    return {result.data(), result.size()}; +} + diff --git a/library/cpp/case_insensitive_string/case_insensitive_char_traits.h b/library/cpp/case_insensitive_string/case_insensitive_char_traits.h new file mode 100644 index 00000000000..2717893c102 --- /dev/null +++ b/library/cpp/case_insensitive_string/case_insensitive_char_traits.h @@ -0,0 +1,30 @@ +#pragma once + +#include <contrib/libs/libc_compat/string.h> + +#include <string> + +struct TCaseInsensitiveCharTraits : private std::char_traits<char> { +    static bool eq(char c1, char c2) { +        return to_upper(c1) == to_upper(c2); +    } + +    static bool lt(char c1, char c2) { +        return to_upper(c1) < to_upper(c2); +    } + +    static int compare(const char* s1, const char* s2, std::size_t n); + +    static const char* find(const char* s, std::size_t n, char a); + +    using std::char_traits<char>::assign; +    using std::char_traits<char>::char_type; +    using std::char_traits<char>::copy; +    using std::char_traits<char>::length; +    using std::char_traits<char>::move; + +private: +    static char to_upper(char ch) { +        return std::toupper((unsigned char)ch); +    } +}; diff --git a/library/cpp/case_insensitive_string/case_insensitive_string.cpp b/library/cpp/case_insensitive_string/case_insensitive_string.cpp new file mode 100644 index 00000000000..16c0f5ff7a2 --- /dev/null +++ b/library/cpp/case_insensitive_string/case_insensitive_string.cpp @@ -0,0 +1,22 @@ +#include "case_insensitive_string.h" + +#include <library/cpp/digest/murmur/murmur.h> + +size_t THash<TCaseInsensitiveStringBuf>::operator()(TCaseInsensitiveStringBuf str) const noexcept { +    TMurmurHash2A<size_t> hash; +    for (size_t i = 0; i < str.size(); ++i) { +        char lower = std::tolower(str[i]); +        hash.Update(&lower, 1); +    } +    return hash.Value(); +} + +template <> +void Out<TCaseInsensitiveString>(IOutputStream& o, const TCaseInsensitiveString& p) { +    o.Write(p.data(), p.size()); +} + +template <> +void Out<TCaseInsensitiveStringBuf>(IOutputStream& o, const TCaseInsensitiveStringBuf& p) { +    o.Write(p.data(), p.size()); +} diff --git a/library/cpp/case_insensitive_string/case_insensitive_string.h b/library/cpp/case_insensitive_string/case_insensitive_string.h new file mode 100644 index 00000000000..443de3e5f94 --- /dev/null +++ b/library/cpp/case_insensitive_string/case_insensitive_string.h @@ -0,0 +1,37 @@ +#pragma once + +#include "case_insensitive_char_traits.h" + +#include <util/generic/strbuf.h> +#include <util/generic/string.h> +#include <util/generic/hash.h> +#include <util/string/split.h> + +using TCaseInsensitiveString = TBasicString<char, TCaseInsensitiveCharTraits>; +using TCaseInsensitiveStringBuf = TBasicStringBuf<char, TCaseInsensitiveCharTraits>; + +template <> +struct THash<TCaseInsensitiveStringBuf> { +    size_t operator()(TCaseInsensitiveStringBuf str) const noexcept; +}; + +template <> +struct THash<TCaseInsensitiveString> : THash<TCaseInsensitiveStringBuf> {}; + +namespace NStringSplitPrivate { + +    template<> +    struct TStringBufOfImpl<TCaseInsensitiveStringBuf> { +        /* +         * WARN: +         * StringSplitter does not use TCharTraits properly. +         * Splitting such strings is explicitly disabled. +         */ +        // using type = TCaseInsensitiveStringBuf; +    }; + +    template<> +    struct TStringBufOfImpl<TCaseInsensitiveString> : TStringBufOfImpl<TCaseInsensitiveStringBuf> { +    }; + +} // namespace NStringSplitPrivate diff --git a/library/cpp/case_insensitive_string/case_insensitive_string_ut.cpp b/library/cpp/case_insensitive_string/case_insensitive_string_ut.cpp new file mode 100644 index 00000000000..49f9c59c95b --- /dev/null +++ b/library/cpp/case_insensitive_string/case_insensitive_string_ut.cpp @@ -0,0 +1,65 @@ +#include "case_insensitive_string.h" + +#include <util/generic/string_ut.h> + +class TCaseInsensitiveStringTest : public TTestBase, private TStringTestImpl<TCaseInsensitiveString, TTestData<char>> { +public: +    UNIT_TEST_SUITE(TCaseInsensitiveStringTest); +    UNIT_TEST(TestOperators); +    UNIT_TEST(TestOperatorsCI); + +    UNIT_TEST_SUITE_END(); +}; + +UNIT_TEST_SUITE_REGISTRATION(TCaseInsensitiveStringTest); + +Y_UNIT_TEST_SUITE(TCaseInsensitiveStringTestEx) { +    Y_UNIT_TEST(BasicTString) { +        TCaseInsensitiveString foo("foo"); +        TCaseInsensitiveString FOO("FOO"); +        TCaseInsensitiveString Bar("Bar"); +        TCaseInsensitiveString bAR("bAR"); + +        UNIT_ASSERT_EQUAL(foo, FOO); +        UNIT_ASSERT_EQUAL(Bar, bAR); + +        constexpr TCaseInsensitiveStringBuf foobar("foobar"); +        UNIT_ASSERT(foobar.StartsWith(foo)); +        UNIT_ASSERT(foobar.StartsWith(FOO)); +        UNIT_ASSERT(foobar.EndsWith(Bar)); +        UNIT_ASSERT(foobar.EndsWith(bAR)); +        UNIT_ASSERT(foobar.Contains(FOO)); +        UNIT_ASSERT(foobar.Contains(Bar)); +    } + +    Y_UNIT_TEST(BasicStdString) { +        using TCaseInsensitiveStdString = std::basic_string<char, TCaseInsensitiveCharTraits>; +        using TCaseInsensitiveStringView = std::basic_string_view<char, TCaseInsensitiveCharTraits>; + +        TCaseInsensitiveStdString foo("foo"); +        TCaseInsensitiveStdString FOO("FOO"); +        TCaseInsensitiveStdString Bar("Bar"); +        TCaseInsensitiveStdString bAR("bAR"); + +        UNIT_ASSERT_EQUAL(foo, FOO); +        UNIT_ASSERT_EQUAL(Bar, bAR); + +        constexpr TCaseInsensitiveStringView foobar("foobar"); +        UNIT_ASSERT(foobar.starts_with(foo)); +        UNIT_ASSERT(foobar.starts_with(FOO)); +        UNIT_ASSERT(foobar.ends_with(Bar)); +        UNIT_ASSERT(foobar.ends_with(bAR)); +        //TODO: test contains after C++23 +    } + +/* +    Y_UNIT_TEST(TestSplit) { +        TCaseInsensitiveStringBuf input("splitAmeAbro"); +        TVector<TCaseInsensitiveStringBuf> expected{"split", "me", "bro"}; + +        TVector<TCaseInsensitiveStringBuf> split = StringSplitter(input).Split('a'); + +        UNIT_ASSERT_VALUES_EQUAL(split, expected); +    } +*/ +} diff --git a/library/cpp/case_insensitive_string/ut/ya.make b/library/cpp/case_insensitive_string/ut/ya.make new file mode 100644 index 00000000000..b209d4571e5 --- /dev/null +++ b/library/cpp/case_insensitive_string/ut/ya.make @@ -0,0 +1,9 @@ +OWNER(eeight) + +UNITTEST_FOR(library/cpp/case_insensitive_string) + +SRCS( +    case_insensitive_string_ut.cpp +) + +END() diff --git a/library/cpp/case_insensitive_string/ya.make b/library/cpp/case_insensitive_string/ya.make new file mode 100644 index 00000000000..dfca415e6b9 --- /dev/null +++ b/library/cpp/case_insensitive_string/ya.make @@ -0,0 +1,17 @@ +OWNER(eeight) + +LIBRARY() + +SRCS( +    case_insensitive_char_traits.cpp +    case_insensitive_string.cpp +) + +PEERDIR( +    contrib/libs/libc_compat +    library/cpp/digest/murmur +) + +END() + +RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/digest/murmur/murmur.cpp b/library/cpp/digest/murmur/murmur.cpp new file mode 100644 index 00000000000..7c7c1c0ff70 --- /dev/null +++ b/library/cpp/digest/murmur/murmur.cpp @@ -0,0 +1 @@ +#include "murmur.h" diff --git a/library/cpp/digest/murmur/murmur.h b/library/cpp/digest/murmur/murmur.h new file mode 100644 index 00000000000..cbf28864128 --- /dev/null +++ b/library/cpp/digest/murmur/murmur.h @@ -0,0 +1,100 @@ +#pragma once + +#include <util/system/defaults.h> +#include <util/system/unaligned_mem.h> + +/* + * https://sites.google.com/site/murmurhash/ + */ + +namespace NMurmurPrivate { +    template <size_t> +    struct TMurmurHash2ATraits; + +    template <> +    struct TMurmurHash2ATraits<32> { +        using TValue = ui32; +        static const TValue Multiplier = 0x5bd1e995; +        enum { R1 = 24, +               R2 = 13, +               R3 = 15 }; +    }; + +    template <> +    struct TMurmurHash2ATraits<64> { +        using TValue = ui64; +        static const TValue Multiplier = ULL(0xc6a4a7935bd1e995); +        enum { R1 = 47, +               R2 = 47, +               R3 = 47 }; +    }; +} + +template <class T> +class TMurmurHash2A { +private: +    using TTraits = typename NMurmurPrivate::TMurmurHash2ATraits<8 * sizeof(T)>; +    using TValue = typename TTraits::TValue; + +public: +    inline TMurmurHash2A(TValue seed = 0) +        : Hash(seed) +    { +    } + +    inline TMurmurHash2A& Update(const void* buf, size_t len) noexcept { +        Size += len; + +        MixTail(buf, len); + +        while (len >= sizeof(TValue)) { +            Hash = Mix(Hash, ReadUnaligned<TValue>(buf)); +            buf = static_cast<const char*>(buf) + sizeof(TValue); +            len -= sizeof(TValue); +        } + +        MixTail(buf, len); + +        return *this; +    } + +    inline TValue Value() const noexcept { +        TValue hash = Mix(Mix(Hash, Tail), (TValue)Size); + +        hash ^= hash >> TTraits::R2; +        hash *= TTraits::Multiplier; +        hash ^= hash >> TTraits::R3; + +        return hash; +    } + +private: +    static inline TValue Mix(TValue h, TValue k) noexcept { +        k *= TTraits::Multiplier; +        k ^= k >> TTraits::R1; +        k *= TTraits::Multiplier; +        h *= TTraits::Multiplier; +        h ^= k; +        return h; +    } + +    inline void MixTail(const void*& buf, size_t& len) noexcept { +        while (len && (len < sizeof(TValue) || Count)) { +            Tail |= (TValue) * ((const unsigned char*&)buf)++ << (Count++ * 8); + +            --len; + +            if (Count == sizeof(TValue)) { +                Hash = Mix(Hash, Tail); +                Tail = 0; +                Count = 0; +            } +        } +    } + +private: +    TValue Hash = 0; +    TValue Tail = 0; +    size_t Count = 0; +    size_t Size = 0; +}; diff --git a/library/cpp/digest/murmur/murmur_ut.cpp b/library/cpp/digest/murmur/murmur_ut.cpp new file mode 100644 index 00000000000..3447980c8cf --- /dev/null +++ b/library/cpp/digest/murmur/murmur_ut.cpp @@ -0,0 +1,61 @@ +#include "murmur.h" + +#include <library/cpp/testing/unittest/registar.h> + +class TMurmurHashTest: public TTestBase { +private: +    UNIT_TEST_SUITE(TMurmurHashTest); +    UNIT_TEST(TestHash2A32) +    UNIT_TEST(TestHash2A64) +    UNIT_TEST(TestUnaligned) +    UNIT_TEST_SUITE_END(); + +private: +    inline void TestHash2A32() { +        ui8 buf[256]; + +        for (size_t i = 0; i < 256; ++i) { +            buf[i] = i; +        } + +        Test2A<ui32>(buf, 256, 0, 97, 178525084UL); +        Test2A<ui32>(buf, 256, 128, 193, 178525084UL); +        Test2A<ui32>(buf, 255, 0, 97, 2459858906UL); +        Test2A<ui32>(buf, 255, 128, 193, 2459858906UL); +    } + +    inline void TestHash2A64() { +        ui8 buf[256]; + +        for (size_t i = 0; i < 256; ++i) { +            buf[i] = i; +        } + +        Test2A<ui64>(buf, 256, 0, 97, ULL(15099340606808450747)); +        Test2A<ui64>(buf, 256, 128, 193, ULL(15099340606808450747)); +        Test2A<ui64>(buf, 255, 0, 97, ULL(8331973280124075880)); +        Test2A<ui64>(buf, 255, 128, 193, ULL(8331973280124075880)); +    } + +    inline void TestUnaligned() { +        ui8 buf[257]; +        for (size_t i = 0; i < 256; ++i) { +            buf[i + 1] = i; +        } +        Test2A<ui64>(buf + 1, 256, 0, 97, ULL(15099340606808450747)); +        Test2A<ui64>(buf + 1, 256, 128, 193, ULL(15099340606808450747)); +        Test2A<ui64>(buf + 1, 255, 0, 97, ULL(8331973280124075880)); +        Test2A<ui64>(buf + 1, 255, 128, 193, ULL(8331973280124075880)); +    } + +private: +    template <class T> +    static inline void Test2A(const ui8* data, size_t len, size_t split1, size_t split2, T expected) { +        const T value1 = TMurmurHash2A<T>().Update(data, split1).Update(data + split1, len - split1).Value(); +        const T value2 = TMurmurHash2A<T>().Update(data, split2).Update(data + split2, len - split2).Value(); +        UNIT_ASSERT_VALUES_EQUAL(value1, value2); +        UNIT_ASSERT_VALUES_EQUAL(value1, expected); +    } +}; + +UNIT_TEST_SUITE_REGISTRATION(TMurmurHashTest); diff --git a/library/cpp/digest/murmur/ut/ya.make b/library/cpp/digest/murmur/ut/ya.make new file mode 100644 index 00000000000..3405399779f --- /dev/null +++ b/library/cpp/digest/murmur/ut/ya.make @@ -0,0 +1,15 @@ +UNITTEST() + +OWNER(elantsev) + +PEERDIR( +    ADDINCL library/cpp/digest/murmur +) + +SRCDIR(library/cpp/digest/murmur) + +SRCS( +    murmur_ut.cpp +) + +END() diff --git a/library/cpp/digest/murmur/ya.make b/library/cpp/digest/murmur/ya.make new file mode 100644 index 00000000000..5647cc75e15 --- /dev/null +++ b/library/cpp/digest/murmur/ya.make @@ -0,0 +1,9 @@ +LIBRARY() + +OWNER(elantsev) + +SRCS( +    murmur.cpp +) + +END() diff --git a/library/cpp/http/misc/httpreqdata.cpp b/library/cpp/http/misc/httpreqdata.cpp index f6951f68cd9..f02611bc582 100644 --- a/library/cpp/http/misc/httpreqdata.cpp +++ b/library/cpp/http/misc/httpreqdata.cpp @@ -1,145 +1,123 @@  #include "httpreqdata.h" +#include <library/cpp/case_insensitive_string/case_insensitive_string.h>  #include <util/stream/mem.h>  TBaseServerRequestData::TBaseServerRequestData(SOCKET s) -    : Addr(nullptr) -    , Host() -    , Port() -    , Path(nullptr) -    , Search(nullptr) -    , SearchLength(0) -    , Socket(s) -    , BeginTime(MicroSeconds()) +    : Socket_(s) +    , BeginTime_(MicroSeconds())  {  } -TBaseServerRequestData::TBaseServerRequestData(const char* qs, SOCKET s) -    : Addr(nullptr) -    , Host() -    , Port() -    , Path(nullptr) -    , Search((char*)qs) -    , SearchLength(qs ? strlen(qs) : 0) -    , OrigSearch(Search, SearchLength) -    , Socket(s) -    , BeginTime(MicroSeconds()) +TBaseServerRequestData::TBaseServerRequestData(TStringBuf qs, SOCKET s) +    : Query_(qs) +    , OrigQuery_(Query_) +    , Socket_(s) +    , BeginTime_(MicroSeconds())  {  } -void TBaseServerRequestData::AppendQueryString(const char* str, size_t length) { -    if (Y_UNLIKELY(Search)) { -        Y_ASSERT(strlen(Search) == SearchLength); -        ModifiedQueryString.Reserve(SearchLength + length + 2); -        ModifiedQueryString.Assign(Search, SearchLength); -        if (SearchLength > 0 && Search[SearchLength - 1] != '&' && -            length > 0 && str[0] != '&') { -            ModifiedQueryString.Append('&'); -        } -        ModifiedQueryString.Append(str, length); -    } else { -        ModifiedQueryString.Reserve(length + 1); -        ModifiedQueryString.Assign(str, length); -    } -    ModifiedQueryString.Append('\0'); -    Search = ModifiedQueryString.data(); -    SearchLength = ModifiedQueryString.size() - 1; // ignore terminator +void TBaseServerRequestData::AppendQueryString(TStringBuf str) { +    if (Y_UNLIKELY(!Query_.empty())) { +        TStringBuf separator = !Query_.EndsWith('&') && !str.StartsWith('&') ? "&"sv : ""sv; +        ModifiedQueryString_ = TString::Join(Query_, separator, str); +     } else { +        ModifiedQueryString_ = str; +     } +    Query_ = ModifiedQueryString_;  }  void TBaseServerRequestData::SetRemoteAddr(TStringBuf addr) { -    TMemoryOutput out(AddrData, Y_ARRAY_SIZE(AddrData) - 1); -    out.Write(addr.substr(0, Y_ARRAY_SIZE(AddrData) - 1)); -    *out.Buf() = '\0'; - -    Addr = AddrData; +    Addr_.ConstructInPlace(addr.substr(0, INET6_ADDRSTRLEN - 1));  } -const char* TBaseServerRequestData::RemoteAddr() const { -    if (!Addr) { -        *AddrData = 0; -        GetRemoteAddr(Socket, AddrData, sizeof(AddrData)); -        Addr = AddrData; -    } - -    return Addr; -} +TStringBuf TBaseServerRequestData::RemoteAddr() const { +    if (!Addr_) { +        auto& addr = Addr_.ConstructInPlace(); +        addr.ReserveAndResize(INET6_ADDRSTRLEN); +        if (GetRemoteAddr(Socket_, addr.begin(), sizeof(INET6_ADDRSTRLEN))) { +            if (auto pos = addr.find('\0'); pos != TString::npos) { +                addr.resize(pos); +            } +        } else { +            addr.clear(); +        } +     } -const char* TBaseServerRequestData::HeaderIn(TStringBuf key) const { -    auto it = HeadersIn_.find(key); +    return *Addr_; + } -    if (it == HeadersIn_.end()) { -        return nullptr; -    } +const TString* TBaseServerRequestData::HeaderIn(TStringBuf key) const { +    return HeadersIn_.FindPtr(key); +} -    return it->second.data(); +TStringBuf TBaseServerRequestData::HeaderInOrEmpty(TStringBuf key) const { +    const auto* ptr = HeaderIn(key); +    return ptr ? TStringBuf{*ptr} : TStringBuf{};  }  TString TBaseServerRequestData::HeaderByIndex(size_t n) const noexcept { -    if (n >= HeadersCount()) { -        return nullptr; +    if (n >= HeadersIn_.size()) { +        return {};      } -    THttpHeadersContainer::const_iterator i = HeadersIn_.begin(); - -    while (n) { -        ++i; -        --n; -    } +    const auto& [key, value] = *std::next(HeadersIn_.begin(), n); -    return TString(i->first) + TStringBuf(": ") + i->second; +    return TString::Join(key, ": ", value);  } -const char* TBaseServerRequestData::Environment(const char* key) const { -    if (stricmp(key, "REMOTE_ADDR") == 0) { -        const char* ip = HeaderIn("X-Real-IP"); -        if (ip) -            return ip; -        return RemoteAddr(); -    } else if (stricmp(key, "QUERY_STRING") == 0) { -        return QueryString(); -    } else if (stricmp(key, "SERVER_NAME") == 0) { -        return ServerName().data(); -    } else if (stricmp(key, "SERVER_PORT") == 0) { -        return ServerPort().data(); -    } else if (stricmp(key, "SCRIPT_NAME") == 0) { +TStringBuf TBaseServerRequestData::Environment(TStringBuf key) const { +    TCaseInsensitiveStringBuf ciKey(key.data(), key.size()); +    if (ciKey == "REMOTE_ADDR") { +        const auto ip = HeaderIn("X-Real-IP"); +        return ip ? *ip : RemoteAddr(); +    } else if (ciKey == "QUERY_STRING") { +        return Query(); +    } else if (ciKey == "SERVER_NAME") { +        return ServerName(); +    } else if (ciKey == "SERVER_PORT") { +        return ServerPort(); +    } else if (ciKey == "SCRIPT_NAME") {          return ScriptName();      } -    return nullptr; +    return {};  } -void TBaseServerRequestData::Clear() { + void TBaseServerRequestData::Clear() {      HeadersIn_.clear(); -    Addr = Path = Search = nullptr; -    OrigSearch = {}; -    SearchLength = 0; -    Host.clear(); -    Port.clear(); -    CurPage.remove(); -    ParseBuf.Clear(); -    BeginTime = MicroSeconds(); +    Addr_ = Nothing(); +    Path_.clear(); +    Query_ = {}; +    OrigQuery_ = {}; +    Host_.clear(); +    Port_.clear(); +    CurPage_.remove(); +    ParseBuf_.clear(); +    BeginTime_ = MicroSeconds();  } -const char* TBaseServerRequestData::GetCurPage() const { -    if (!CurPage && Host) { -        CurPage = "http://"; -        CurPage += Host; -        if (Port) { -            CurPage += ':'; -            CurPage += Port; +const TString& TBaseServerRequestData::GetCurPage() const { +    if (!CurPage_ && Host_) { +        CurPage_ = "http://"; +        CurPage_ += Host_; +        if (Port_) { +            CurPage_ += ':'; +            CurPage_ += Port_;          } -        CurPage += Path; -        if (Search) { -            CurPage += '?'; -            CurPage += Search; +        CurPage_ += Path_; +        if (Query_) { +            CurPage_ += '?'; +            CurPage_ += Query_;          }      } -    return CurPage.data(); +    return CurPage_;  } -bool TBaseServerRequestData::Parse(const char* origReq) { -    size_t origReqLength = strlen(origReq); -    ParseBuf.Assign(origReq, origReqLength + 1); -    char* req = ParseBuf.Data(); +bool TBaseServerRequestData::Parse(TStringBuf origReqBuf) { +    ParseBuf_.reserve(origReqBuf.size() + 1); +    ParseBuf_.assign(origReqBuf.begin(), origReqBuf.end()); +    ParseBuf_.push_back('\0'); +    char* req = ParseBuf_.data();      while (*req == ' ' || *req == '\t')          req++; @@ -161,20 +139,20 @@ bool TBaseServerRequestData::Parse(const char* origReq) {          *fragment = 0; // ignore fragment      else          fragment = urlEnd; -    Path = req; +    char* path = req;      // calculate Search length without additional strlen-ing -    Search = strchr(Path, '?'); -    if (Search) { -        *Search++ = 0; -        ptrdiff_t delta = fragment - Search; +    char* query = strchr(path, '?'); +    if (query) { +        *query++ = 0; +        ptrdiff_t delta = fragment - query;          // indeed, second case is a parse error -        SearchLength = (delta >= 0) ? delta : (urlEnd - Search); -        Y_ASSERT(strlen(Search) == SearchLength); +        Query_ = {query, static_cast<size_t>(delta >= 0 ? delta : (urlEnd - query))};      } else { -        SearchLength = 0; +        Query_ = {};      } -    OrigSearch = {Search, SearchLength}; +    Path_ = path; +    OrigQuery_ = Query_;      return true;  } @@ -185,12 +163,11 @@ void TBaseServerRequestData::AddHeader(const TString& name, const TString& value      if (stricmp(name.data(), "Host") == 0) {          size_t hostLen = strcspn(value.data(), ":");          if (value[hostLen] == ':') -            Port = value.substr(hostLen + 1); -        Host = value.substr(0, hostLen); +            Port_ = value.substr(hostLen + 1); +        Host_ = value.substr(0, hostLen);      }  } -void TBaseServerRequestData::SetPath(const TString& path) { -    PathStorage = TBuffer(path.data(), path.size() + 1); -    Path = PathStorage.Data(); +void TBaseServerRequestData::SetPath(TString path) { +    Path_ = std::move(path);  } diff --git a/library/cpp/http/misc/httpreqdata.h b/library/cpp/http/misc/httpreqdata.h index 16e59c4d78c..b5c9e446a99 100644 --- a/library/cpp/http/misc/httpreqdata.h +++ b/library/cpp/http/misc/httpreqdata.h @@ -13,52 +13,52 @@  #include <util/system/yassert.h>  #include <util/generic/string.h>  #include <util/datetime/base.h> -#include <util/generic/buffer.h> +#include <util/generic/vector.h> +#include <util/generic/maybe.h>  using THttpHeadersContainer = THashMap<TString, TString, TCIOps, TCIOps>;  class TBaseServerRequestData {  public:      TBaseServerRequestData(SOCKET s = INVALID_SOCKET); -    TBaseServerRequestData(const char* qs, SOCKET s = INVALID_SOCKET); +    TBaseServerRequestData(TStringBuf qs, SOCKET s = INVALID_SOCKET);      void SetHost(const TString& host, ui16 port) { -        Host = host; -        Port = ToString(port); +        Host_ = host; +        Port_ = ToString(port);      }      const TString& ServerName() const { -        return Host; +        return Host_;      }      NAddr::IRemoteAddrPtr ServerAddress() const { -        return NAddr::GetSockAddr(Socket); +        return NAddr::GetSockAddr(Socket_);      }      const TString& ServerPort() const { -        return Port; +        return Port_;      } -    const char* ScriptName() const { -        return Path; +    TStringBuf ScriptName() const { +        return Path_;      } -    const char* QueryString() const { -        return Search; +    TStringBuf Query() const { +        return Query_;      } -    TStringBuf QueryStringBuf() const { -        return TStringBuf(Search, SearchLength); +    TStringBuf OrigQuery() const { +        return OrigQuery_;      } -    TStringBuf OrigQueryStringBuf() const { -        return OrigSearch; -    } - -    void AppendQueryString(const char* str, size_t length); -    const char* RemoteAddr() const; +    void AppendQueryString(TStringBuf str); +    TStringBuf RemoteAddr() const;      void SetRemoteAddr(TStringBuf addr); -    const char* HeaderIn(TStringBuf key) const; +    // Returns nullptr when the header does not exist +    const TString* HeaderIn(TStringBuf key) const; +    // Throws on missing header +    TStringBuf HeaderInOrEmpty(TStringBuf key) const;      const THttpHeadersContainer& HeadersIn() const {          return HeadersIn_; @@ -69,39 +69,36 @@ public:      }      TString HeaderByIndex(size_t n) const noexcept; -    const char* Environment(const char* key) const; +    TStringBuf Environment(TStringBuf key) const;      void Clear();      void SetSocket(SOCKET s) noexcept { -        Socket = s; +        Socket_ = s;      }      ui64 RequestBeginTime() const noexcept { -        return BeginTime; +        return BeginTime_;      } -    void SetPath(const TString& path); -    const char* GetCurPage() const; -    bool Parse(const char* req); +    void SetPath(TString path); +    const TString& GetCurPage() const; +    bool Parse(TStringBuf req);      void AddHeader(const TString& name, const TString& value);  private: -    TBuffer PathStorage; -    mutable char* Addr; -    TString Host; -    TString Port; -    char* Path; -    char* Search; -    size_t SearchLength; // length of Search -    TStringBuf OrigSearch; +    mutable TMaybe<TString> Addr_; +    TString Host_; +    TString Port_; +    TString Path_; +    TStringBuf Query_; +    TStringBuf OrigQuery_;      THttpHeadersContainer HeadersIn_; -    mutable char AddrData[INET6_ADDRSTRLEN]; -    SOCKET Socket; -    ui64 BeginTime; -    mutable TString CurPage; -    TBuffer ParseBuf; -    TBuffer ModifiedQueryString; +    SOCKET Socket_; +    ui64 BeginTime_; +    mutable TString CurPage_; +    TVector<char> ParseBuf_; +    TString ModifiedQueryString_;  };  class TServerRequestData: public TBaseServerRequestData { @@ -110,14 +107,14 @@ public:          : TBaseServerRequestData(s)      {      } -    TServerRequestData(const char* qs, SOCKET s = INVALID_SOCKET) +    TServerRequestData(TStringBuf qs, SOCKET s = INVALID_SOCKET)          : TBaseServerRequestData(qs, s)      {          Scan();      }      void Scan() { -        CgiParam.Scan(QueryStringBuf()); +        CgiParam.Scan(Query());      }  public: diff --git a/library/cpp/http/misc/httpreqdata_ut.cpp b/library/cpp/http/misc/httpreqdata_ut.cpp index e7f16ef27c8..3e13046fd07 100644 --- a/library/cpp/http/misc/httpreqdata_ut.cpp +++ b/library/cpp/http/misc/httpreqdata_ut.cpp @@ -13,8 +13,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          sd.AddHeader("x-XxX", "y-yyy");          UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XX")), TStringBuf("y-yy")); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XXX")), TStringBuf("y-yyy")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("X-XX"), TStringBuf("y-yy")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("X-XXX"), TStringBuf("y-yyy"));      }      Y_UNIT_TEST(ComplexHeaders) { @@ -23,21 +23,21 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          sd.AddHeader("x-Xx", "y-yy");          UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 1); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XX")), TStringBuf("y-yy")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("X-XX"), TStringBuf("y-yy"));          sd.AddHeader("x-Xz", "y-yy");          UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-Xz")), TStringBuf("y-yy")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("X-Xz"), TStringBuf("y-yy"));          UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "zzz");          UNIT_ASSERT_VALUES_EQUAL(sd.ServerPort(), "1");          sd.AddHeader("Host", "1234");          UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 3); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("Host")), TStringBuf("1234")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("Host"), TStringBuf("1234"));          UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "1234");          sd.AddHeader("Host", "12345:678");          UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 3); -        UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("Host")), TStringBuf("12345:678")); +        UNIT_ASSERT_VALUES_EQUAL(sd.HeaderInOrEmpty("Host"), TStringBuf("12345:678"));          UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "12345");          UNIT_ASSERT_VALUES_EQUAL(sd.ServerPort(), "678");      } @@ -51,8 +51,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          // This should work          UNIT_ASSERT(rd.Parse(" /yandsearch?>a=fake&haha=da HTTP 1.1 OK")); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ">a=fake&haha=da"); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf()); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), ">a=fake&haha=da"); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), rd.OrigQuery());          rd.Scan();          UNIT_ASSERT(rd.CgiParam.Has("gta", "fake")); @@ -66,8 +66,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          const TString qs("gta=fake&haha=da");          TServerRequestData rd(qs.c_str()); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); -        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQuery(), qs);          UNIT_ASSERT(rd.CgiParam.Has("gta"));          UNIT_ASSERT(rd.CgiParam.Has("haha")); @@ -81,8 +81,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          TServerRequestData rd;          rd.Parse(header.c_str()); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); -        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQuery(), qs);          rd.Scan();          UNIT_ASSERT(rd.CgiParam.Has("gta")); @@ -94,8 +94,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          TServerRequestData rd;          rd.Parse(" /y#ndsearch?>a=fake&haha=da&uberParam=yes&q=? HTTP 1.1 OK"); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ""); -        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), ""); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), ""); +        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQuery(), "");          rd.Scan();          UNIT_ASSERT(rd.CgiParam.empty()); @@ -105,8 +105,8 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          TServerRequestData rd;          rd.Parse(" /yandsearch?#"); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), ""); -        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), ""); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), ""); +        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQuery(), "");          rd.Scan();          UNIT_ASSERT(rd.CgiParam.empty()); @@ -119,14 +119,14 @@ Y_UNIT_TEST_SUITE(TRequestServerDataTest) {          UNIT_ASSERT(rd.CgiParam.Has("gta", "fake"));          UNIT_ASSERT(rd.CgiParam.Has("haha", "da")); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf()); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), rd.OrigQuery());          constexpr TStringBuf appendix = "gta=true>a=new"; -        rd.AppendQueryString(appendix.data(), appendix.size()); +        rd.AppendQueryString(appendix); -        UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs + '&' + appendix); -        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs); +        UNIT_ASSERT_STRINGS_EQUAL(rd.Query(), qs + '&' + appendix); +        UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQuery(), qs);          rd.Scan(); diff --git a/library/cpp/http/misc/ya.make b/library/cpp/http/misc/ya.make index fceb3cf79c0..7eb44812189 100644 --- a/library/cpp/http/misc/ya.make +++ b/library/cpp/http/misc/ya.make @@ -15,6 +15,7 @@ SRCS(  )  PEERDIR( +    library/cpp/case_insensitive_string      library/cpp/cgiparam      library/cpp/digest/lower_case  ) | 
