123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897 |
- #include "http.h"
- #include "http_ex.h"
- #include <library/cpp/threading/equeue/equeue.h>
- #include <util/generic/buffer.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>
- #include <library/cpp/deprecated/atomic/atomic.h>
- #include <util/system/compat.h> // stricmp, strnicmp, strlwr, strupr, stpcpy
- #include <util/system/defaults.h>
- #include <util/system/event.h>
- #include <util/system/mutex.h>
- #include <util/system/pipe.h>
- #include <util/system/thread.h>
- #include <util/thread/factory.h>
- #include <cerrno>
- #include <cstring>
- using namespace NAddr;
- namespace {
- class IPollAble {
- public:
- inline IPollAble() noexcept {
- }
- virtual ~IPollAble() {
- }
- virtual void OnPollEvent(TInstant now) = 0;
- };
- struct TShouldStop {
- };
- struct TWakeupPollAble: public IPollAble {
- void OnPollEvent(TInstant) override {
- 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();
- void ScheduleDelete();
- public:
- TSocket Socket_;
- NAddr::IRemoteAddrRef ListenerSockAddrRef_;
- THttpServer::TImpl* HttpServ_ = nullptr;
- bool Reject_ = false;
- TInstant LastUsed;
- TInstant AcceptMoment;
- size_t ReceivedRequests = 0;
- struct TCleanupState {
- ui64 ThreadMask = 0;
- bool Closed = false;
- } CleanupState_;
- };
- class THttpServer::TImpl {
- public:
- class TConnections {
- 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);
- if (Options.OneShotPoll) {
- Poller_->WaitReadOneShot(c->Socket_, (void*)static_cast<const IPollAble*>(c));
- } else {
- Poller_->WaitRead(c->Socket_, (void*)static_cast<const IPollAble*>(c));
- }
- }
- void Cleanup(size_t threadNum) {
- if (Options.nListenerThreads < 2) {
- return;
- }
- TIntrusiveListWithAutoDelete<TClientConnection, TDelete> toDelete;
- {
- TGuard<TMutex> g(Mutex_);
- PendingDelete_.ForEach([&toDelete, threadNum](TClientConnection * conn) {
- if (!(conn->CleanupState_.ThreadMask &= ~((ui64)1 << threadNum))) {
- toDelete.PushBack(conn);
- }
- });
- }
- }
- inline void Erase(TClientConnection* c, TInstant now) noexcept {
- TGuard<TMutex> g(Mutex_);
- EraseUnsafe(c, /*removeFromPoller*/!Options.OneShotPoll);
- if (Options.ExpirationTimeout > TDuration::Zero()) {
- 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;
- }
- TClientConnection* c = &*(Conns_.Begin());
- if (c->LastUsed > border) {
- return false;
- }
- EraseUnsafe(c);
- if (Options.nListenerThreads > 1) {
- c->ScheduleDelete();
- PendingDelete_.PushBack(c);
- } else {
- delete c;
- }
- return true;
- }
- void EraseUnsafe(TClientConnection* c, bool removeFromPoller = true) noexcept {
- if (removeFromPoller) {
- Poller_->Unwait(c->Socket_);
- }
- c->Unlink();
- }
- public:
- TMutex Mutex_;
- TIntrusiveListWithAutoDelete<TClientConnection, TDelete> Conns_;
- TIntrusiveListWithAutoDelete<TClientConnection, TDelete> PendingDelete_;
- TSocketPoller* Poller_ = nullptr;
- const THttpServerOptions& Options;
- };
- TAutoPtr<TClientRequest> CreateRequest(TAutoPtr<TClientConnection> c) {
- THolder<TClientRequest> obj(Cb_->CreateClient());
- obj->Conn_.Reset(c.Release());
- return obj;
- }
- void AddRequestFromSocket(const TSocket& s, TInstant now, NAddr::IRemoteAddrRef listenerSockAddrRef) {
- if (MaxRequestsReached()) {
- Cb_->OnMaxConn();
- bool wasRemoved = Connections->RemoveOld(TInstant::Max());
- if (!wasRemoved && Options_.RejectExcessConnections) {
- (new TClientConnection(s, this, listenerSockAddrRef))->Reject();
- return;
- }
- }
- auto connection = new TClientConnection(s, this, listenerSockAddrRef);
- connection->LastUsed = now;
- connection->DeActivate();
- }
- void SaveErrorCode() {
- ErrorCode = WSAGetLastError();
- }
- 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_));
- // throws on error
- TPipeHandle::Pipe(ListenWakeupReadFd, ListenWakeupWriteFd);
- SetNonBlock(ListenWakeupWriteFd, true);
- SetNonBlock(ListenWakeupReadFd, true);
- Poller->WaitRead(ListenWakeupReadFd, &WakeupPollAble);
- ErrorCode = 0;
- std::function<void(TSocket)> callback = [&](TSocket socket) {
- THolder<TListenSocket> ls(new TListenSocket(socket, this));
- if (Options_.OneShotPoll) {
- Poller->WaitReadOneShot(socket, static_cast<IPollAble*>(ls.Get()));
- } else {
- Poller->WaitRead(socket, static_cast<IPollAble*>(ls.Get()));
- }
- Reqs.PushBack(ls.Release());
- };
- bool addressesBound = TryToBindAddresses(Options_, &callback);
- if (!addressesBound) {
- SaveErrorCode();
- return false;
- }
- Requests->Start(Options_.nThreads, Options_.MaxQueueSize);
- FailRequests->Start(Options_.nFThreads, Options_.MaxFQueueSize);
- Cb_->OnListenStart();
- try {
- RunningListeners_.store(Options_.nListenerThreads);
- for (size_t i = 0; i < Options_.nListenerThreads; ++i) {
- ListenThreads.push_back(MakeHolder<TThread>([this, threadNum = i]() {
- ListenSocket(threadNum);
- }));
- ListenThreads.back()->Start();
- }
- } catch (const yexception&) {
- SaveErrorCode();
- return false;
- }
- return true;
- }
- void JoinListenerThreads() {
- while (!ListenThreads.empty()) {
- ListenThreads.back()->Join();
- ListenThreads.pop_back();
- }
- }
- void Wait() {
- Cb_->OnWait();
- TGuard<TMutex> g(StopMutex);
- JoinListenerThreads();
- }
- void Stop() {
- Shutdown();
- TGuard<TMutex> g(StopMutex);
- JoinListenerThreads();
- while (AtomicGet(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());
- }
- bool Reply(void*) override {
- if (!ProcessHeaders()) {
- 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 {
- Cb_->OnFailRequest(-1);
- }
- }
- }
- size_t GetRequestQueueSize() const {
- return Requests->Size();
- }
- size_t GetFailQueueSize() const {
- return FailRequests->Size();
- }
- const IThreadPool& GetRequestQueue() const {
- return *Requests;
- }
- const IThreadPool& GetFailQueue() const {
- return *FailRequests;
- }
- 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 (Server_->Options_.OneShotPoll) {
- Server_->Poller->WaitReadOneShot(S_, this);
- }
- if (s == INVALID_SOCKET) {
- ythrow yexception() << "accept: " << LastSystemErrorText();
- }
- Server_->AddRequestFromSocket(s, TInstant::Now(), SockAddrRef_);
- }
- SOCKET GetSocket() const noexcept {
- return S_;
- }
- private:
- TSocket S_;
- TImpl* Server_ = nullptr;
- NAddr::IRemoteAddrRef SockAddrRef_;
- };
- void ListenSocket(size_t threadNum) {
- TThread::SetCurrentThreadName(Options_.ListenThreadName.c_str());
- TVector<void*> events;
- events.resize(Options_.EpollMaxEvents);
- TInstant now = TInstant::Now();
- for (;;) {
- try {
- Connections->Cleanup(threadNum);
- 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);
- }
- // When MaxConnections is limited or ExpirationTimeout is set, OnPollEvent can call
- // RemoveOld and destroy other IPollAble* objects in the
- // poller. Thus in this case we can safely process only one
- // event from the poller at a time.
- if (!Options_.MaxConnections && Options_.ExpirationTimeout == TDuration::Zero()) {
- if (ret >= events.size()) {
- events.resize(ret * 2);
- }
- }
- } catch (const TShouldStop&) {
- break;
- } catch (...) {
- Cb_->OnException();
- }
- }
- if (0 == --RunningListeners_) {
- 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;
- Options_.MaxQueueSize = maxQS;
- Requests->Start(Options_.nThreads, Options_.MaxQueueSize);
- }
- TImpl(THttpServer* parent, ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options_)
- : Requests(mainWorkers)
- , FailRequests(failWorkers)
- , Options_(options_)
- , Cb_(cb)
- , Parent_(parent)
- {
- if (Options_.nListenerThreads > 1) {
- Options_.OneShotPoll = true;
- const auto minPollTimeout = TDuration::MilliSeconds(100);
- if (!Options_.PollTimeout || Options_.PollTimeout > minPollTimeout) {
- Options_.PollTimeout = minPollTimeout;
- }
- Y_ENSURE(Options_.nListenerThreads < 64);
- }
- }
- TImpl(THttpServer* parent, ICallBack* cb, const TOptions& options, IThreadFactory* factory)
- : TImpl(
- parent,
- cb,
- MakeThreadPool<TSimpleThreadPool>(factory, options.UseElasticQueues, cb, options.RequestsThreadName),
- MakeThreadPool<TThreadPool>(factory, options.UseElasticQueues, nullptr, options.FailRequestsThreadName),
- options) {
- }
- ~TImpl() {
- try {
- Stop();
- } catch (...) {
- }
- }
- inline const TOptions& Options() const noexcept {
- return Options_;
- }
- inline void DecreaseConnections() noexcept {
- AtomicDecrement(ConnectionCount);
- }
- inline void IncreaseConnections() noexcept {
- AtomicIncrement(ConnectionCount);
- }
- inline i64 GetClientCount() const {
- return AtomicGet(ConnectionCount);
- }
- inline bool MaxRequestsReached() const {
- return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections);
- }
- TVector<THolder<TThread>> ListenThreads;
- std::atomic<size_t> RunningListeners_ = 0;
- TIntrusiveListWithAutoDelete<TListenSocket, TDelete> Reqs;
- TPipeHandle ListenWakeupReadFd;
- TPipeHandle ListenWakeupWriteFd;
- TMtpQueueRef Requests;
- TMtpQueueRef FailRequests;
- TAtomic ConnectionCount = 0;
- THolder<TSocketPoller> Poller;
- THolder<TConnections> Connections;
- int ErrorCode = 0;
- TOptions Options_;
- ICallBack* Cb_ = nullptr;
- THttpServer* Parent_ = nullptr;
- TWakeupPollAble WakeupPollAble;
- TMutex StopMutex;
- private:
- template <class TThreadPool_>
- static THolder<IThreadPool> MakeThreadPool(IThreadFactory* factory, bool elastic, ICallBack* callback = nullptr, const TString& threadName = {}) {
- if (!factory) {
- factory = SystemThreadFactory();
- }
- THolder<IThreadPool> pool;
- const auto params = IThreadPool::TParams().SetFactory(factory).SetThreadName(threadName);
- if (callback) {
- pool = MakeHolder<TThreadPoolBinder<TThreadPool_, THttpServer::ICallBack>>(callback, params);
- } else {
- pool = MakeHolder<TThreadPool_>(params);
- }
- if (elastic) {
- pool = MakeHolder<TElasticQueue>(std::move(pool));
- }
- 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() {
- }
- 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);
- }
- const THttpServer::TOptions& THttpServer::Options() const noexcept {
- return Impl_->Options();
- }
- size_t THttpServer::GetRequestQueueSize() const {
- return Impl_->GetRequestQueueSize();
- }
- size_t THttpServer::GetFailQueueSize() const {
- return Impl_->GetFailQueueSize();
- }
- const IThreadPool& THttpServer::GetRequestQueue() const {
- return Impl_->GetRequestQueue();
- }
- const IThreadPool& THttpServer::GetFailQueue() const {
- return Impl_->GetFailQueue();
- }
- bool THttpServer::MaxRequestsReached() const {
- return Impl_->MaxRequestsReached();
- }
- TClientConnection::TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef)
- : Socket_(s)
- , ListenerSockAddrRef_(listenerSockAddrRef)
- , HttpServ_(serv)
- {
- SetNoDelay(Socket_, true);
- const TDuration& clientTimeout = HttpServ_->Options().ClientTimeout;
- if (clientTimeout != TDuration::Zero()) {
- SetSocketTimeout(Socket_, (long)clientTimeout.Seconds(), clientTimeout.MilliSecondsOfSecond());
- }
- HttpServ_->IncreaseConnections();
- }
- TClientConnection::~TClientConnection() {
- if (!CleanupState_.Closed) {
- HttpServ_->DecreaseConnections();
- }
- }
- void TClientConnection::ScheduleDelete() {
- Socket_.Close();
- HttpServ_->DecreaseConnections();
- CleanupState_.ThreadMask = ((ui64)1 << HttpServ_->Options().nListenerThreads) - 1;
- CleanupState_.Closed = true;
- }
- 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;
- }
- }
- THolder<TClientRequest> obj(HttpServ_->CreateRequest(this_));
- AcceptMoment = now;
- HttpServ_->AddRequest(obj, Reject_);
- }
- void TClientConnection::Activate(TInstant now) noexcept {
- HttpServ_->Connections->Erase(this, now);
- LastUsed = now;
- ++ReceivedRequests;
- }
- 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*/) {
- 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;
- }
- bool TClientRequest::IsLocal() const {
- return HasLocalAddress(Socket());
- }
- bool TClientRequest::CheckLoopback() {
- bool isLocal = false;
- try {
- isLocal = IsLocal();
- } catch (const yexception& e) {
- 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;
- }
- void TClientRequest::ReleaseConnection() {
- if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) {
- Output().Finish();
- Conn_->DeActivate();
- Y_UNUSED(Conn_.Release());
- }
- }
- void TClientRequest::ResetConnection() {
- if (HttpConn_) {
- // send RST packet to client
- HttpConn_->Reset();
- HttpConn_.Destroy();
- }
- }
- void TClientRequest::Process(void* ThreadSpecificResource) {
- THolder<TClientRequest> this_(this);
- auto* serverImpl = Conn_->HttpServ_;
- 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);
- }
- if (!BeforeParseRequestOk(ThreadSpecificResource)) {
- ReleaseConnection();
- return;
- }
- if (ParsedHeaders.empty()) {
- RequestString = Input().FirstLine();
- const THttpHeaders& h = Input().Headers();
- ParsedHeaders.reserve(h.Count());
- for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) {
- ParsedHeaders.emplace_back(it->Name(), it->Value());
- }
- }
- if (Reply(ThreadSpecificResource)) {
- ReleaseConnection();
- /*
- * *this will be destroyed...
- */
- return;
- }
- } catch (...) {
- serverImpl->Cb_->OnException();
- throw;
- }
- Y_UNUSED(this_.Release());
- }
- 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...
- const char* str = RequestString.data();
- // 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;
- }
- url = RequestString.substr(start, idx - start);
- }
- }
- 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_;
- }
- const TSocket& TClientRequest::Socket() const noexcept {
- return Conn_->Socket_;
- }
- NAddr::IRemoteAddrRef TClientRequest::GetListenerSockAddrRef() const noexcept {
- return Conn_->ListenerSockAddrRef_;
- }
- TInstant TClientRequest::AcceptMoment() const noexcept {
- return Conn_->AcceptMoment;
- }
- /*
- * TRequestReplier
- */
- TRequestReplier::TRequestReplier() {
- }
- TRequestReplier::~TRequestReplier() {
- }
- bool TRequestReplier::Reply(void* threadSpecificResource) {
- const TReplyParams params = {
- threadSpecificResource, Input(), Output()};
- return DoReply(params);
- }
- bool TryToBindAddresses(const THttpServerOptions& options, const std::function<void(TSocket)>* callbackOnBoundAddress) {
- THttpServerOptions::TBindAddresses addrs;
- try {
- options.BindAddresses(addrs);
- } catch (const std::exception&) {
- return false;
- }
- for (const auto& na : addrs) {
- for (TNetworkAddress::TIterator ai = na.Begin(); ai != na.End(); ++ai) {
- NAddr::TAddrInfo addr(&*ai);
- TSocket socket(::socket(addr.Addr()->sa_family, SOCK_STREAM, 0));
- if (socket == INVALID_SOCKET) {
- return false;
- }
- FixIPv6ListenSocket(socket);
- if (options.ReuseAddress) {
- int yes = 1;
- ::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes));
- }
- if (options.ReusePort) {
- SetReusePort(socket, true);
- }
- if (::bind(socket, addr.Addr(), addr.Len()) == SOCKET_ERROR) {
- return false;
- }
- if (::listen(socket, options.ListenBacklog) == SOCKET_ERROR) {
- return false;
- }
- if (callbackOnBoundAddress != nullptr) {
- (*callbackOnBoundAddress)(socket);
- }
- }
- }
- return true;
- }
|