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
|
#pragma once
#include <map>
#include <list>
#include <atomic>
#include <BString.h>
#include <BRegex.h>
#include <Exceptions.h>
#include <Threads.h>
#include <Handle.h>
#include <Buffer.h>
#include <Http.h>
namespace Balau {
class HttpWorker;
class HttpServer {
public:
class Response {
public:
Response(HttpServer * server, Http::Request req, IO<Handle> out) : m_server(server), m_req(req), m_out(out), m_buffer(new Buffer()), m_responseCode(200), m_type("text/html; charset=UTF-8"), m_flushed(false) { }
void SetResponseCode(int code) { m_responseCode = code; }
void SetContentType(const String & type) { m_type = type; }
void setNoSize() { m_noSize = true; }
IO<Buffer> get() { return m_buffer; }
IO<Buffer> operator->() { return m_buffer; }
void Flush();
void AddHeader(const String & line) { m_extraHeaders.push_front(line); }
void AddHeader(const String & key, const String & val) { AddHeader(key + ": " + val); }
private:
HttpServer * m_server;
Http::Request m_req;
IO<Handle> m_out;
IO<Buffer> m_buffer;
int m_responseCode;
String m_type;
std::list<String> m_extraHeaders;
bool m_flushed;
bool m_noSize = false;
Response(const Response &) = delete;
Response & operator=(const Response &) = delete;
};
class Action {
public:
Action(const Regex & regex, const Regex & host = Regexes::any) : m_regex(regex), m_host(host), m_refCount(0) { }
virtual ~Action() { AAssert(m_refCount == 0, "Don't delete an Action directly"); }
struct ActionMatch {
Regex::Captures uri, host;
};
ActionMatch matches(const char * uri, const char * host);
void unref() { if (--m_refCount == 0) delete this; }
void ref() { ++m_refCount; }
void registerMe(HttpServer * server) { server->registerAction(this); }
virtual bool Do(HttpServer * server, Http::Request & req, ActionMatch & match, IO<Handle> out) throw (GeneralException) = 0;
private:
const Regex m_regex, m_host;
std::atomic<int> m_refCount;
Action(const Action &) = delete;
Action & operator=(const Action &) = delete;
};
HttpServer() : m_started(false), m_listenerPtr(NULL), m_port(80) { }
~HttpServer() { if (!m_started) stop(); }
void start();
void stop();
void setPort(int port) { AAssert(!m_started, "You can't set the HTTP port once the server has started"); m_port = port; }
void setLocal(const char * local) { AAssert(!m_started, "You can't set the HTTP IP once the server has started"); m_local = local; }
void registerAction(Action * action);
void flushAllActions();
struct ActionFound {
Action * action;
Action::ActionMatch matches;
};
ActionFound findAction(const char * uri, const char * host);
String getServerName() { return "Balau/1.0"; }
bool started();
private:
bool m_started;
void * m_listenerPtr;
int m_port;
String m_local;
typedef std::list<Action *> ActionList;
ActionList m_actions;
RWLock m_actionsLock;
Events::TaskEvent m_listenerEvent;
friend class HttpWorker;
HttpServer(const HttpServer &) = delete;
HttpServer & operator=(const HttpServer &) = delete;
};
};
|