-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathhttp_request_handler.cpp
More file actions
117 lines (102 loc) · 3.73 KB
/
http_request_handler.cpp
File metadata and controls
117 lines (102 loc) · 3.73 KB
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
#include <boost/regex.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "async_web_server_cpp/http_request_handler.hpp"
#include "async_web_server_cpp/http_connection.hpp"
#include "async_web_server_cpp/http_reply.hpp"
namespace async_web_server_cpp
{
HttpRequestHandlerGroup::HttpRequestHandlerGroup(HttpServerRequestHandler default_handler)
: default_handler_(default_handler)
{
}
class PathMatcher
{
public:
explicit PathMatcher(const std::string &path_regex_string)
: path_regex_(boost::regex(path_regex_string))
{
}
bool operator()(const HttpRequest &request)
{
return regex_match(request.path, path_regex_);
}
private:
const boost::regex path_regex_;
};
void HttpRequestHandlerGroup::addHandlerForPath(const std::string &path_regex, HttpServerRequestHandler handler)
{
addHandler(PathMatcher(path_regex), handler);
}
void HttpRequestHandlerGroup::addHandler(HandlerPredicate predicate, HttpServerRequestHandler handler)
{
handlers_.push_back(std::make_pair(predicate, handler));
}
bool HttpRequestHandlerGroup::operator()(const HttpRequest &request, boost::shared_ptr<HttpConnection> connection, const char* begin, const char* end)
{
for (size_t i = 0; i < handlers_.size(); ++i)
{
std::pair<HandlerPredicate, HttpServerRequestHandler> &handler = handlers_[i];
if (handler.first(request))
{
if(handler.second(request, connection, begin, end))
return true;
}
}
return default_handler_(request, connection, begin, end);
}
class BodyCollectingConnection;
typedef boost::shared_ptr<BodyCollectingConnection> BodyCollectingConnectionPtr;
typedef boost::weak_ptr<BodyCollectingConnection> BodyCollectingConnectionWeakPtr;
class BodyCollectingConnection : public boost::enable_shared_from_this<BodyCollectingConnection>,
private boost::noncopyable
{
public:
BodyCollectingConnection(HttpRequestBodyCollector::Handler handler, const HttpRequest &request, boost::shared_ptr<HttpConnection> connection)
: handler_(handler), request_(request), connection_(connection), received_length_(0) {
std::string length_str = request_.get_header_value_or_default("Content-Length", "");
try {
length_ = boost::lexical_cast<ssize_t>(length_str);
}
catch(const boost::bad_lexical_cast &) {
length_ = -1; //indicate error
}
}
static void static_handle_read(BodyCollectingConnectionPtr _this, const char* begin, const char* end) {
_this->handle_read(begin, end);
}
void handle_read(const char* begin, const char* end) {
if(length_ < 0) {
HttpReply::builder(HttpReply::bad_request).write(connection_);
connection_->write("No Content-Length header");
return;
}
std::string chunk(begin, end-begin);
body_stream_ << chunk;
received_length_ += chunk.length();
if(received_length_ >= size_t(length_)) {
handler_(request_, connection_, body_stream_.str().substr(0, length_));
}
else {
connection_->async_read(boost::bind(&BodyCollectingConnection::static_handle_read, shared_from_this(), _1, _2));
}
}
private:
HttpRequestBodyCollector::Handler handler_;
const HttpRequest request_;
boost::shared_ptr<HttpConnection> connection_;
std::stringstream body_stream_;
ssize_t length_;
size_t received_length_;
};
HttpRequestBodyCollector::HttpRequestBodyCollector(Handler handler)
: handler_(handler) {}
bool HttpRequestBodyCollector::operator()(const HttpRequest &request, boost::shared_ptr<HttpConnection> connection, const char* begin, const char* end)
{
BodyCollectingConnectionPtr collecting_connection(new BodyCollectingConnection(handler_, request, connection));
collecting_connection->handle_read(begin, end);
return true;
}
}