1818#include < boost/asio/strand.hpp>
1919#include < boost/asio/buffer.hpp>
2020#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>
2124#include < list>
2225#include < vector>
2326#include < iterator>
@@ -37,7 +40,6 @@ namespace boost { namespace network { namespace http {
3740
3841template <class Tag ,class Handler >
3942struct 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;
4143
4244enum status_t {
4345 ok =200
@@ -61,6 +63,7 @@ namespace boost { namespace network { namespace http {
6163 };
6264
6365typedef typename string<Tag>::type string_type;
66+ typedef basic_request<Tag> request;
6467
6568async_connection (
6669 asio::io_service & io_service
@@ -73,7 +76,9 @@ namespace boost { namespace network { namespace http {
7376 , thread_pool_(thread_pool)
7477 , headers_already_sent(false )
7578 , headers_buffer(BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE)
76- {}
79+ {
80+ new_start = read_buffer_.begin ();
81+ }
7782
7883/* * Function: template <class Range> set_headers(Range headers)
7984 * Precondition: headers have not been sent yet
@@ -146,22 +151,26 @@ namespace boost { namespace network { namespace http {
146151// TODO implement a sane default here, for now ignore the error
147152 }
148153
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+
149161 asio::ip::tcp::socket socket_;
150162 asio::io_service::strand strand;
151163 Handler & handler;
152164 utils::thread_pool & thread_pool_;
153165bool headers_already_sent;
154166 asio::streambuf headers_buffer;
155167
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;
163168 buffer_type read_buffer_;
164169 boost::uint16_t status;
170+ request_parser_type parser;
171+ request request_;
172+ buffer_type::iterator new_start;
173+ string_type partial_parsed;
165174
166175template <class ,class >friend struct async_server_base ;
167176
@@ -170,24 +179,166 @@ namespace boost { namespace network { namespace http {
170179 };
171180
172181void start () {
182+ read_more (method);
183+ }
184+
185+ void read_more (state_t state) {
173186 socket_.async_read_some (
174187asio::buffer (read_buffer_)
175188 , strand.wrap (
176189boost::bind (
177190 &async_connection<Tag,Handler>::handle_read_data,
178191 async_connection<Tag,Handler>::shared_from_this (),
179- method ,
192+ state ,
180193 boost::asio::placeholders::error,
181194 boost::asio::placeholders::bytes_transferred
182195 )
183196 )
184197 );
185198 }
186199
187- void handle_read_data (state_t , boost::system::error_codeconst & 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_codeconst & 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
189322 }
190323
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+ }
191342template <class Range ,class Callback >
192343void write_headers (Range range, Callback callback) {
193344// TODO send out the headers, then once that's done
@@ -236,6 +387,7 @@ namespace boost { namespace network { namespace http {
236387// on doing I/O.
237388//
238389
390+ static std::size_t const connection_buffer_size = BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE;
239391 shared_array_list temporaries =
240392 boost::make_shared<array_list>();
241393 shared_buffers buffers =