Re: [asio-users] asio http code examples
Brought to you by:
chris_kohlhoff
From: Christopher K. <chr...@ya...> - 2004-11-18 22:05:13
|
Hi Jose, --- jose <jj...@ya...> wrote: > I would like to get some guidance to start some real > world web examples that would make the library even > more interesting: > > - an http 1.0 get request > - a simple proxy that gets one http request and issues > multiple http requests and sends back a summary > response > > Let me know any info you have to get me started on > this or maybe you already coded something very similar Although some HTTP code has been written using asio, it is owned by a company and can't be freely shared. However I can outline two possible ways for implementing it. I'll only talk about how to receive and decode an http message, since sending is trivial. There are two approaches that I am aware of... The first approach involves using a buffered stream. This gives you the ability to peek ahead at data without removing it from the stream, something you can't do without buffering. To implement this way you break down the HTTP response into its syntactic elements, i.e.: - status line - multiple headers - body For each element you write an async_recv function, e.g.: template <typename Buffered_Stream, typename Handler> void async_recv_http_status_line(Buffered_Stream& stream, http_status_line& status_line, Handler handler) { ... } In http the status line is terminated with "\r\n", so the implementation of the above function would scan the stream's buffer for that delimiter. If it can't find it, it extracts all data from the stream, and then does an async_fill() on the stream to get more data. Once this is complete it scans for the delimiter again. Once low level functions like this have been implemented, you then implement an overall function: template <typename Buffered_Stream, typename Handler> void async_recv_http_response(Buffered_Stream& stream, http_response& response, Handler handler) { ... } This function is implemented using the functions for each element. That is, it chains them together (one async operation after another) until the whole message has been received. The second approach (and the one we have used) does not require a buffered stream, and so may be more efficient. It might also be more work to develop, but I'm not sure. In this approach you develop a standalone http message decoder that you feed data to. E.g. the class interface looks a bit like: class http_response_decoder { public: enum status_type { need_more_data, decode_complete, decode_error }; status_type decode(http_response& response, const char* begin, const char* end, const char*& new_begin); }; Here, begin and end tell the decoder what buffer it should use as input data to perform decoding. The new_begin parameter is updated to indicate how much data has been consumed by the decoder. Once data has been consumed there is no need to keep it in the buffer any more. The decoder is typically implemented using a state machine (or nested state machines). You use it by receiving a chunk of data (of any length) off the socket using async_recv, and then feed that buffer to the decoder. The decoder tells you if you need more data, in which case you issue another async_recv. If the decoder tells you that decoding is complete you can pass the response to your application and then return to receiving more data. Cheers, Chris |