summaryrefslogtreecommitdiff
path: root/src/transport.hh
blob: 5e6733ff8a93076770a5f2e310f45354927ff302 (plain)
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
#ifndef TRANSPORT_HH
#define TRANSPORT_HH

#include "unique_fd.hh"

#include <filesystem>
#include <functional>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>

class Buffer;
class Config;
class Logger;
class Looper;
class TaskRunner;

class Transport {
public:
  class Request {
  public:
    virtual ~Request() = default;

    virtual std::string_view method() const = 0;
    virtual std::string_view path() const = 0;
    virtual std::string_view query(std::string_view name) const = 0;
    virtual std::optional<std::string> header_one(
        std::string_view name) const = 0;
    virtual std::vector<std::string> header_all(
        std::string_view name) const = 0;
  };

  class Input {
  public:
    virtual ~Input() = default;

    enum class Return {
      OK,  // At least one byte was added to buffer.
      FULL,  // Zero bytes added to buffer as it is full.
      END, // Zero or more bytes added to buffer but there are no more bytes
           // available because input has ended.
      ERR, // No bytes added to buffer and there was an fatal error reading
           // any more bytes.
      WAIT,  // Zero or more bytes added to buffer but wait before calling
             // fill again (see wait_once).
    };

    virtual Return fill(Buffer* buffer, size_t buf_request_size = 1) = 0;

    // Setup callback to be called when Input is ready to be read again using
    // looper. Callback will only be called once. Callback might be called
    // before wait returns if Input is already ready. If Input is destroyed
    // before getting ready the callback will never be called.
    virtual void wait_once(std::shared_ptr<Looper> looper,
                           std::function<void()> callback) = 0;

  protected:
    Input() = default;
  };

  class Response {
  public:
    virtual ~Response() = default;

    virtual uint16_t code() const = 0;
    virtual std::vector<std::pair<std::string, std::string>> const&
        headers() const = 0;
    // Only call this once. If it returns null, call open_content_async instead.
    virtual std::unique_ptr<Input> open_content() = 0;
    // Only call this once and only if open_content() first returned nullptr.
    // If response is destroyed before callback is posted the callback will
    // never be posted. But if callback is already posted then it will run,
    // and the input will still be valid.
    virtual void open_content_async(
        std::shared_ptr<TaskRunner> runner,
        std::function<void(std::unique_ptr<Input>)> callback);

    virtual void add_header(std::string name, std::string value) = 0;

  protected:
    Response() = default;
  };

  std::unique_ptr<Response> create_ok_data(std::string data);
  std::unique_ptr<Response> create_ok_file(std::filesystem::path path);
  std::unique_ptr<Response> create_ok_exif_thumbnail(
      std::filesystem::path path);
  std::unique_ptr<Response> create_not_found();
  std::unique_ptr<Response> create_redirect(std::string target,
                                            bool temporary = true);
  virtual std::unique_ptr<Response> create_data(
      uint16_t code, std::string data) = 0;
  virtual std::unique_ptr<Response> create_file(
      uint16_t code, std::filesystem::path data) = 0;
  virtual std::unique_ptr<Response> create_exif_thumbnail(
      uint16_t code, std::filesystem::path data) = 0;

  class Handler {
  public:
    virtual ~Handler() = default;

    virtual std::unique_ptr<Response> request(Transport* transport,
                                              Request const* request) = 0;

  protected:
    Handler() = default;
  };

  // Takes care of GET/HEAD, optional cache headers and general housekeeping.
  // Also removes // and similar from paths.
  static std::unique_ptr<Handler> create_default_handler(
      std::shared_ptr<Logger> logger,
      Handler* handler);

  class Factory {
  public:
    virtual ~Factory() = default;

    virtual std::unique_ptr<Transport> create(
        std::shared_ptr<Logger> logger,
        std::shared_ptr<Looper> looper,
        std::shared_ptr<TaskRunner> runner,
        // config_logger is used to write any errors during create
        // when reading the config. No reference kept as with logger.
        Logger* config_logger,
        Config const* config,
        Handler* handler) = 0;

  protected:
    Factory() = default;
    Factory(Factory const&) = delete;
    Factory& operator=(Factory const&) = delete;
  };

  virtual ~Transport() = default;

  virtual void add_client(unique_fd&& fd) = 0;

protected:
  Transport() = default;
  Transport(Transport const&) = delete;
  Transport& operator=(Transport const&) = delete;
};

#endif  // TRANSPORT_HH