18
18
#include < boost/asio/strand.hpp>
19
19
#include < boost/asio/buffer.hpp>
20
20
#include < boost/make_shared.hpp>
21
+ #include < boost/network/protocol/http/server/request_parser.hpp>
22
+ #include < boost/range/iterator_range.hpp>
23
+ #include < boost/spirit/include/qi.hpp>
21
24
#include < list>
22
25
#include < vector>
23
26
#include < iterator>
@@ -37,7 +40,6 @@ namespace boost { namespace network { namespace http {
37
40
38
41
template <class Tag , class Handler >
39
42
struct async_connection : boost::enable_shared_from_this<async_connection<Tag,Handler> > {
40
- static std::size_t const connection_buffer_size = BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE;
41
43
42
44
enum status_t {
43
45
ok = 200
@@ -61,6 +63,7 @@ namespace boost { namespace network { namespace http {
61
63
};
62
64
63
65
typedef typename string<Tag>::type string_type;
66
+ typedef basic_request<Tag> request;
64
67
65
68
async_connection (
66
69
asio::io_service & io_service
@@ -73,7 +76,9 @@ namespace boost { namespace network { namespace http {
73
76
, thread_pool_(thread_pool)
74
77
, headers_already_sent(false )
75
78
, headers_buffer(BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE)
76
- {}
79
+ {
80
+ new_start = read_buffer_.begin ();
81
+ }
77
82
78
83
/* * Function: template <class Range> set_headers(Range headers)
79
84
* Precondition: headers have not been sent yet
@@ -146,22 +151,26 @@ namespace boost { namespace network { namespace http {
146
151
// TODO implement a sane default here, for now ignore the error
147
152
}
148
153
154
+ typedef boost::array<char , BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE> buffer_type;
155
+ typedef boost::array<char , BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE> array;
156
+ typedef std::list<shared_ptr<array> > array_list;
157
+ typedef boost::shared_ptr<array_list> shared_array_list;
158
+ typedef boost::shared_ptr<std::vector<asio::const_buffer> > shared_buffers;
159
+ typedef request_parser<Tag> request_parser_type;
160
+
149
161
asio::ip::tcp::socket socket_;
150
162
asio::io_service::strand strand;
151
163
Handler & handler;
152
164
utils::thread_pool & thread_pool_;
153
165
bool headers_already_sent;
154
166
asio::streambuf headers_buffer;
155
167
156
- typedef boost::array<char , connection_buffer_size>
157
- buffer_type;
158
- typedef boost::array<char , connection_buffer_size>
159
- array;
160
- typedef std::list<shared_ptr<array> > array_list;
161
- typedef boost::shared_ptr<array_list> shared_array_list;
162
- typedef boost::shared_ptr<std::vector<asio::const_buffer> > shared_buffers;
163
168
buffer_type read_buffer_;
164
169
boost::uint16_t status;
170
+ request_parser_type parser;
171
+ request request_;
172
+ buffer_type::iterator new_start;
173
+ string_type partial_parsed;
165
174
166
175
template <class , class > friend struct async_server_base ;
167
176
@@ -170,24 +179,166 @@ namespace boost { namespace network { namespace http {
170
179
};
171
180
172
181
void start () {
182
+ read_more (method);
183
+ }
184
+
185
+ void read_more (state_t state) {
173
186
socket_.async_read_some (
174
187
asio::buffer (read_buffer_)
175
188
, strand.wrap (
176
189
boost::bind (
177
190
&async_connection<Tag,Handler>::handle_read_data,
178
191
async_connection<Tag,Handler>::shared_from_this (),
179
- method ,
192
+ state ,
180
193
boost::asio::placeholders::error,
181
194
boost::asio::placeholders::bytes_transferred
182
195
)
183
196
)
184
197
);
185
198
}
186
199
187
- void handle_read_data (state_t , boost::system::error_code const & ec, std::size_t bytes_transferred) {
188
- // FIXME -- damn all that work got wiped out because Jeni tripped on the power. :(
200
+ void handle_read_data (state_t state, boost::system::error_code const & ec, std::size_t bytes_transferred) {
201
+ if (!ec) {
202
+ logic::tribool parsed_ok;
203
+ iterator_range<buffer_type::iterator> result_range, input_range;
204
+ switch (state) {
205
+ case method:
206
+ input_range = boost::make_iterator_range (
207
+ new_start, read_buffer_.end ());
208
+ fusion::tie (parsed_ok, result_range) = parser.parse_until (
209
+ request_parser_type::method_done, input_range);
210
+ if (!parsed_ok) {
211
+ client_error ();
212
+ break ;
213
+ } else if (parsed_ok == true ) {
214
+ swap (partial_parsed, request_.method );
215
+ request_.method .append (
216
+ boost::begin (result_range),
217
+ boost::end (result_range));
218
+ trim (request_.method );
219
+ new_start = boost::end (result_range);
220
+ } else {
221
+ partial_parsed.append (
222
+ boost::begin (result_range),
223
+ boost::end (result_range));
224
+ new_start = read_buffer_.begin ();
225
+ read_more (method);
226
+ break ;
227
+ }
228
+ case uri:
229
+ input_range = boost::make_iterator_range (
230
+ new_start, read_buffer_.end ());
231
+ fusion::tie (parsed_ok, result_range) = parser.parse_until (
232
+ request_parser_type::uri_done,
233
+ input_range);
234
+ if (!parsed_ok) {
235
+ client_error ();
236
+ break ;
237
+ } else if (parsed_ok == true ) {
238
+ swap (partial_parsed, request_.destination );
239
+ request_.destination .append (
240
+ boost::begin (result_range),
241
+ boost::end (result_range));
242
+ trim (request_.destination );
243
+ new_start = boost::end (result_range);
244
+ } else {
245
+ partial_parsed.append (
246
+ boost::begin (result_range),
247
+ boost::end (result_range));
248
+ new_start = read_buffer_.begin ();
249
+ read_more (uri);
250
+ break ;
251
+ }
252
+ case version:
253
+ input_range = boost::make_iterator_range (
254
+ new_start, read_buffer_.end ());
255
+ fusion::tie (parsed_ok, result_range) = parser.parse_until (
256
+ request_parser_type::version_done,
257
+ input_range);
258
+ if (!parsed_ok) {
259
+ client_error ();
260
+ break ;
261
+ } else if (parsed_ok == true ) {
262
+ fusion::tuple<uint8_t , uint8_t > version_pair;
263
+ using namespace boost ::spirit::qi;
264
+ partial_parsed.append (boost::begin (result_range), boost::end (result_range));
265
+ parse (
266
+ partial_parsed.begin (), partial_parsed.end (),
267
+ (
268
+ lit (" HTTP/" )
269
+ >> ushort_
270
+ >> ' .'
271
+ >> ushort_
272
+ )
273
+ , version_pair);
274
+ request_.http_version_major = fusion::get<0 >(version_pair);
275
+ request_.http_version_minor = fusion::get<1 >(version_pair);
276
+ new_start = boost::end (result_range);
277
+ } else {
278
+ partial_parsed.append (
279
+ boost::begin (result_range),
280
+ boost::end (result_range));
281
+ new_start = read_buffer_.begin ();
282
+ read_more (version);
283
+ break ;
284
+ }
285
+ case headers:
286
+ input_range = boost::make_iterator_range (
287
+ new_start, read_buffer_.end ());
288
+ fusion::tie (parsed_ok, result_range) = parser.parse_until (
289
+ request_parser_type::headers_done,
290
+ input_range);
291
+ if (!parsed_ok) {
292
+ client_error ();
293
+ break ;
294
+ } else if (parsed_ok == true ) {
295
+ partial_parsed.append (
296
+ boost::begin (result_range),
297
+ boost::end (result_range));
298
+ trim (partial_parsed);
299
+ parse_headers (partial_parsed, request_.headers );
300
+ new_start = boost::end (result_range);
301
+ thread_pool ().post (
302
+ boost::bind (
303
+ &Handler::operator (),
304
+ handler,
305
+ cref (request_),
306
+ async_connection<Tag,Handler>::shared_from_this ()));
307
+ return ;
308
+ } else {
309
+ partial_parsed.append (
310
+ boost::begin (result_range),
311
+ boost::end (result_range));
312
+ new_start = read_buffer_.begin ();
313
+ read_more (headers);
314
+ break ;
315
+ }
316
+ default :
317
+ BOOST_ASSERT (false && " This is a bug, report to the cpp-netlib devel mailing list!" );
318
+ std::abort ();
319
+ }
320
+ }
321
+ // TODO log the error
189
322
}
190
323
324
+ void client_error () {
325
+ // FIXME write out a client request error
326
+ }
327
+
328
+ void parse_headers (string_type & input, typename request::headers_container_type & container) {
329
+ using namespace boost ::spirit::qi;
330
+ std::vector<fusion::tuple<std::string,std::string> > headers;
331
+ parse (
332
+ input.begin (), input.end (),
333
+ *(
334
+ +(alnum|(punct-' :' ))
335
+ >> lit (" : " )
336
+ >> +(alnum|space|punct)
337
+ >> lit (" \r\n " )
338
+ )
339
+ , headers
340
+ );
341
+ }
191
342
template <class Range , class Callback >
192
343
void write_headers (Range range, Callback callback) {
193
344
// TODO send out the headers, then once that's done
@@ -236,6 +387,7 @@ namespace boost { namespace network { namespace http {
236
387
// on doing I/O.
237
388
//
238
389
390
+ static std::size_t const connection_buffer_size = BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE;
239
391
shared_array_list temporaries =
240
392
boost::make_shared<array_list>();
241
393
shared_buffers buffers =
0 commit comments