@@ -21,7 +21,6 @@ struct file_server;
21
21
typedef http::server<file_server> server;
22
22
23
23
struct file_cache {
24
-
25
24
typedef std::map<std::string, std::pair<void *, std::size_t > > region_map;
26
25
typedef std::map<std::string, std::vector<server::response_header> > meta_map;
27
26
@@ -66,7 +65,8 @@ struct file_cache {
66
65
67
66
regions.insert (std::make_pair (real_filename, std::make_pair (region, size)));
68
67
static server::response_header common_headers[] = {
69
- {" Connection" , " close" }, {" Content-Type" , " x-application/octet-stream" },
68
+ {" Connection" , " close" },
69
+ {" Content-Type" , " x-application/octet-stream" },
70
70
{" Content-Length" , " 0" }};
71
71
std::vector<server::response_header> headers (common_headers,
72
72
common_headers + 3 );
@@ -91,8 +91,7 @@ struct file_cache {
91
91
static std::vector<server::response_header> empty_vector;
92
92
auto headers = file_headers.find (doc_root_ + path);
93
93
if (headers != file_headers.end ()) {
94
- auto begin = headers->second .begin (),
95
- end = headers->second .end ();
94
+ auto begin = headers->second .begin (), end = headers->second .end ();
96
95
return boost::make_iterator_range (begin, end);
97
96
} else
98
97
return boost::make_iterator_range (empty_vector);
@@ -138,22 +137,75 @@ struct connection_handler : std::enable_shared_from_this<connection_handler> {
138
137
asio::const_buffers_1 (
139
138
static_cast <char const *>(mmaped_region.first ) + offset,
140
139
rightmost_bound - offset),
141
- [=] (std::error_code const &ec) {
140
+ [=](std::error_code const &ec) {
142
141
self->handle_chunk (mmaped_region, rightmost_bound, connection, ec);
143
142
});
144
143
}
145
144
146
145
void handle_chunk (std::pair<void *, std::size_t > mmaped_region, off_t offset,
147
146
server::connection_ptr connection,
148
147
std::error_code const &ec) {
149
- assert (offset>= 0 );
148
+ assert (offset >= 0 );
150
149
if (!ec && static_cast <std::size_t >(offset) < mmaped_region.second )
151
150
send_file (mmaped_region, offset, connection);
152
151
}
153
152
154
153
file_cache &file_cache_;
155
154
};
156
155
156
+ struct input_consumer : public std ::enable_shared_from_this<input_consumer> {
157
+ // Maximum size for incoming request bodies.
158
+ static constexpr std::size_t MAX_INPUT_BODY_SIZE = 2 << 16 ;
159
+
160
+ explicit input_consumer (std::shared_ptr<connection_handler> h,
161
+ server::request r)
162
+ : request_(std::move(r)), handler_(std::move(h)), content_length_{0 } {
163
+ for (const auto &header : request_.headers ) {
164
+ if (boost::iequals (header.name , " content-length" )) {
165
+ content_length_ = std::stoul (header.value );
166
+ std::cerr << " Content length: " << content_length_ << ' \n ' ;
167
+ break ;
168
+ }
169
+ }
170
+ }
171
+
172
+ void operator ()(server::connection::input_range input, std::error_code ec,
173
+ std::size_t bytes_transferred,
174
+ server::connection_ptr connection) {
175
+ std::cerr << " Callback: " << bytes_transferred << " ; ec = " << ec << ' \n ' ;
176
+ if (ec == asio::error::eof) return ;
177
+ if (!ec) {
178
+ if (empty (input))
179
+ return (*handler_)(request_.destination , connection, true );
180
+ request_.body .insert (request_.body .end (), boost::begin (input),
181
+ boost::end (input));
182
+ if (request_.body .size () > MAX_INPUT_BODY_SIZE) {
183
+ connection->set_status (server::connection::bad_request);
184
+ static server::response_header error_headers[] = {
185
+ {" Connection" , " close" }};
186
+ connection->set_headers (
187
+ boost::make_iterator_range (error_headers, error_headers + 1 ));
188
+ connection->write (" Body too large." );
189
+ return ;
190
+ }
191
+ std::cerr << " Body: " << request_.body << ' \n ' ;
192
+ if (request_.body .size () == content_length_)
193
+ return (*handler_)(request_.destination , connection, true );
194
+ std::cerr << " Scheduling another read...\n " ;
195
+ auto self = this ->shared_from_this ();
196
+ connection->read ([self](server::connection::input_range input,
197
+ std::error_code ec, std::size_t bytes_transferred,
198
+ server::connection_ptr connection) {
199
+ (*self)(input, ec, bytes_transferred, connection);
200
+ });
201
+ }
202
+ }
203
+
204
+ server::request request_;
205
+ std::shared_ptr<connection_handler> handler_;
206
+ size_t content_length_;
207
+ };
208
+
157
209
struct file_server {
158
210
explicit file_server (file_cache &cache) : cache_(cache) {}
159
211
@@ -165,6 +217,14 @@ struct file_server {
165
217
} else if (request.method == " GET" ) {
166
218
std::shared_ptr<connection_handler> h (new connection_handler (cache_));
167
219
(*h)(request.destination , connection, true );
220
+ } else if (request.method == " PUT" || request.method == " POST" ) {
221
+ auto h = std::make_shared<connection_handler>(cache_);
222
+ auto c = std::make_shared<input_consumer>(h, request);
223
+ connection->read ([c](server::connection::input_range input,
224
+ std::error_code ec, std::size_t bytes_transferred,
225
+ server::connection_ptr connection) {
226
+ (*c)(input, ec, bytes_transferred, connection);
227
+ });
168
228
} else {
169
229
static server::response_header error_headers[] = {
170
230
{" Connection" , " close" }};
@@ -184,11 +244,10 @@ int main(int, char *[]) {
184
244
file_server handler (cache);
185
245
server::options options (handler);
186
246
server instance (options.thread_pool (std::make_shared<utils::thread_pool>(4 ))
187
- .address (" 0.0.0.0" )
188
- .port (" 8000" ));
247
+ .address (" 0.0.0.0" )
248
+ .port (" 8000" ));
189
249
instance.run ();
190
- }
191
- catch (std::exception &e) {
250
+ } catch (std::exception &e) {
192
251
std::cerr << e.what () << std::endl;
193
252
}
194
253
}
0 commit comments