aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/http/server/http.h
blob: 517fcf9eb25f286ef0a7dde540c53a8bb2bb850b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#pragma once

#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/generic/ptr.h>
#include <util/generic/vector.h>
#include <util/system/atomic.h>

class IThreadFactory; 
class TClientRequest;
class TClientConnection;

class THttpServer {
    friend class TClientRequest;
    friend class TClientConnection;

public:
    class ICallBack {
    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() {
            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;

    static TAtomicBase AcceptReturnsInvalidSocketCounter();

private:
    bool MaxRequestsReached() const;

private:
    THolder<TImpl> Impl_;
};

/**
 * @deprecated Use TRequestReplier instead
 */
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:
    /*
     * Processes the request after 'connection' been created and 'Headers' been read
     * Returns 'false' if the processing must be continued by the next handler,
     * 'true' otherwise ('this' will be deleted)
     */
    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 {
public:
    TRequestReplier();
    ~TRequestReplier() override;

    struct TReplyParams {
        void* ThreadSpecificResource;
        THttpInput& Input;
        THttpOutput& Output;
    };

    /*
     * Processes the request after 'connection' been created and 'Headers' been read
     * Returns 'false' if the processing must be continued by the next handler,
     * 'true' otherwise ('this' will be deleted)
     */
    virtual bool DoReply(const TReplyParams& params) = 0;

private:
    bool Reply(void* threadSpecificResource) final;

    using TClientRequest::Input;
    using TClientRequest::Output;
};

bool TryToBindAddresses(const THttpServerOptions& options, const std::function<void(TSocket)>* callbackOnBoundAddress = nullptr);