1#pragma once
 2
 3#include <atomic>
 4#include <functional>
 5#include <map>
 6#include <string>
 7#include <thread>
 8
 9struct common_params;
10
11// generator-like API for HTTP response generation
12// this object response with one of the 2 modes:
13// 1) normal response: `data` contains the full response body
14// 2) streaming response: each call to next(output) generates the next chunk
15//    when next(output) returns false, no more data after the current chunk
16//    note: some chunks can be empty, in which case no data is sent for that chunk
17struct server_http_res {
18    std::string content_type = "application/json; charset=utf-8";
19    int status = 200;
20    std::string data;
21    std::map<std::string, std::string> headers;
22
23    // TODO: move this to a virtual function once we have proper polymorphism support
24    std::function<bool(std::string &)> next = nullptr;
25    bool is_stream() const {
26        return next != nullptr;
27    }
28
29    virtual ~server_http_res() = default;
30};
31
32// unique pointer, used by set_chunked_content_provider
33// httplib requires the stream provider to be stored in heap
34using server_http_res_ptr = std::unique_ptr<server_http_res>;
35
36struct server_http_req {
37    std::map<std::string, std::string> params; // path_params + query_params
38    std::map<std::string, std::string> headers; // reserved for future use
39    std::string path; // reserved for future use
40    std::string body;
41    const std::function<bool()> & should_stop;
42
43    std::string get_param(const std::string & key, const std::string & def = "") const {
44        auto it = params.find(key);
45        if (it != params.end()) {
46            return it->second;
47        }
48        return def;
49    }
50};
51
52struct server_http_context {
53    class Impl;
54    std::unique_ptr<Impl> pimpl;
55
56    std::thread thread; // server thread
57    std::atomic<bool> is_ready = false;
58
59    std::string path_prefix;
60    std::string hostname;
61    int port;
62
63    server_http_context();
64    ~server_http_context();
65
66    bool init(const common_params & params);
67    bool start();
68    void stop() const;
69
70    // note: the handler should never throw exceptions
71    using handler_t = std::function<server_http_res_ptr(const server_http_req & req)>;
72
73    void get(const std::string & path, const handler_t & handler) const;
74    void post(const std::string & path, const handler_t & handler) const;
75
76    // for debugging
77    std::string listening_address;
78};