On 03/07/2017 03:07, Vinnie Falco via Boost wrote:
On Sun, Jul 2, 2017 at 6:43 PM, Niall Douglas via Boost
wrote: It's nearly 3am here...
I looked once again at http::basic_parser and http::serializer. It might be possible to refactor http::basic_parser into a separate class and with some mess in http::parser support two versions. One which allows ConstBufferSequence and the other which allows just pair
.
I've always felt concern about pair
http::serializer is another story entirely. It contains and is tied to adapters which contain Asio buffer types. And it uses Asio buffer algorithms.
You've taken the position that this is an easy matter, that you have extensive knowledge and experience in the domain, so I would kindly ask that you provide a working prototype of http::serializer which does not use Asio buffer types and yet remains compatible with the rest of Beast.
Your http::serializer claims it is for: 1. Send the header first, and the body later. 2. Set chunk extensions or trailers using a chunk decorator. 3. Send a message incrementally: bounded work in each I/O cycle. 4. Use a series of caller-provided buffers to represent the body. The way I've always implemented HTTP serialisers in the recent past is as a collection of open ranges of contiguous byte buffers for ASIO to gather send from. Generally I've kept a headers() collection and a body() collection. Iterators for the whole serialiser iterate all the headers first, then the body. But if the end user wanted to send just the headers first, they simply by hand feed the headers range to ASIO first, then the body range. So that's Item 1 taken care of. Item 2, as I mentioned before I've never needed more than basic HTTP in my career to date, so never needed to implement chunked encoding. But I can tell you what my first instinct is: body() is a FIFO drain, so as the user appends new body buffers, they get drained and sent. So, the end iterator returned by body() is able to stop pointing after the last item in body() if new items are added to body(). Item 3 is very straightforward because the end user is the person creating the iterator range to hand to ASIO. So they simply choose a range which is a subset of the total instead of the total. Item 4 is even easier, because this entire design already is a series of caller provided buffers from start to finish. Beast might provide convenience functions for generating those buffers, but essentially the caller supplies the buffers. Finally, trailers I have never had need to implement either, but I'd suggest a trailers() collection for those as well. Exactly the same semantics as earlier. I appreciate Vinnie that you envisioned Beast as doing all this stuff for the end user and hiding all this complexity by wrapping up ASIO with an i/o API which hides how ASIO is being used underneath. I think that makes sense in a high level HTTP library. For a low level HTTP library I think it a design mistake, much simpler is much better. Less is more. I've used the above serialiser design on a number of occasions now, it's very efficient, composable, and flexible. It *does* push understanding of HTTP onto the end user, but then if the end user doesn't understand HTTP, they wouldn't be able to use a low level library anyway. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/