diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/http/misc/httpreqdata.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/http/misc/httpreqdata.cpp')
-rw-r--r-- | library/cpp/http/misc/httpreqdata.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/library/cpp/http/misc/httpreqdata.cpp b/library/cpp/http/misc/httpreqdata.cpp new file mode 100644 index 0000000000..f6951f68cd --- /dev/null +++ b/library/cpp/http/misc/httpreqdata.cpp @@ -0,0 +1,196 @@ +#include "httpreqdata.h" + +#include <util/stream/mem.h> + +TBaseServerRequestData::TBaseServerRequestData(SOCKET s) + : Addr(nullptr) + , Host() + , Port() + , Path(nullptr) + , Search(nullptr) + , SearchLength(0) + , 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()) +{ +} + +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::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; +} + +const char* TBaseServerRequestData::RemoteAddr() const { + if (!Addr) { + *AddrData = 0; + GetRemoteAddr(Socket, AddrData, sizeof(AddrData)); + Addr = AddrData; + } + + return Addr; +} + +const char* TBaseServerRequestData::HeaderIn(TStringBuf key) const { + auto it = HeadersIn_.find(key); + + if (it == HeadersIn_.end()) { + return nullptr; + } + + return it->second.data(); +} + +TString TBaseServerRequestData::HeaderByIndex(size_t n) const noexcept { + if (n >= HeadersCount()) { + return nullptr; + } + + THttpHeadersContainer::const_iterator i = HeadersIn_.begin(); + + while (n) { + ++i; + --n; + } + + return TString(i->first) + TStringBuf(": ") + i->second; +} + +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) { + return ScriptName(); + } + return nullptr; +} + +void TBaseServerRequestData::Clear() { + HeadersIn_.clear(); + Addr = Path = Search = nullptr; + OrigSearch = {}; + SearchLength = 0; + 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; + } + CurPage += Path; + if (Search) { + CurPage += '?'; + CurPage += Search; + } + } + return CurPage.data(); +} + +bool TBaseServerRequestData::Parse(const char* origReq) { + size_t origReqLength = strlen(origReq); + ParseBuf.Assign(origReq, origReqLength + 1); + char* req = ParseBuf.Data(); + + while (*req == ' ' || *req == '\t') + req++; + if (*req != '/') + return false; // we are not a proxy + while (req[1] == '/') // remove redundant slashes + req++; + + // detect url end (can contain some garbage after whitespace, e.g. 'HTTP 1.1') + char* urlEnd = req; + while (*urlEnd && *urlEnd != ' ' && *urlEnd != '\t') + urlEnd++; + if (*urlEnd) + *urlEnd = 0; + + // cut fragment if exists + char* fragment = strchr(req, '#'); + if (fragment) + *fragment = 0; // ignore fragment + else + fragment = urlEnd; + Path = req; + + // calculate Search length without additional strlen-ing + Search = strchr(Path, '?'); + if (Search) { + *Search++ = 0; + ptrdiff_t delta = fragment - Search; + // indeed, second case is a parse error + SearchLength = (delta >= 0) ? delta : (urlEnd - Search); + Y_ASSERT(strlen(Search) == SearchLength); + } else { + SearchLength = 0; + } + OrigSearch = {Search, SearchLength}; + + return true; +} + +void TBaseServerRequestData::AddHeader(const TString& name, const TString& value) { + HeadersIn_[name] = 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); + } +} + +void TBaseServerRequestData::SetPath(const TString& path) { + PathStorage = TBuffer(path.data(), path.size() + 1); + Path = PathStorage.Data(); +} |