#include "httpreqdata.h" #include 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(); }