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};