Re: [boost] [asio-users] [http] Formal review of Boost.Http
On 7 Aug 2015 at 19:29, Vinícius dos Santos Oliveira wrote:
I do not believe Http is ready for peer review for these reasons, and I personally would urge you withdraw it until you have fixed these issues and then come back to us. If you do not withdraw it, I will vote for rejection.
Can I persuade you to review the Boost.Http design? I'd reject myself if you find any fundamental flaw on the design and even if you're going to reject the library because the lack of tooling (not directly related to design or documentation, which are the most important items on any library), it'd be useful to know what needs to be addressed on the design before I submit again (in the case the submission is rejected).
I think my earlier email was poorly phrased now I've slept on it. I made my objections seem like they were about portability, when they were really about design and intent of Http. What I should have said was this: Standalone ASIO is the reference Networking TS implementation for standardisation. Http is currently a set of extensions to Boost.ASIO specifically when it *should* be a set of extensions to the reference Networking TS implementation for C++ standardisation. This is why your current design and architecture is flawed, but luckily there isn't too much work to fix this by finishing the port of Http to the Networking TS. The Internet of Things tends to involve lots of small somewhat underpowered internet devices where C++ is likely going to play a much more important role than historically in embedded systems. The chances are that any Networking TS in C++ will be very extensively used in such IoT applications. If there were also a high quality set of extensions adding HTTP support to the Networking TS, I think your chances are good that your Http library would be seriously considered by WG21 for standardisation. *This* is why I very strongly believe that Http needs to cleave itself tightly to the Networking TS reference implementation, and not to Boost.ASIO. Moreover, if you make Http an extension of the Networking TS, you get Boost support with that for free - Http becomes dual use.
About C++03 support, it's not required for Boost acceptance, so I can add later. I want to increase tests coverage a lot before porting code to C++03, so I don't introduce accidental bugs in the process.
As a strong advocate for C++ 11 over 03 I can understand. However, IoT developers tend to be stuck on some pretty ancient toolsets for longer than others. 03 support I think would greatly increase your potential userbase.
In the case the abstractions I need enter on the C++ standard, maybe your APIbind will help me.
I actually would advise you to choose ASIO's STL abstraction machinery over my own alternative APIBind in this instance.
But I just don't find any reference to BOOST_ASIO_HAS_STD_SYSTEM_ERROR outside of config.hpp. Even if it was used, it is undocumented, which means it is an implementation detail that won't be guaranteed to be there forever (accidental behaviour versus a documented guarantee).
I'm pretty sure that implementation detail won't change in a hurry. STL abstraction machinery changes as quickly as a STL does i.e. every decade or so.
https://svn.boost.org/trac/boost/wiki/BestPracticeHandbook#a7.SAFETY:S tronglyconsideranightlyorweeklyinputfuzzautomatedtestifyourlibraryisab letoacceptuntrustedinput
That's why this first implementation uses a proven-parser that is very well tested.
The buck always stops with the top most layer, not internally used third party libraries. You NEED to fuzz test untrusted inputs when parsing HTTP. For all you know, your STL implementation could be the thing with the overflow bug, or the way in which you use it.
* I don't understand why you cannot issue more than one async read at a time nor async write at a time. In something like pipelined HTTP that seems like a very common pattern. I smell a potential design flaw, and while the docs mention a "queue_socket" I can't see such a thing in the reference section.
Too much synchronization and buffering.
The pipeline has the following requests:
A => B => C
If I were to allow replies to request B, the design would be more complex, increasing the difficult to implement alternative backends and everyone's life. Also, the reply to request B cannot actually be sent while the reply to request A is on hold. This means that the whole response to request B would need buffering and if response B is a video live stream, this means an implicit (the user cannot know) crash after an unfortunate memory exhaustion. I couldn't claim a **lightweight** server if this excessive buffering was to occur. I couldn't claim the project is appropriate for embedded devices if I had chosen the buffering approach. It's a trade-off. I should write about it in the "design choice" of the documentation.
HTTP/2.0 does have proper multiplexing and it can be more useful to respond several requests without "head of line blocking".
Ok, let's accept that HTTP before 2.0 can't multiplex (not my experience personally, but I agree it's got big gotchas before 2.0). You need a user facing API for Http which lets user code multiplex where that is available, and not multiplex when that is not available. In other words, identical code written against Http must automatically be optimal in either connection case. You're probably going to ask how I might implement that right? I think my first guess is you need two completion handler layers and therefore two completion dispatcher reactors: the bottom layer is the same as ASIO's and uses the ASIO reactor, whilst the top layer which users of Http sees is a reactor operated by Http and is disconnected, though operated by, the ASIO reactor.
A queue socket is a concept, I don't provide one. I can look into how make the documentation less confusing by adding a page exclusively dedicated to explain the problem it solves. Would that work for you?
It could be this queue socket concept of yours is exactly what I just proposed as two completion handler and reactor layers. In either case, I don't think queue sockets should be a concept, I think they need to be the core of your library's user facing API. If power users wish to bypass that user facing API layer for less hand holding and less latency, that should also be possible. But I think HTTP multiplexing should be assumed to be the default starting point for Http applications. Once HTTP 2.0 is more common, it will seem madness that Http's user facing API is _not_ 100% multiplexing.
* Your tutorial examples use "using namespace std;" at global level.
That's a showstopper of bad practice, and you need to purge all of those. Same for "using namespace boost;" at global level.
The tutorials should be as small as possible to not scary the users.
But I can put a comment "you should avoid using namespace". Does it help?
using namespace is fine at local scope. It's not fine at global scope. Replacing all global using namespace with local using namespace is all you need to do.
* Your reference section is one very long thin list. You might want
to use more horizontal space.
I'd be happy already if I knew hot to remove the TOC from the reference page. It'd be much more clean already.
Personally in AFIO I hack the CSS to make the list into columns. ASIO employs a table. There are many solutions.
* I personally found the design rationale not useful. I specifically
want to know:
1. Why did Http choose ASIO as my base over leading competitor X and Y? 2. What sacrifices occurred due to that choice? i.e. things I'd love weren't the case.
I assume I don't need to reply these questions during the review, given the reviewers may already be experienced on the answers.
Well ... I'm not sure that's actually the case. It's not we don't have opinions on the answers, it's whether our answers are different to your answers. You'll see this during the AFIO review later this month - I have some really weird opinions no one else shares like choosing my own custom lightweight monadic future-promise implementation over async_result. That will be the source of much criticism I'm sure.
3. What alternatives may be better suited for the user examining
Http for suitability and why? i.e. make your documentation useful to people with a problem to solve, not just a howto manual.
I don't quite understand this point.
What I'm really asking is for details of when before starting Http you reviewed the options available and the designs they used, and exactly why you chose the design choices in Http you did with reference and comparision to prior art. Like a literature review, but for programming libraries. Does this make sense? It's partially for us to help us understand your choices, but also to help those examining Http to see if it's useful to them to figure out the best solution to their problem (which may be to use an alternative to Http). Documentation which is useful over documentation which is reference.
* Benchmarks, especially latency ones which are important for many
uses of HTTP are missing. I'd particularly like to know confidence intervals on the statistical distribution so I know worst case outcomes.
These values will change when I replace the parser used now. Also, they can change based on the buffer sizes and parser options, which the user is/will be able to change.
Nevertheless, I do want to do some serious benchmarking, specially because it'll give me a reference point when I write my own parser and want to compare performance speedup. I can do some poor benchmark this weekend and show the results.
That would be interesting, but don't go crazy on it. Also, please do enable the undefined behaviour sanitiser permanently including in release mode and with full stack smashing protection before running benchmarks. Anything parsing malicious input should have all those turned on where available.
I hope all the above isn't too disheartening Vinícius.
Not at all. I think you're the second person to dedicate more time reviewing my work and this isn't disheartening at all. Just that your feedback is usually around tooling and not the design itself (everybody has its preferences).
That's because I like the design a lot and have little bad to say about it. I've also been subscribed to your github since the beginning, and I have been reviewing your code on and off as you wrote it. You're a talented programmer.
Jamfile for the main library build,
Consider this done. I won't integrate into Boost without removing CMake first. This was already partially stated in the Bjorn's announcement (but somehow implicit, to be fair).
I have no problem at all with dual build systems if you're happy keeping both maintained. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
2015-08-08 11:00 GMT-03:00 Niall Douglas
As a strong advocate for C++ 11 over 03 I can understand. However, IoT developers tend to be stuck on some pretty ancient toolsets for longer than others. 03 support I think would greatly increase your potential userbase.
I do care about C++03. That's why it's on the roadmap. But the design wouldn't change noticeably and that's why I believe Boost.Http is ready for review. Some of the requirements you're complaining about aren't Boost requirements. Boost.Http isn't perfect now (and it'll take maybe a few years before I exhaust my plans for improvements), but it has a strong core that is already useful by itself. Lots of Boost libraries continued to improve with time. It's not like you only do bugfixing after a library is accepted. The buck always stops with the top most layer, not internally used
third party libraries.
You NEED to fuzz test untrusted inputs when parsing HTTP. For all you know, your STL implementation could be the thing with the overflow bug, or the way in which you use it.
I opened an issue, so I won't forget about it: https://github.com/BoostGSoC14/boost.http/issues/12 Ok, let's accept that HTTP before 2.0 can't multiplex (not my
experience personally, but I agree it's got big gotchas before 2.0).
You need a user facing API for Http which lets user code multiplex where that is available, and not multiplex when that is not available. In other words, identical code written against Http must automatically be optimal in either connection case.
Current design already supports concurrent requests. Each socket is a communication channel with your application and every time you can handle another request, you open a new socket where you'll do it. That's my plan for HTTP 2.0. The advantage is that you don't need to associate any id with every message (that's more lightweight and more portable against different HTTP backends). It could be this queue socket concept of yours is exactly what I just
proposed as two completion handler and reactor layers. In either case, I don't think queue sockets should be a concept, I think they need to be the core of your library's user facing API.
And then you aren't following C++ rule number #1 anymore: You only pay for
what you use. That's why Asio itself doesn't solve this problem for you.
You can use boost::http::basic_socket
3. What alternatives may be better suited for the user examining
Http for suitability and why? i.e. make your documentation useful to people with a problem to solve, not just a howto manual.
I don't quite understand this point.
What I'm really asking is for details of when before starting Http you reviewed the options available and the designs they used, and exactly why you chose the design choices in Http you did with reference and comparision to prior art.
Like a literature review, but for programming libraries. Does this make sense? It's partially for us to help us understand your choices, but also to help those examining Http to see if it's useful to them to figure out the best solution to their problem (which may be to use an alternative to Http).
Documentation which is useful over documentation which is reference.
I see. That's the entire point on the "design choices" chapter: https://boostgsoc14.github.io/boost.http/design_choices.html Of course I can always improve this chapter by explaining more and more. This review is helping me gather more questions to answer, but I'm already answering here. So you guys can just ask. -- Vinícius dos Santos Oliveira https://about.me/vinipsmaker
On 8 Aug 2015 at 13:48, Vinícius dos Santos Oliveira wrote:
But the design wouldn't change noticeably and that's why I believe Boost.Http is ready for review. Some of the requirements you're complaining about aren't Boost requirements. Boost.Http isn't perfect now (and it'll take maybe a few years before I exhaust my plans for improvements), but it has a strong core that is already useful by itself. Lots of Boost libraries continued to improve with time. It's not like you only do bugfixing after a library is accepted.
All of this is true. And I am mindful I am complaining about a design choice which is specifically that you are targeting Boost before WG21. However a Boost library is about intent and purpose and philosophy as well as technical architecture and implementation. I personally believe "Boost-ness" can mean a library should not be part of Boost which is self-contradictory I know. I appreciate that cleaving more closely to the Networking TS instead of Boost.ASIO may seem like an internal implementation detail, not a design detail. But it ticks the intent and purpose and philosophy boxes for me and right now you're not ticking them. Plus, as I mentioned, you get "free" Boost compatibility via the ASIO to Boost.ASIO conversion scripts. Where I'm really at is I think if Http is accepted you're going to either have to ditch it and reimplement atop the Networking TS as Chris folds the substantial changes WG21 will force onto ASIO into Boost.ASIO, or end up refactoring Http to cleave more closely to the Networking TS anyway. I am therefore of the position it's more efficient to skip that and just cleave right now to the Networking TS.
The buck always stops with the top most layer, not internally used
third party libraries.
You NEED to fuzz test untrusted inputs when parsing HTTP. For all you know, your STL implementation could be the thing with the overflow bug, or the way in which you use it.
I opened an issue, so I won't forget about it: https://github.com/BoostGSoC14/boost.http/issues/12
Thanks for that.
It could be this queue socket concept of yours is exactly what I just proposed as two completion handler and reactor layers. In either case, I don't think queue sockets should be a concept, I think they need to be the core of your library's user facing API.
And then you aren't following C++ rule number #1 anymore: You only pay for what you use. That's why Asio itself doesn't solve this problem for you. You can use boost::http::basic_socket
if you need to work around Asio composed operations at this level. All customization points are there for anyone.
I am finding myself unconvinced by your arguments here. What stands in the way of a two layer API design? Bottom layer is racy but lowest latency. Top layer is not racy, but adds some latency. I think for the majority of HTTP users they just want it to work without surprises to a high default performance level. If you look at the history of the HTTP library support in Python you'll see what I mean - firstly, it's surprisingly easy to get a HTTP library API design wrong, even in a v2 refactor. And secondly that people need both a stupid-simple API and a more bare metal API *simultaneously* with HTTP, and therein lies the design gotcha. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
First of all, sorry to all members of the list about my unavailability. I
was planing to write an experimental HTTP 2.0 backend, so I could give more
confidence about how much I believe this Boost.Http core I present for
review is the right abstraction.
Anyway, looks like I took the wrong approach. I should have answered the
easiest questions first and implement the HTTP 2.0 backend (experimental,
using existing-library and not Boost-quality) later.
2015-08-11 14:35 GMT-03:00 Niall Douglas
Where I'm really at is I think if Http is accepted you're going to either have to ditch it and reimplement atop the Networking TS as Chris folds the substantial changes WG21 will force onto ASIO into Boost.ASIO, or end up refactoring Http to cleave more closely to the Networking TS anyway.
I'm okay with that.
And then you aren't following C++ rule number #1 anymore: You only pay for
what you use. That's why Asio itself doesn't solve this problem for you. You can use boost::http::basic_socket
if you need to work around Asio composed operations at this level. All customization points are there for anyone. I am finding myself unconvinced by your arguments here. What stands in the way of a two layer API design? Bottom layer is racy but lowest latency. Top layer is not racy, but adds some latency.
I think for the majority of HTTP users they just want it to work without surprises to a high default performance level. If you look at the history of the HTTP library support in Python you'll see what I mean - firstly, it's surprisingly easy to get a HTTP library API design wrong, even in a v2 refactor. And secondly that people need both a stupid-simple API and a more bare metal API *simultaneously* with HTTP, and therein lies the design gotcha.
If you want a high level API, you're going to use coroutines. There is nothing in the wild so readable as coroutines. Coroutines are **the** solution to solve spaghetti code in asynchronous abstractions. Lambdas and futures will never be as readable as coroutines. Anyway... If you want a high-level API, you're going to use coroutines and the use of coroutines will already suspend your code until the completion of the previous operation. You end up not scheduling too many operations at once (less resources consumed) and you are using the API the right way. If you want to not use coroutines and still have a somehow high-level API, just change the underlying socket. It's not a problem. The only problem I see here is the lack of a page just documenting composed operations given the confusion that arose on this matter. Really, you should NOT pay for what you do NOT use. Eventually we'll have coroutines in the language, so you will be unable to even something more efficient and will end up just using coroutines. And with the design I propose, you won't even pay for scheduling/storing multiple operations that just cannot be used right now. If the "pay for what I don't use" design was what Boost wanted, I believe Boost.Asio would do different (fair enough that Boost.Asio is a low-level library). Now, about a real high-level API. Boost.Http is somewhat low-level, but not because the reasons given. I can provide a higher-level API and it won't change the points you're against. If you see the Boost.Http roadmap, you'll notice where Boost.Http is really low-level (lack of requests router, form parsing, HTTP session management...). This kind of stuff can go hugely polemic and I think it's very unwisely to integrate it all at once. You'd be like comparing frameworks that are completely different (like Python's Django or Flask) and asking "hey, what is the **right** choice?". This kind of question is really unhelpful. These frameworks continue to evolve and sometimes they break API or even completely new approaches arise (like the recent rise of popularity in web microframeworks). I'd rather provide really generic and flexible building blocks than state that my view of web development is correct. Not too long ago, LAMP was a very popular solution, and this solution assumed you would use MySql database, but sometimes you do not even need a database. You should check the answer for "Why isn't a router available?" on the Boost.Http FAQ: https://boostgsoc14.github.io/boost.http/design_choices.html It's very polemic and I need to develop a NEW approach, not import the design from some place or another. I need to reconcile current approaches (I'd like to use the word paradigm here). Not only reconcile them, but I need to allow some kind of collaboration. And it's C++, it's harder. It's not harder because it's C++. It's harder because the C++ community takes software development very seriously. And then, it's not just C++, it's Boost, the small group from C++ that is know among the community as the group who strives to deliver even higher quality software. If we stick for what we need for now, I believe the correct question to focus on is "If I need to communicate HTTP messages, what is the correct approach?". It's what we need now, pass HTTP messages around. And then, the HTTP protocol may not even be involved, that's why I focused so much on allow alternative HTTP backends. Extremely detailed and careful requirements like the ones written for Message[1] and ServerSocket[2] is not something you'll see anyone doing. And it takes a lot of care because you need to be careful who you're excluding. I choose to not exclude HTTP 1.0 and I've put HTTP upgrade and HTTP chunking as optional features that the user must check. I also choose to not exclude alternative backends. I also choose to allow **lightweight** implementations, so embedded devices would be left out. cpp-netlib and pion have their own thread pools and aren't very friendly to embedded devices. I also go fully async, allowing really really fine-grained control by the user. Even trying to be so ambitious, I'd not say that the design went so low-level that becomes unusable, as the spawn example proves[3] (163 lines and a good part is because Boost.Asio boilerplate, not Boost.Http). I have some experience with HTTP libraries (one of the most important being the Tufão project[4]) and I acquired experience. This experience I have is what makes me capable of judging some design decisions that can be a mistake. Not considering alternative HTTP backends from the beginning being one of them. Other mistakes being less obvious. The Node.js API is really trick (implicit decision on whether use chunking or not) to get right if you're concerned with portability among applications (there is an old and fixed Tufão bug related to just this[5]). The hush to get high-level APIs can also become a problem because you can very very easily lose the possibility to do fine-grained adjustments. First you're fine with single-threaded, and then you want the handling being split into threads. Then you want not split the responsibility to split the connections among threads, but each pair of request-response with a scheduler that is clever than round-robin[6]. Eventually you'll end up losing the interoperability and having to rewrite large parts of the application. I'm very concerned about interoperability, that's why I mentioned it in the very initial GSoC proposal last year, along the following lines: "In fact, there is a lot of higher-level abstractions competing with each
other, providing mostly incompatible abstractions. By not targeting this field, this library can actually become a new base for all these higher-level abstractions and allow greater interoperability among them." -- https://github.com/vinipsmaker/gsoc2014-boost#non-goals
The more I think, the more I believe how much such "middle-level" API is underestimated. I mentioned at random places how much I appreciate the message-oriented approach I'm using. Now I think I should have dedicated a whole chapter on the topic. If it weren't for this message-oriented approach, the design would be much more complex. It'd be like trying to solve problems of a high-level API (set_timeout, set_scheduler, set_handler_factory, set_allocator, set_pool, set_feature_xyz) at this level already and thinking really hard to not miss **ANY** feature that the user could possibly want to customize. The message-oriented approach has a single-first-immediate impact: Communication channels and message representations are decoupled. Without this simple separation, you do not need to complicate communication channels so much. And you also gain the ability to use your own allocators, pools, data structures, non-allocating buffers and so on. I've read some messages about people concerned that the API is too level and even still will allocate sometimes. All the examples I've written allocate and the reason is that all the examples I wrote don't have a bounded limit of HTTP connections (there isn't a single big chunk of stack-allocated pool/buffer/...). A new "handler" will be created as a new connection appears. But if you put a limit, implement your own data structures and read the documentation (it doesn't even need to be an extremely careful read), you're done. There are some gritty decisions on implementation details that made me allocate at some spots (use of functors, lack of dynarray...), but then I should discuss the implementation and not mix with API design (unless you propose an interface to specify allocators). It's not really like Boost.Http is too low level. It's more like only the less polemic building blocks are available now. You'll see the same main players in a higher-level abstraction and the main difference is most likely that you won't manage the main players yourself. And advocate for a Boost.Http instead a Boost.NetExtensions because I allow alternative backends. Asio will always be involved because the pure async nature, but you might not even use network and use an alternative backend that communicate using shared memory and other means. There are many more thoughts, but I think I'm diverging too much from Niall's concern, so I'll stop here and answer the rest of the questions. If you guys have any question to specific points, just raise them. [1] https://boostgsoc14.github.io/boost.http/reference/message_concept.html [2] https://boostgsoc14.github.io/boost.http/reference/server_socket_concept.htm... [3] https://github.com/BoostGSoC14/boost.http/blob/0fc8dd7a594bb5ebb676d2d55621a... [4] https://github.com/vinipsmaker/tufao [5] https://github.com/vinipsmaker/tufao/issues/41 [6] https://en.wikipedia.org/wiki/Round-robin_scheduling -- Vinícius dos Santos Oliveira https://about.me/vinipsmaker
What I should have said was this: Standalone ASIO is the reference Networking TS implementation for standardisation. Http is currently a set of extensions to Boost.ASIO specifically when it *should* be a set of extensions to the reference Networking TS implementation for C++ standardisation. This is why your current design and architecture is flawed, but luckily there isn't too much work to fix this by finishing the port of Http to the Networking TS.
(Q. for Niall Douglas) Does this change the public-facing API of the proposed Boost.http, or just the implementation?
* I don't understand why you cannot issue more than one async read at a time nor async write at a time. In something like pipelined HTTP that seems like a very common pattern. ...
Too much synchronization and buffering.
The pipeline has the following requests:
A => B => C
If I were to allow replies to request B, the design would be more complex,...
(Q. for Vinícius) Using the diagram at http://stackoverflow.com/q/10480122/841830, does the above mean that Boost.Http only supports the left-most diagram (e.g. a browser client cannot request image.png until it has received the entirety of index.html)? I'd share Niall's concern that moving to HTTP/2 might require API changes. In addition to the arrows shown on the rightmost diagram in the above link, HTTP/2 also supports sending back a file that has not been requested yet. And it supports one of those arrows being a WebSocket or SSE connection that continues to send data. It'd be good to see a code example of how an HTTP/2 server would work, with all these features present. (I.e. even if it won't compile yet.) Darren
On 8 Aug 2015 at 18:19, Darren Cook wrote:
What I should have said was this: Standalone ASIO is the reference Networking TS implementation for standardisation. Http is currently a set of extensions to Boost.ASIO specifically when it *should* be a set of extensions to the reference Networking TS implementation for C++ standardisation. This is why your current design and architecture is flawed, but luckily there isn't too much work to fix this by finishing the port of Http to the Networking TS.
(Q. for Niall Douglas) Does this change the public-facing API of the proposed Boost.http, or just the implementation?
A good question I considered before voicing my opinion on Http. I don't know if this is the right answer, but my best guess is that if cleaved tightly to the Networking TS, Http would appear in std::experimental alongside Networking when a standalone build and standalone ASIO is configured to be the Networking TS library. If standalone build but standalone ASIO is just merely ASIO, Http would appear in namespace ::asio::http. Finally, if part of Boost, Http would appear in namespace ::boost::http, not ::boost::asio::http. There are of course pros and cons to these namespace choices, and I'm not strongly decided on any of the options. But I think the key point is that Http would need to be written to not surprise the end user in all three configurations, and that would require exceptional care in the API design and implementation, not least in the use case where someone combines all three configurations of Http in the same translation unit. I have a bit of experience in getting library APIs to appear at multiple namespace mount points thanks to APIBind, and I'll confess I still get occasional CI failures where I accidentally collide a symbol in a breaking way due to an unenforced programming error. ABI cleanliness is a pain. I suspect, you see, that the easiest by far namespacing is always within the asio/networking namespace. And that's a big API change over what's proposed. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
2015-08-08 14:19 GMT-03:00 Darren Cook
(Q. for Vinícius) Using the diagram at http://stackoverflow.com/q/10480122/841830, does the above mean that Boost.Http only supports the left-most diagram (e.g. a browser client cannot request image.png until it has received the entirety of index.html)?
The browser can issue all requests at once, but thanks to HTTP 1.1 head of line blocking, it'll only get the response to the second request once the response to the first request has being generated. At least you decrease the latency. -- Vinícius dos Santos Oliveira https://about.me/vinipsmaker
participants (3)
-
Darren Cook
-
Niall Douglas
-
Vinícius dos Santos Oliveira