diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /library/cpp/http/server | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/http/server')
-rw-r--r-- | library/cpp/http/server/conn.cpp | 84 | ||||
-rw-r--r-- | library/cpp/http/server/conn.h | 56 | ||||
-rw-r--r-- | library/cpp/http/server/http.cpp | 566 | ||||
-rw-r--r-- | library/cpp/http/server/http.h | 86 | ||||
-rw-r--r-- | library/cpp/http/server/http_ex.cpp | 120 | ||||
-rw-r--r-- | library/cpp/http/server/http_ex.h | 24 | ||||
-rw-r--r-- | library/cpp/http/server/http_ut.cpp | 140 | ||||
-rw-r--r-- | library/cpp/http/server/options.cpp | 44 | ||||
-rw-r--r-- | library/cpp/http/server/options.h | 130 | ||||
-rw-r--r-- | library/cpp/http/server/response.cpp | 32 | ||||
-rw-r--r-- | library/cpp/http/server/response.h | 26 | ||||
-rw-r--r-- | library/cpp/http/server/response_ut.cpp | 26 | ||||
-rw-r--r-- | library/cpp/http/server/ut/ya.make | 4 | ||||
-rw-r--r-- | library/cpp/http/server/ya.make | 28 |
14 files changed, 683 insertions, 683 deletions
diff --git a/library/cpp/http/server/conn.cpp b/library/cpp/http/server/conn.cpp index 38a76c4c30..dd0860a315 100644 --- a/library/cpp/http/server/conn.cpp +++ b/library/cpp/http/server/conn.cpp @@ -1,31 +1,31 @@ -#include "conn.h" - -#include <util/network/socket.h> +#include "conn.h" + +#include <util/network/socket.h> #include <util/stream/buffered.h> - -class THttpServerConn::TImpl { -public: + +class THttpServerConn::TImpl { +public: inline TImpl(const TSocket& s, size_t outputBufferSize) - : S_(s) - , SI_(S_) - , SO_(S_) + : S_(s) + , SI_(S_) + , SO_(S_) , BO_(&SO_, outputBufferSize) - , HI_(&SI_) - , HO_(&BO_, &HI_) - { - } - + , HI_(&SI_) + , HO_(&BO_, &HI_) + { + } + inline ~TImpl() { - } - + } + inline THttpInput* Input() noexcept { - return &HI_; - } - + return &HI_; + } + inline THttpOutput* Output() noexcept { - return &HO_; - } - + return &HO_; + } + inline void Reset() { if (S_ != INVALID_SOCKET) { // send RST packet to client @@ -34,35 +34,35 @@ public: } } -private: - TSocket S_; - TSocketInput SI_; - TSocketOutput SO_; - TBufferedOutput BO_; - THttpInput HI_; - THttpOutput HO_; -}; - -THttpServerConn::THttpServerConn(const TSocket& s) +private: + TSocket S_; + TSocketInput SI_; + TSocketOutput SO_; + TBufferedOutput BO_; + THttpInput HI_; + THttpOutput HO_; +}; + +THttpServerConn::THttpServerConn(const TSocket& s) : THttpServerConn(s, s.MaximumTransferUnit()) -{ -} - +{ +} + THttpServerConn::THttpServerConn(const TSocket& s, size_t outputBufferSize) : Impl_(new TImpl(s, outputBufferSize)) { } THttpServerConn::~THttpServerConn() { -} - +} + THttpInput* THttpServerConn::Input() noexcept { - return Impl_->Input(); -} - + return Impl_->Input(); +} + THttpOutput* THttpServerConn::Output() noexcept { - return Impl_->Output(); -} + return Impl_->Output(); +} void THttpServerConn::Reset() { return Impl_->Reset(); diff --git a/library/cpp/http/server/conn.h b/library/cpp/http/server/conn.h index 3aa5329af4..93c2358c23 100644 --- a/library/cpp/http/server/conn.h +++ b/library/cpp/http/server/conn.h @@ -1,37 +1,37 @@ -#pragma once - +#pragma once + #include <library/cpp/http/io/stream.h> -#include <util/generic/ptr.h> - -class TSocket; - -/// Потоки ввода/вывода для получения запросов и отправки ответов HTTP-сервера. -class THttpServerConn { -public: - explicit THttpServerConn(const TSocket& s); - THttpServerConn(const TSocket& s, size_t outputBufferSize); +#include <util/generic/ptr.h> + +class TSocket; + +/// Потоки ввода/вывода для получения запросов и отправки ответов HTTP-сервера. +class THttpServerConn { +public: + explicit THttpServerConn(const TSocket& s); + THttpServerConn(const TSocket& s, size_t outputBufferSize); ~THttpServerConn(); - + THttpInput* Input() noexcept; THttpOutput* Output() noexcept; - + inline const THttpInput* Input() const noexcept { - return const_cast<THttpServerConn*>(this)->Input(); - } - + return const_cast<THttpServerConn*>(this)->Input(); + } + inline const THttpOutput* Output() const noexcept { - return const_cast<THttpServerConn*>(this)->Output(); - } - - /// Проверяет, можно ли установить режим, при котором соединение с сервером - /// не завершается после окончания транзакции. + return const_cast<THttpServerConn*>(this)->Output(); + } + + /// Проверяет, можно ли установить режим, при котором соединение с сервером + /// не завершается после окончания транзакции. inline bool CanBeKeepAlive() const noexcept { - return Output()->CanBeKeepAlive(); - } - + return Output()->CanBeKeepAlive(); + } + void Reset(); -private: - class TImpl; - THolder<TImpl> Impl_; -}; +private: + class TImpl; + THolder<TImpl> Impl_; +}; diff --git a/library/cpp/http/server/http.cpp b/library/cpp/http/server/http.cpp index 128583bdd7..581fc77399 100644 --- a/library/cpp/http/server/http.cpp +++ b/library/cpp/http/server/http.cpp @@ -1,12 +1,12 @@ #include "http.h" #include "http_ex.h" - + #include <library/cpp/threading/equeue/equeue.h> #include <util/generic/buffer.h> #include <util/generic/cast.h> -#include <util/generic/intrlist.h> -#include <util/generic/yexception.h> +#include <util/generic/intrlist.h> +#include <util/generic/yexception.h> #include <util/network/address.h> #include <util/network/socket.h> #include <util/network/poller.h> @@ -18,7 +18,7 @@ #include <util/system/pipe.h> #include <util/system/thread.h> #include <util/thread/factory.h> - + #include <cerrno> #include <cstring> #include <ctime> @@ -28,39 +28,39 @@ using namespace NAddr; -namespace { - class IPollAble { - public: +namespace { + class IPollAble { + public: inline IPollAble() noexcept { - } - - virtual ~IPollAble() { - } - + } + + virtual ~IPollAble() { + } + virtual void OnPollEvent(TInstant now) = 0; - }; + }; + + struct TShouldStop { + }; - struct TShouldStop { - }; - - struct TWakeupPollAble: public IPollAble { + struct TWakeupPollAble: public IPollAble { void OnPollEvent(TInstant) override { - throw TShouldStop(); - } - }; -} - -class TClientConnection: public IPollAble, public TIntrusiveListItem<TClientConnection> { + throw TShouldStop(); + } + }; +} + +class TClientConnection: public IPollAble, public TIntrusiveListItem<TClientConnection> { public: TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef); ~TClientConnection() override; - + void OnPollEvent(TInstant now) override; - + inline void Activate(TInstant now) noexcept; inline void DeActivate(); inline void Reject(); - + public: TSocket Socket_; NAddr::IRemoteAddrRef ListenerSockAddrRef_; @@ -69,28 +69,28 @@ public: TInstant LastUsed; TInstant AcceptMoment; size_t ReceivedRequests = 0; -}; - -class THttpServer::TImpl { +}; + +class THttpServer::TImpl { public: class TConnections { - public: + public: inline TConnections(TSocketPoller* poller, const THttpServerOptions& options) : Poller_(poller) , Options(options) { } - + inline ~TConnections() { } - + inline void Add(TClientConnection* c) noexcept { TGuard<TMutex> g(Mutex_); - + Conns_.PushBack(c); Poller_->WaitRead(c->Socket_, (void*)static_cast<const IPollAble*>(c)); } - + inline void Erase(TClientConnection* c, TInstant now) noexcept { TGuard<TMutex> g(Mutex_); EraseUnsafe(c); @@ -98,18 +98,18 @@ public: TryRemovingUnsafe(now - Options.ExpirationTimeout); } } - + inline void Clear() noexcept { TGuard<TMutex> g(Mutex_); - + Conns_.Clear(); } - + inline bool RemoveOld(TInstant border) noexcept { TGuard<TMutex> g(Mutex_); return TryRemovingUnsafe(border); } - + bool TryRemovingUnsafe(TInstant border) noexcept { if (Conns_.Empty()) { return false; @@ -122,7 +122,7 @@ public: delete c; return true; } - + void EraseUnsafe(TClientConnection* c) noexcept { Poller_->Unwait(c->Socket_); c->Unlink(); @@ -134,7 +134,7 @@ public: TSocketPoller* Poller_ = nullptr; const THttpServerOptions& Options; }; - + static void* ListenSocketFunction(void* param) { try { ((TImpl*)param)->ListenSocket(); @@ -144,10 +144,10 @@ public: return nullptr; } - + TAutoPtr<TClientRequest> CreateRequest(TAutoPtr<TClientConnection> c) { THolder<TClientRequest> obj(Cb_->CreateClient()); - + obj->Conn_.Reset(c.Release()); return obj; @@ -161,13 +161,13 @@ public: (new TClientConnection(s, this, listenerSockAddrRef))->Reject(); return; } - } - + } + auto connection = new TClientConnection(s, this, listenerSockAddrRef); connection->LastUsed = now; connection->DeActivate(); } - + void SaveErrorCode() { ErrorCode = WSAGetLastError(); } @@ -175,11 +175,11 @@ public: int GetErrorCode() const { return ErrorCode; } - + const char* GetError() const { return LastSystemErrorText(ErrorCode); } - + bool Start() { Poller.Reset(new TSocketPoller()); Connections.Reset(new TConnections(Poller.Get(), Options_)); @@ -202,14 +202,14 @@ public: } catch (const yexception&) { SaveErrorCode(); return false; - } - + } + // Wait until the thread has completely started and return the success indicator ListenStartEvent.Wait(); - + return ListenerRunningOK; } - + void Wait() { Cb_->OnWait(); TGuard<TMutex> g(StopMutex); @@ -227,46 +227,46 @@ public: ListenThread->Join(); ListenThread.Reset(nullptr); } - + while (ConnectionCount) { usleep(10000); Connections->Clear(); - } - + } + Connections.Destroy(); Poller.Destroy(); } - + void Shutdown() { ListenWakeupWriteFd.Write("", 1); // ignore result } - + void AddRequest(TAutoPtr<TClientRequest> req, bool fail) { struct TFailRequest: public THttpClientRequestEx { - inline TFailRequest(TAutoPtr<TClientRequest> parent) { - Conn_.Reset(parent->Conn_.Release()); - HttpConn_.Reset(parent->HttpConn_.Release()); - } - + inline TFailRequest(TAutoPtr<TClientRequest> parent) { + Conn_.Reset(parent->Conn_.Release()); + HttpConn_.Reset(parent->HttpConn_.Release()); + } + bool Reply(void*) override { if (!ProcessHeaders()) { return true; } - ProcessFailRequest(0); - return true; - } + ProcessFailRequest(0); + return true; + } }; - + if (!fail && Requests->Add(req.Get())) { Y_UNUSED(req.Release()); } else { req = new TFailRequest(req); - + if (FailRequests->Add(req.Get())) { Y_UNUSED(req.Release()); - } else { + } else { Cb_->OnFailRequest(-1); } } @@ -288,44 +288,44 @@ public: return *FailRequests; } - class TListenSocket: public IPollAble, public TIntrusiveListItem<TListenSocket> { - public: - inline TListenSocket(const TSocket& s, TImpl* parent) - : S_(s) - , Server_(parent) + class TListenSocket: public IPollAble, public TIntrusiveListItem<TListenSocket> { + public: + inline TListenSocket(const TSocket& s, TImpl* parent) + : S_(s) + , Server_(parent) , SockAddrRef_(GetSockAddr(S_)) - { - } - + { + } + ~TListenSocket() override { - } - + } + void OnPollEvent(TInstant) override { SOCKET s = ::accept(S_, nullptr, nullptr); - - if (s == INVALID_SOCKET) { - ythrow yexception() << "accept: " << LastSystemErrorText(); + + if (s == INVALID_SOCKET) { + ythrow yexception() << "accept: " << LastSystemErrorText(); } Server_->AddRequestFromSocket(s, TInstant::Now(), SockAddrRef_); - } + } SOCKET GetSocket() const noexcept { - return S_; - } - - private: - TSocket S_; + return S_; + } + + private: + TSocket S_; TImpl* Server_ = nullptr; NAddr::IRemoteAddrRef SockAddrRef_; }; - + void ListenSocket() { TThread::SetCurrentThreadName(Options_.ListenThreadName.c_str()); ErrorCode = 0; TIntrusiveListWithAutoDelete<TListenSocket, TDelete> Reqs; - + std::function<void(TSocket)> callback = [&](TSocket socket) { THolder<TListenSocket> ls(new TListenSocket(socket, this)); Poller->WaitRead(socket, static_cast<IPollAble*>(ls.Get())); @@ -335,7 +335,7 @@ public: if (!addressesBound) { SaveErrorCode(); ListenStartEvent.Signal(); - + return; } @@ -347,18 +347,18 @@ public: TVector<void*> events; events.resize(1); - + TInstant now = TInstant::Now(); - for (;;) { + for (;;) { try { const TInstant deadline = Options_.PollTimeout == TDuration::Zero() ? TInstant::Max() : now + Options_.PollTimeout; const size_t ret = Poller->WaitD(events.data(), events.size(), deadline); - + now = TInstant::Now(); for (size_t i = 0; i < ret; ++i) { ((IPollAble*)events[i])->OnPollEvent(now); } - + if (ret == 0 && Options_.ExpirationTimeout > TDuration::Zero()) { Connections->RemoveOld(now - Options_.ExpirationTimeout); } @@ -370,26 +370,26 @@ public: if (!Options_.MaxConnections && Options_.ExpirationTimeout == TDuration::Zero()) { if (ret >= events.size()) { events.resize(ret * 2); - } - } - } catch (const TShouldStop&) { - break; + } + } + } catch (const TShouldStop&) { + break; } catch (...) { Cb_->OnException(); - } - } + } + } while (!Reqs.Empty()) { THolder<TListenSocket> ls(Reqs.PopFront()); - + Poller->Unwait(ls->GetSocket()); - } - + } + Requests->Stop(); FailRequests->Stop(); Cb_->OnListenStop(); } - + void RestartRequestThreads(ui32 nTh, ui32 maxQS) { Requests->Stop(); Options_.nThreads = nTh; @@ -408,24 +408,24 @@ public: TImpl(THttpServer* parent, ICallBack* cb, const TOptions& options, IThreadFactory* factory) : TImpl( - parent, - cb, + parent, + cb, MakeThreadPool<TSimpleThreadPool>(factory, options.UseElasticQueues, cb, options.RequestsThreadName), MakeThreadPool<TThreadPool>(factory, options.UseElasticQueues, nullptr, options.FailRequestsThreadName), - options) { + options) { } ~TImpl() { try { Stop(); } catch (...) { - } + } } - + inline const TOptions& Options() const noexcept { return Options_; } - + inline void DecreaseConnections() noexcept { AtomicDecrement(ConnectionCount); } @@ -439,7 +439,7 @@ public: } inline bool MaxRequestsReached() const { - return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections); + return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections); } THolder<TThread> ListenThread; @@ -480,57 +480,57 @@ private: return pool; } -}; +}; THttpServer::THttpServer(ICallBack* cb, const TOptions& options, IThreadFactory* pool) : Impl_(new TImpl(this, cb, options, pool)) -{ -} - +{ +} + THttpServer::THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options) : Impl_(new TImpl(this, cb, mainWorkers, failWorkers, options)) { } -THttpServer::~THttpServer() { -} - +THttpServer::~THttpServer() { +} + i64 THttpServer::GetClientCount() const { return Impl_->GetClientCount(); } -bool THttpServer::Start() { - return Impl_->Start(); -} - -void THttpServer::Stop() { - Impl_->Stop(); -} - -void THttpServer::Shutdown() { - Impl_->Shutdown(); -} - -void THttpServer::Wait() { - Impl_->Wait(); -} - -int THttpServer::GetErrorCode() { - return Impl_->GetErrorCode(); -} - -const char* THttpServer::GetError() { - return Impl_->GetError(); -} - -void THttpServer::RestartRequestThreads(ui32 n, ui32 queue) { - Impl_->RestartRequestThreads(n, queue); -} - +bool THttpServer::Start() { + return Impl_->Start(); +} + +void THttpServer::Stop() { + Impl_->Stop(); +} + +void THttpServer::Shutdown() { + Impl_->Shutdown(); +} + +void THttpServer::Wait() { + Impl_->Wait(); +} + +int THttpServer::GetErrorCode() { + return Impl_->GetErrorCode(); +} + +const char* THttpServer::GetError() { + return Impl_->GetError(); +} + +void THttpServer::RestartRequestThreads(ui32 n, ui32 queue) { + Impl_->RestartRequestThreads(n, queue); +} + const THttpServer::TOptions& THttpServer::Options() const noexcept { - return Impl_->Options(); -} - + return Impl_->Options(); +} + size_t THttpServer::GetRequestQueueSize() const { return Impl_->GetRequestQueueSize(); } @@ -552,45 +552,45 @@ bool THttpServer::MaxRequestsReached() const { } TClientConnection::TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef) - : Socket_(s) + : Socket_(s) , ListenerSockAddrRef_(listenerSockAddrRef) - , HttpServ_(serv) -{ - SetNoDelay(Socket_, true); - + , HttpServ_(serv) +{ + SetNoDelay(Socket_, true); + const TDuration& clientTimeout = HttpServ_->Options().ClientTimeout; if (clientTimeout != TDuration::Zero()) { SetSocketTimeout(Socket_, (long)clientTimeout.Seconds(), clientTimeout.MilliSecondsOfSecond()); } - HttpServ_->IncreaseConnections(); -} - + HttpServ_->IncreaseConnections(); +} + TClientConnection::~TClientConnection() { - HttpServ_->DecreaseConnections(); -} - + HttpServ_->DecreaseConnections(); +} + void TClientConnection::OnPollEvent(TInstant now) { THolder<TClientConnection> this_(this); Activate(now); - - { - char tmp[1]; - - if (::recv(Socket_, tmp, 1, MSG_PEEK) < 1) { - /* - * We can received a FIN so our socket was moved to - * TCP_CLOSE_WAIT state. Check it before adding work - * for this socket. - */ - - return; - } - } - + + { + char tmp[1]; + + if (::recv(Socket_, tmp, 1, MSG_PEEK) < 1) { + /* + * We can received a FIN so our socket was moved to + * TCP_CLOSE_WAIT state. Check it before adding work + * for this socket. + */ + + return; + } + } + THolder<TClientRequest> obj(HttpServ_->CreateRequest(this_)); AcceptMoment = now; - + HttpServ_->AddRequest(obj, Reject_); } @@ -600,35 +600,35 @@ void TClientConnection::Activate(TInstant now) noexcept { ++ReceivedRequests; } -void TClientConnection::DeActivate() { +void TClientConnection::DeActivate() { HttpServ_->Connections->Add(this); -} - +} + void TClientConnection::Reject() { Reject_ = true; HttpServ_->Connections->Add(this); } -TClientRequest::TClientRequest() { -} - -TClientRequest::~TClientRequest() { -} - -bool TClientRequest::Reply(void* /*ThreadSpecificResource*/) { +TClientRequest::TClientRequest() { +} + +TClientRequest::~TClientRequest() { +} + +bool TClientRequest::Reply(void* /*ThreadSpecificResource*/) { if (strnicmp(RequestString.data(), "GET ", 4)) { - Output() << "HTTP/1.0 501 Not Implemented\r\n\r\n"; - } else { - Output() << "HTTP/1.0 200 OK\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "Hello World!\r\n"; - } - - return true; -} - + Output() << "HTTP/1.0 501 Not Implemented\r\n\r\n"; + } else { + Output() << "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "Hello World!\r\n"; + } + + return true; +} + bool TClientRequest::IsLocal() const { return HasLocalAddress(Socket()); } @@ -639,29 +639,29 @@ bool TClientRequest::CheckLoopback() { try { isLocal = IsLocal(); } catch (const yexception& e) { - Output() << "HTTP/1.0 500 Oops\r\n\r\n" - << e.what() << "\r\n"; - return false; + Output() << "HTTP/1.0 500 Oops\r\n\r\n" + << e.what() << "\r\n"; + return false; } if (!isLocal) { - Output() << "HTTP/1.0 403 Permission denied\r\n" - "Content-Type: text/html; charset=windows-1251\r\n" - "Connection: close\r\n" - "\r\n" - "<html><head><title>Permission denied</title></head>" - "<body><h1>Permission denied</h1>" - "<p>This request must be sent from the localhost.</p>" - "</body></html>\r\n"; - - return false; - } - - return true; -} - + Output() << "HTTP/1.0 403 Permission denied\r\n" + "Content-Type: text/html; charset=windows-1251\r\n" + "Connection: close\r\n" + "\r\n" + "<html><head><title>Permission denied</title></head>" + "<body><h1>Permission denied</h1>" + "<p>This request must be sent from the localhost.</p>" + "</body></html>\r\n"; + + return false; + } + + return true; +} + void TClientRequest::ReleaseConnection() { - if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) { + if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) { Output().Finish(); Conn_->DeActivate(); Y_UNUSED(Conn_.Release()); @@ -676,101 +676,101 @@ void TClientRequest::ResetConnection() { } } -void TClientRequest::Process(void* ThreadSpecificResource) { +void TClientRequest::Process(void* ThreadSpecificResource) { THolder<TClientRequest> this_(this); - + auto* serverImpl = Conn_->HttpServ_; - try { - if (!HttpConn_) { + try { + if (!HttpConn_) { const size_t outputBufferSize = HttpServ()->Options().OutputBufferSize; if (outputBufferSize) { HttpConn_.Reset(new THttpServerConn(Socket(), outputBufferSize)); } else { HttpConn_.Reset(new THttpServerConn(Socket())); } - + auto maxRequestsPerConnection = HttpServ()->Options().MaxRequestsPerConnection; HttpConn_->Output()->EnableKeepAlive(HttpServ()->Options().KeepAliveEnabled && (!maxRequestsPerConnection || Conn_->ReceivedRequests < maxRequestsPerConnection)); - HttpConn_->Output()->EnableCompression(HttpServ()->Options().CompressionEnabled); - } - + HttpConn_->Output()->EnableCompression(HttpServ()->Options().CompressionEnabled); + } + if (ParsedHeaders.empty()) { RequestString = Input().FirstLine(); - - const THttpHeaders& h = Input().Headers(); + + const THttpHeaders& h = Input().Headers(); ParsedHeaders.reserve(h.Count()); - for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) { + for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) { ParsedHeaders.emplace_back(it->Name(), it->Value()); - } - } - - if (Reply(ThreadSpecificResource)) { + } + } + + if (Reply(ThreadSpecificResource)) { ReleaseConnection(); - - /* - * *this will be destroyed... - */ - - return; - } - } catch (...) { + + /* + * *this will be destroyed... + */ + + return; + } + } catch (...) { serverImpl->Cb_->OnException(); - - throw; - } - + + throw; + } + Y_UNUSED(this_.Release()); -} - -void TClientRequest::ProcessFailRequest(int failstate) { +} + +void TClientRequest::ProcessFailRequest(int failstate) { Output() << "HTTP/1.1 503 Service Unavailable\r\n" "Content-Type: text/plain\r\n" "Content-Length: 21\r\n" "\r\n" "Service Unavailable\r\n"; - + TString url; - + if (!strnicmp(RequestString.data(), "GET ", 4)) { - // Trying to extract url... + // Trying to extract url... const char* str = RequestString.data(); - - // Skipping spaces before url... - size_t start = 3; + + // Skipping spaces before url... + size_t start = 3; while (str[start] == ' ') { - ++start; - } - - if (str[start]) { - // Traversing url... - size_t idx = start; - - while (str[idx] != ' ' && str[idx]) { - ++idx; - } - + ++start; + } + + if (str[start]) { + // Traversing url... + size_t idx = start; + + while (str[idx] != ' ' && str[idx]) { + ++idx; + } + url = RequestString.substr(start, idx - start); - } - } - - const THttpServer::ICallBack::TFailLogData d = { - failstate, - url, - }; - - // Handling failure... - Conn_->HttpServ_->Cb_->OnFailRequestEx(d); - Output().Flush(); -} - + } + } + + const THttpServer::ICallBack::TFailLogData d = { + failstate, + url, + }; + + // Handling failure... + Conn_->HttpServ_->Cb_->OnFailRequestEx(d); + Output().Flush(); +} + THttpServer* TClientRequest::HttpServ() const noexcept { - return Conn_->HttpServ_->Parent_; -} - + return Conn_->HttpServ_->Parent_; +} + const TSocket& TClientRequest::Socket() const noexcept { - return Conn_->Socket_; -} + return Conn_->Socket_; +} NAddr::IRemoteAddrRef TClientRequest::GetListenerSockAddrRef() const noexcept { return Conn_->ListenerSockAddrRef_; @@ -791,8 +791,8 @@ TRequestReplier::~TRequestReplier() { bool TRequestReplier::Reply(void* threadSpecificResource) { const TReplyParams params = { - threadSpecificResource, Input(), Output()}; - + threadSpecificResource, Input(), Output()}; + return DoReply(params); } @@ -833,7 +833,7 @@ bool TryToBindAddresses(const THttpServerOptions& options, const std::function<v return false; } - if (callbackOnBoundAddress != nullptr) { + if (callbackOnBoundAddress != nullptr) { (*callbackOnBoundAddress)(socket); } } diff --git a/library/cpp/http/server/http.h b/library/cpp/http/server/http.h index b292d38f27..1b72215706 100644 --- a/library/cpp/http/server/http.h +++ b/library/cpp/http/server/http.h @@ -1,92 +1,92 @@ #pragma once -#include "conn.h" -#include "options.h" - +#include "conn.h" +#include "options.h" + #include <util/thread/pool.h> #include <library/cpp/http/io/stream.h> -#include <util/memory/blob.h> +#include <util/memory/blob.h> #include <util/generic/ptr.h> #include <util/generic/vector.h> #include <util/system/atomic.h> - + class IThreadFactory; -class TClientRequest; -class TClientConnection; +class TClientRequest; +class TClientConnection; -class THttpServer { +class THttpServer { friend class TClientRequest; friend class TClientConnection; - + public: class ICallBack { - public: + public: struct TFailLogData { int failstate; TString url; }; - + virtual ~ICallBack() { } - + virtual void OnFailRequest(int /*failstate*/) { } - + virtual void OnFailRequestEx(const TFailLogData& d) { OnFailRequest(d.failstate); } - + virtual void OnException() { } - + virtual void OnMaxConn() { } - + virtual TClientRequest* CreateClient() = 0; - + virtual void OnListenStart() { } - + virtual void OnListenStop() { } - + virtual void OnWait() { } - - virtual void* CreateThreadSpecificResource() { + + virtual void* CreateThreadSpecificResource() { return nullptr; } - + virtual void DestroyThreadSpecificResource(void*) { } }; - + typedef THttpServerOptions TOptions; typedef TSimpleSharedPtr<IThreadPool> TMtpQueueRef; - + THttpServer(ICallBack* cb, const TOptions& options = TOptions(), IThreadFactory* pool = nullptr); THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options = TOptions()); virtual ~THttpServer(); - + bool Start(); - + // shutdown a.s.a.p. void Stop(); - + // graceful shutdown with serving all already open connections void Shutdown(); - + void Wait(); int GetErrorCode(); const char* GetError(); void RestartRequestThreads(ui32 nTh, ui32 maxQS); const TOptions& Options() const noexcept; i64 GetClientCount() const; - + class TImpl; size_t GetRequestQueueSize() const; size_t GetFailQueueSize() const; - + const IThreadPool& GetRequestQueue() const; const IThreadPool& GetFailQueue() const; @@ -102,32 +102,32 @@ private: /** * @deprecated Use TRequestReplier instead */ -class TClientRequest: public IObjectInQueue { +class TClientRequest: public IObjectInQueue { friend class THttpServer::TImpl; - + public: TClientRequest(); ~TClientRequest() override; - + inline THttpInput& Input() noexcept { return *HttpConn_->Input(); } - + inline THttpOutput& Output() noexcept { return *HttpConn_->Output(); } - + THttpServer* HttpServ() const noexcept; const TSocket& Socket() const noexcept; NAddr::IRemoteAddrRef GetListenerSockAddrRef() const noexcept; TInstant AcceptMoment() const noexcept; - + bool IsLocal() const; bool CheckLoopback(); void ProcessFailRequest(int failstate); - + void ReleaseConnection(); - + void ResetConnection(); private: @@ -138,17 +138,17 @@ private: */ virtual bool Reply(void* ThreadSpecificResource); void Process(void* ThreadSpecificResource) override; - + public: TVector<std::pair<TString, TString>> ParsedHeaders; TString RequestString; - + private: THolder<TClientConnection> Conn_; THolder<THttpServerConn> HttpConn_; -}; - -class TRequestReplier: public TClientRequest { +}; + +class TRequestReplier: public TClientRequest { public: TRequestReplier(); ~TRequestReplier() override; diff --git a/library/cpp/http/server/http_ex.cpp b/library/cpp/http/server/http_ex.cpp index e07db22bfc..2fa2ccfead 100644 --- a/library/cpp/http/server/http_ex.cpp +++ b/library/cpp/http/server/http_ex.cpp @@ -1,32 +1,32 @@ -#include "http_ex.h" - -#include <util/generic/buffer.h> -#include <util/generic/cast.h> +#include "http_ex.h" + +#include <util/generic/buffer.h> +#include <util/generic/cast.h> #include <util/stream/null.h> - + bool THttpClientRequestExtension::Parse(char* req, TBaseServerRequestData& rd) { rd.SetSocket(Socket()); - + if (!rd.Parse(req)) { - Output() << "HTTP/1.1 403 Forbidden\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 39\r\n" - "\r\n" - "The server cannot be used as a proxy.\r\n"; - - return false; - } - - return true; -} - + Output() << "HTTP/1.1 403 Forbidden\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 39\r\n" + "\r\n" + "The server cannot be used as a proxy.\r\n"; + + return false; + } + + return true; +} + bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData) { - for (const auto& header : ParsedHeaders) { + for (const auto& header : ParsedHeaders) { rd.AddHeader(header.first, header.second); - } - + } + char* s = RequestString.begin(); - + enum EMethod { NotImplemented, Get, @@ -39,7 +39,7 @@ bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBl enum EMethod foundMethod; char* urlStart; - if (strnicmp(s, "GET ", 4) == 0) { + if (strnicmp(s, "GET ", 4) == 0) { foundMethod = Get; urlStart = s + 4; } else if (strnicmp(s, "POST ", 5) == 0) { @@ -59,49 +59,49 @@ bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBl } switch (foundMethod) { - case Get: - case Delete: - if (!Parse(urlStart, rd)) { - return false; - } - break; - - case Post: - case Put: + case Get: + case Delete: + if (!Parse(urlStart, rd)) { + return false; + } + break; + + case Post: + case Put: case Patch: - try { - ui64 contentLength = 0; - if (Input().HasExpect100Continue()) { - Output().SendContinue(); - } - - if (!Input().ContentEncoded() && Input().GetContentLength(contentLength)) { + try { + ui64 contentLength = 0; + if (Input().HasExpect100Continue()) { + Output().SendContinue(); + } + + if (!Input().ContentEncoded() && Input().GetContentLength(contentLength)) { if (contentLength > HttpServ()->Options().MaxInputContentLength) { Output() << "HTTP/1.1 413 Payload Too Large\r\nContent-Length:0\r\n\r\n"; Output().Finish(); return false; } - TBuffer buf(SafeIntegerCast<size_t>(contentLength)); - buf.Resize(Input().Load(buf.Data(), (size_t)contentLength)); - postData = TBlob::FromBuffer(buf); - } else { - postData = TBlob::FromStream(Input()); - } - } catch (...) { - Output() << "HTTP/1.1 400 Bad request\r\n\r\n"; - return false; + TBuffer buf(SafeIntegerCast<size_t>(contentLength)); + buf.Resize(Input().Load(buf.Data(), (size_t)contentLength)); + postData = TBlob::FromBuffer(buf); + } else { + postData = TBlob::FromStream(Input()); + } + } catch (...) { + Output() << "HTTP/1.1 400 Bad request\r\n\r\n"; + return false; } - if (!Parse(urlStart, rd)) { - return false; - } - break; - - case NotImplemented: - Output() << "HTTP/1.1 501 Not Implemented\r\n\r\n"; - return false; - } - - return true; -} + if (!Parse(urlStart, rd)) { + return false; + } + break; + + case NotImplemented: + Output() << "HTTP/1.1 501 Not Implemented\r\n\r\n"; + return false; + } + + return true; +} diff --git a/library/cpp/http/server/http_ex.h b/library/cpp/http/server/http_ex.h index 1ef43ea4fd..39cfbbe66f 100644 --- a/library/cpp/http/server/http_ex.h +++ b/library/cpp/http/server/http_ex.h @@ -1,28 +1,28 @@ -#pragma once - -#include "http.h" - +#pragma once + +#include "http.h" + #include <library/cpp/http/misc/httpreqdata.h> - -class THttpClientRequestExtension: public TClientRequest { + +class THttpClientRequestExtension: public TClientRequest { public: bool Parse(char* req, TBaseServerRequestData& rd); bool ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData); }; - + template <class TRequestData> -class THttpClientRequestExtImpl: public THttpClientRequestExtension { -protected: +class THttpClientRequestExtImpl: public THttpClientRequestExtension { +protected: bool Parse(char* req) { return THttpClientRequestExtension::Parse(req, RD); } bool ProcessHeaders() { return THttpClientRequestExtension::ProcessHeaders(RD, Buf); } - + protected: TRequestData RD; - TBlob Buf; -}; + TBlob Buf; +}; using THttpClientRequestEx = THttpClientRequestExtImpl<TServerRequestData>; diff --git a/library/cpp/http/server/http_ut.cpp b/library/cpp/http/server/http_ut.cpp index cc62bb988e..ab24207eac 100644 --- a/library/cpp/http/server/http_ut.cpp +++ b/library/cpp/http/server/http_ut.cpp @@ -1,58 +1,58 @@ -#include "http.h" -#include "http_ex.h" - +#include "http.h" +#include "http_ex.h" + #include <library/cpp/testing/unittest/registar.h> #include <library/cpp/testing/unittest/tests_data.h> - + #include <util/generic/cast.h> #include <util/stream/output.h> #include <util/stream/zlib.h> #include <util/system/datetime.h> #include <util/system/sem.h> - + Y_UNIT_TEST_SUITE(THttpServerTest) { - class TEchoServer: public THttpServer::ICallBack { + class TEchoServer: public THttpServer::ICallBack { class TRequest: public THttpClientRequestEx { - public: - inline TRequest(TEchoServer* parent) - : Parent_(parent) - { - } - + public: + inline TRequest(TEchoServer* parent) + : Parent_(parent) + { + } + bool Reply(void* /*tsr*/) override { - if (!ProcessHeaders()) { + if (!ProcessHeaders()) { return true; - } - - Output() << "HTTP/1.1 200 Ok\r\n\r\n"; + } + + Output() << "HTTP/1.1 200 Ok\r\n\r\n"; if (Buf.Size()) { Output().Write(Buf.AsCharPtr(), Buf.Size()); - } else { - Output() << Parent_->Res_; - } - Output().Finish(); - - return true; - } - - private: + } else { + Output() << Parent_->Res_; + } + Output().Finish(); + + return true; + } + + private: TEchoServer* Parent_ = nullptr; - }; - - public: + }; + + public: inline TEchoServer(const TString& res) - : Res_(res) - { - } - + : Res_(res) + { + } + TClientRequest* CreateClient() override { - return new TRequest(this); - } - - private: + return new TRequest(this); + } + + private: TString Res_; - }; - + }; + class TSleepingServer: public THttpServer::ICallBack { class TReplier: public TRequestReplier { public: @@ -269,7 +269,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { TStringStream ss; ss << (KeepAliveConnection ? "keep-alive " : "") << Type; if (ContentEncoding.size()) { - ss << " with encoding=" << ContentEncoding; + ss << " with encoding=" << ContentEncoding; } return ss.Str(); } else { @@ -292,7 +292,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { class TFailingMtpQueue: public TSimpleThreadPool { private: bool FailOnAdd_ = false; - + public: void SetFailOnAdd(bool fail = true) { FailOnAdd_ = fail; @@ -313,47 +313,47 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { TString TestData(size_t size = 5 * 4096) { TString res; - + for (size_t i = 0; i < size; ++i) { - res += (char)i; - } + res += (char)i; + } return res; } - + Y_UNIT_TEST(TestEchoServer) { TString res = TestData(); TPortManager pm; const ui16 port = pm.GetPort(); const bool trueFalse[] = {true, false}; - - TEchoServer serverImpl(res); - THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true)); - + + TEchoServer serverImpl(res); + THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true)); + for (int i = 0; i < 2; ++i) { UNIT_ASSERT(server.Start()); - + TTestRequest r(port); r.Content = res; - - for (bool keepAlive : trueFalse) { + + for (bool keepAlive : trueFalse) { r.KeepAliveConnection = keepAlive; - + // THttpOutput use chunked stream, else use Content-Length - for (bool useHttpOutput : trueFalse) { + for (bool useHttpOutput : trueFalse) { r.UseHttpOutput = useHttpOutput; - - for (bool enableResponseEncoding : trueFalse) { + + for (bool enableResponseEncoding : trueFalse) { r.EnableResponseEncoding = enableResponseEncoding; - + const TString reqTypes[] = {"GET", "POST"}; for (const TString& reqType : reqTypes) { r.Type = reqType; - + const TString encoders[] = {"", "deflate"}; for (const TString& encoder : encoders) { r.ContentEncoding = encoder; - - for (bool expect100Continue : trueFalse) { + + for (bool expect100Continue : trueFalse) { r.Expect100Continue = expect100Continue; TString resp = r.Execute(); UNIT_ASSERT_C(resp == res, "diff echo response for request:\n" + r.GetDescription()); @@ -365,12 +365,12 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { } server.Stop(); - } - } + } + } Y_UNIT_TEST(TestReusePortEnabled) { if (!IsReusePortAvailable()) { - return; // skip test + return; // skip test } TString res = TestData(); TPortManager pm; @@ -383,7 +383,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { } for (ui32 testRun = 0; testRun < 3; testRun++) { - for (auto& server : servers) { + for (auto& server : servers) { // start servers one at a time and check at least one of them is replying UNIT_ASSERT(server->Start()); @@ -391,7 +391,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { UNIT_ASSERT_C(r.Execute() == res, "diff echo response for request:\n" + r.GetDescription()); } - for (auto& server : servers) { + for (auto& server : servers) { // ping servers and stop them one at a time // at the last iteration only one server is still working and then gets stopped as well @@ -471,7 +471,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { return true; } }; - + public: TClientRequest* CreateClient() override { return new TRequest(); @@ -684,7 +684,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { server.Stop(); }; -#if 0 +#if 0 Y_UNIT_TEST(TestSocketsLeak) { const bool trueFalse[] = {true, false}; TPortManager portManager; @@ -709,7 +709,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { server.BusyThread(); for (size_t i = 0; i < 3; ++i) { - auto func = [&server, port, keepAlive]() { + auto func = [&server, port, keepAlive]() { server.BusyThread(); THolder<TTestRequest> r = MakeHolder<TTestRequest>(port); r->KeepAliveConnection = keepAlive; @@ -722,7 +722,7 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { Sleep(TDuration::MilliSeconds(100)); server.BusyThread(); // we wait while connections are established by the // system and accepted by the server - server.Free(3); // we release all connections processing + server.Free(3); // we release all connections processing for (auto&& thread : threads) { thread->Join(); @@ -735,5 +735,5 @@ Y_UNIT_TEST_SUITE(THttpServerTest) { UNIT_ASSERT_EQUAL_C(server.RepliesCount(), 1, "only one request should have been processed, got " + ToString(server.RepliesCount())); } } -#endif -} +#endif +} diff --git a/library/cpp/http/server/options.cpp b/library/cpp/http/server/options.cpp index 05c954384a..391ac68a11 100644 --- a/library/cpp/http/server/options.cpp +++ b/library/cpp/http/server/options.cpp @@ -1,12 +1,12 @@ -#include "options.h" - +#include "options.h" + #include <util/string/cast.h> -#include <util/digest/numeric.h> -#include <util/network/ip.h> -#include <util/network/socket.h> -#include <util/generic/hash_set.h> -#include <util/generic/yexception.h> - +#include <util/digest/numeric.h> +#include <util/network/ip.h> +#include <util/network/socket.h> +#include <util/generic/hash_set.h> +#include <util/generic/yexception.h> + using TAddr = THttpServerOptions::TAddr; static inline TString AddrToString(const TAddr& addr) { @@ -16,28 +16,28 @@ static inline TString AddrToString(const TAddr& addr) { static inline TNetworkAddress ToNetworkAddr(const TString& address, ui16 port) { if (address.empty() || address == TStringBuf("*")) { return TNetworkAddress(port); - } - + } + return TNetworkAddress(address, port); -} - -void THttpServerOptions::BindAddresses(TBindAddresses& ret) const { +} + +void THttpServerOptions::BindAddresses(TBindAddresses& ret) const { THashSet<TString> check; - + for (auto addr : BindSockaddr) { if (!addr.Port) { addr.Port = Port; - } - + } + const TString straddr = AddrToString(addr); if (check.find(straddr) == check.end()) { check.insert(straddr); ret.push_back(ToNetworkAddr(addr.Addr, addr.Port)); - } - } - - if (ret.empty()) { + } + } + + if (ret.empty()) { ret.push_back(Host ? TNetworkAddress(Host, Port) : TNetworkAddress(Port)); - } -} + } +} diff --git a/library/cpp/http/server/options.h b/library/cpp/http/server/options.h index 38eda0e5e7..28ce8be0e1 100644 --- a/library/cpp/http/server/options.h +++ b/library/cpp/http/server/options.h @@ -1,49 +1,49 @@ #pragma once - -#include <util/network/ip.h> -#include <util/network/init.h> + +#include <util/network/ip.h> +#include <util/network/init.h> #include <util/network/address.h> #include <util/generic/size_literals.h> #include <util/generic/string.h> -#include <util/generic/vector.h> +#include <util/generic/vector.h> #include <util/datetime/base.h> - -class THttpServerOptions { -public: + +class THttpServerOptions { +public: inline THttpServerOptions(ui16 port = 17000) noexcept : Port(port) - { - } - + { + } + using TBindAddresses = TVector<TNetworkAddress>; - void BindAddresses(TBindAddresses& ret) const; - + void BindAddresses(TBindAddresses& ret) const; + inline THttpServerOptions& AddBindAddress(const TString& address, ui16 port) { const TAddr addr = { - address, - port, - }; - + address, + port, + }; + BindSockaddr.push_back(addr); return *this; } inline THttpServerOptions& AddBindAddress(const TString& address) { return AddBindAddress(address, 0); - } - + } + inline THttpServerOptions& EnableKeepAlive(bool enable) noexcept { - KeepAliveEnabled = enable; - - return *this; - } - + KeepAliveEnabled = enable; + + return *this; + } + inline THttpServerOptions& EnableCompression(bool enable) noexcept { - CompressionEnabled = enable; - - return *this; - } - + CompressionEnabled = enable; + + return *this; + } + inline THttpServerOptions& EnableRejectExcessConnections(bool enable) noexcept { RejectExcessConnections = enable; @@ -63,11 +63,11 @@ public: } inline THttpServerOptions& SetThreads(ui32 threads) noexcept { - nThreads = threads; - - return *this; - } - + nThreads = threads; + + return *this; + } + /// Default interface name to bind the server. Used when none of BindAddress are provided. inline THttpServerOptions& SetHost(const TString& host) noexcept { Host = host; @@ -77,35 +77,35 @@ public: /// Default port to bind the server. Used when none of BindAddress are provided. inline THttpServerOptions& SetPort(ui16 port) noexcept { - Port = port; - - return *this; - } - + Port = port; + + return *this; + } + inline THttpServerOptions& SetMaxConnections(ui32 mc = 0) noexcept { - MaxConnections = mc; - - return *this; - } - + MaxConnections = mc; + + return *this; + } + inline THttpServerOptions& SetMaxQueueSize(ui32 mqs = 0) noexcept { - MaxQueueSize = mqs; - - return *this; - } + MaxQueueSize = mqs; + + return *this; + } inline THttpServerOptions& SetClientTimeout(const TDuration& timeout) noexcept { - ClientTimeout = timeout; - - return *this; - } + ClientTimeout = timeout; + return *this; + } + inline THttpServerOptions& SetListenBacklog(int val) noexcept { - ListenBacklog = val; - - return *this; - } - + ListenBacklog = val; + + return *this; + } + inline THttpServerOptions& SetOutputBufferSize(size_t val) noexcept { OutputBufferSize = val; @@ -149,19 +149,19 @@ public: bool KeepAliveEnabled = true; bool CompressionEnabled = false; bool RejectExcessConnections = false; - bool ReusePort = false; // set SO_REUSEPORT socket option + bool ReusePort = false; // set SO_REUSEPORT socket option bool ReuseAddress = true; // set SO_REUSEADDR socket option - TAddrs BindSockaddr; - ui16 Port = 17000; // The port on which to run the web server - TString Host; // DNS entry - const char* ServerName = "YWS/1.0"; // The Web server name to return in HTTP headers - ui32 nThreads = 0; // Thread count for requests processing - ui32 MaxQueueSize = 0; // Max allowed request count in queue + TAddrs BindSockaddr; + ui16 Port = 17000; // The port on which to run the web server + TString Host; // DNS entry + const char* ServerName = "YWS/1.0"; // The Web server name to return in HTTP headers + ui32 nThreads = 0; // Thread count for requests processing + ui32 MaxQueueSize = 0; // Max allowed request count in queue ui32 nFThreads = 1; ui32 MaxFQueueSize = 0; ui32 MaxConnections = 100; int ListenBacklog = SOMAXCONN; - TDuration ClientTimeout; + TDuration ClientTimeout; size_t OutputBufferSize = 0; ui64 MaxInputContentLength = sizeof(size_t) <= 4 ? 2_GB : 64_GB; size_t MaxRequestsPerConnection = 0; // If keep-alive is enabled, request limit before connection is closed @@ -173,4 +173,4 @@ public: TString ListenThreadName = "HttpListen"; TString RequestsThreadName = "HttpServer"; TString FailRequestsThreadName = "HttpServer"; -}; +}; diff --git a/library/cpp/http/server/response.cpp b/library/cpp/http/server/response.cpp index 52d64c91ce..3c7a3e6a93 100644 --- a/library/cpp/http/server/response.cpp +++ b/library/cpp/http/server/response.cpp @@ -1,7 +1,7 @@ #include "response.h" - + #include <util/stream/output.h> -#include <util/stream/mem.h> +#include <util/stream/mem.h> #include <util/string/cast.h> THttpResponse& THttpResponse::AddMultipleHeaders(const THttpHeaders& headers) { @@ -11,16 +11,16 @@ THttpResponse& THttpResponse::AddMultipleHeaders(const THttpHeaders& headers) { return *this; } -THttpResponse& THttpResponse::SetContentType(const TStringBuf& contentType) { +THttpResponse& THttpResponse::SetContentType(const TStringBuf& contentType) { Headers.AddOrReplaceHeader(THttpInputHeader("Content-Type", ToString(contentType))); - - return *this; + + return *this; } void THttpResponse::OutTo(IOutputStream& os) const { TVector<IOutputStream::TPart> parts; const size_t FIRST_LINE_PARTS = 3; - const size_t HEADERS_PARTS = Headers.Count() * 4; + const size_t HEADERS_PARTS = Headers.Count() * 4; const size_t CONTENT_PARTS = 5; parts.reserve(FIRST_LINE_PARTS + HEADERS_PARTS + CONTENT_PARTS); @@ -30,20 +30,20 @@ void THttpResponse::OutTo(IOutputStream& os) const { parts.push_back(IOutputStream::TPart::CrLf()); // headers - for (THttpHeaders::TConstIterator i = Headers.Begin(); i != Headers.End(); ++i) { + for (THttpHeaders::TConstIterator i = Headers.Begin(); i != Headers.End(); ++i) { parts.push_back(IOutputStream::TPart(i->Name())); parts.push_back(IOutputStream::TPart(TStringBuf(": "))); parts.push_back(IOutputStream::TPart(i->Value())); parts.push_back(IOutputStream::TPart::CrLf()); } - char buf[50]; - + char buf[50]; + if (!Content.empty()) { - TMemoryOutput mo(buf, sizeof(buf)); + TMemoryOutput mo(buf, sizeof(buf)); mo << Content.size(); - + parts.push_back(IOutputStream::TPart(TStringBuf("Content-Length: "))); parts.push_back(IOutputStream::TPart(buf, mo.Buf() - buf)); parts.push_back(IOutputStream::TPart::CrLf()); @@ -51,15 +51,15 @@ void THttpResponse::OutTo(IOutputStream& os) const { // content parts.push_back(IOutputStream::TPart::CrLf()); - + if (!Content.empty()) { parts.push_back(IOutputStream::TPart(Content)); } os.Write(parts.data(), parts.size()); -} - -template <> +} + +template <> void Out<THttpResponse>(IOutputStream& os, const THttpResponse& resp) { - resp.OutTo(os); + resp.OutTo(os); } diff --git a/library/cpp/http/server/response.h b/library/cpp/http/server/response.h index a75cb85605..7880babac5 100644 --- a/library/cpp/http/server/response.h +++ b/library/cpp/http/server/response.h @@ -1,8 +1,8 @@ #pragma once - + #include <library/cpp/http/misc/httpcodes.h> #include <library/cpp/http/io/stream.h> - + #include <util/generic/strbuf.h> #include <util/string/cast.h> @@ -12,23 +12,23 @@ class IOutputStream; class THttpResponse { public: THttpResponse() noexcept - : Code(HTTP_OK) - { - } - + : Code(HTTP_OK) + { + } + explicit THttpResponse(HttpCodes code) noexcept : Code(code) { } - template <typename ValueType> + template <typename ValueType> THttpResponse& AddHeader(const TString& name, const ValueType& value) { return AddHeader(THttpInputHeader(name, ToString(value))); } THttpResponse& AddHeader(const THttpInputHeader& header) { Headers.AddHeader(header); - + return *this; } @@ -38,8 +38,8 @@ public: return Headers; } - THttpResponse& SetContentType(const TStringBuf& contentType); - + THttpResponse& SetContentType(const TStringBuf& contentType); + /** * @note If @arg content isn't empty its size is automatically added as a * "Content-Length" header during output to IOutputStream. @@ -47,7 +47,7 @@ public: */ THttpResponse& SetContent(const TString& content) { Content = content; - + return *this; } @@ -61,8 +61,8 @@ public: * @see IOutputStream& operator << (IOutputStream&, const THttpResponse&) */ THttpResponse& SetContent(const TString& content, const TStringBuf& contentType) { - return SetContent(content).SetContentType(contentType); - } + return SetContent(content).SetContentType(contentType); + } HttpCodes HttpCode() const { return Code; diff --git a/library/cpp/http/server/response_ut.cpp b/library/cpp/http/server/response_ut.cpp index 73e2112ad3..ecd41015d9 100644 --- a/library/cpp/http/server/response_ut.cpp +++ b/library/cpp/http/server/response_ut.cpp @@ -2,11 +2,11 @@ #include <library/cpp/testing/unittest/registar.h> -#include <util/string/cast.h> - +#include <util/string/cast.h> + Y_UNIT_TEST_SUITE(TestHttpResponse) { Y_UNIT_TEST(TestCodeOnly) { - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse()), "HTTP/1.1 200 Ok\r\n\r\n"); + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse()), "HTTP/1.1 200 Ok\r\n\r\n"); UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse(HTTP_NOT_FOUND)), "HTTP/1.1 404 Not found\r\n\r\n"); } @@ -70,7 +70,7 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { "Content-Length: 10\r\n" "\r\n" "0123456789"; - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("0123456789")), + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("0123456789")), EXPECTED); } @@ -80,8 +80,8 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { "Content-Length: 28\r\n" "\r\n" "<xml><tag value=\"1\" /></xml>"; - THttpResponse resp; - resp.SetContent("<xml><tag value=\"1\" /></xml>").SetContentType("text/xml"); + THttpResponse resp; + resp.SetContent("<xml><tag value=\"1\" /></xml>").SetContentType("text/xml"); UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), EXPECTED); } @@ -90,8 +90,8 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne")) .AddHeader("X-Header-2", "ValueTwo") .AddHeader(THttpInputHeader("X-Header-3", "ValueThree")) - .SetContent("Some stuff") - .SetContentType("text/plain"); + .SetContent("Some stuff") + .SetContentType("text/plain"); THttpResponse copy = resp; UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp)); @@ -102,19 +102,19 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne")); resp.AddHeader(THttpInputHeader("X-Header-2", "ValueTwo")); resp.AddHeader(THttpInputHeader("X-Header-3", "ValueThree")); - resp.SetContent("Some stuff").SetContentType("text/plain"); + resp.SetContent("Some stuff").SetContentType("text/plain"); - THttpResponse copy; + THttpResponse copy; copy = resp; UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp)); } Y_UNIT_TEST(TestEmptyContent) { - UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("")), "HTTP/1.1 200 Ok\r\n\r\n"); + UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("")), "HTTP/1.1 200 Ok\r\n\r\n"); } Y_UNIT_TEST(TestReturnReference) { - THttpResponse resp; + THttpResponse resp; UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader("Header1", 1)); UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader(THttpInputHeader("Header2", "2"))); @@ -124,7 +124,7 @@ Y_UNIT_TEST_SUITE(TestHttpResponse) { UNIT_ASSERT_EQUAL(&resp, &resp.AddMultipleHeaders(headers)); UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some stuff")); - UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some other stuff").SetContentType("text/plain")); + UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some other stuff").SetContentType("text/plain")); } Y_UNIT_TEST(TestSetContentType) { diff --git a/library/cpp/http/server/ut/ya.make b/library/cpp/http/server/ut/ya.make index bcb4d4c0b8..17c20a8138 100644 --- a/library/cpp/http/server/ut/ya.make +++ b/library/cpp/http/server/ut/ya.make @@ -2,8 +2,8 @@ UNITTEST_FOR(library/cpp/http/server) OWNER(pg) -SIZE(MEDIUM) - +SIZE(MEDIUM) + SRCS( http_ut.cpp response_ut.cpp diff --git a/library/cpp/http/server/ya.make b/library/cpp/http/server/ya.make index bae6f33306..7b6bd59024 100644 --- a/library/cpp/http/server/ya.make +++ b/library/cpp/http/server/ya.make @@ -1,27 +1,27 @@ -LIBRARY() - -OWNER( - pg +LIBRARY() + +OWNER( + pg mvel kulikov g:base g:middle -) - -SRCS( - conn.cpp - http.cpp - http_ex.cpp - options.cpp +) + +SRCS( + conn.cpp + http.cpp + http_ex.cpp + options.cpp response.cpp -) - +) + PEERDIR( library/cpp/http/misc library/cpp/http/io library/cpp/threading/equeue ) -END() +END() RECURSE_FOR_TESTS(ut) |