
Hi list, I've been designing a HTTP library for Boost inclusion for the last two years. First it was funded as a GSoC 2014 project. Then I continued to polish the implemented bits on my own and the library was peer reviewed (and rejected) last year. I'm currently addressing the requests made during last year's review and one of the requested items was a higher-level interface built on top the current building blocks that would be easier to use. One of such abstractions would be an HTTP request router. I usually do my research and check what others have done (not only in C++), read a lot of spec and do a design on my own (sometimes I ask for feedback of a few chosen ones). I rarely ask for public feedback because I usually can solve the interface issues on my own. However, Boost.Http is a new thing and I'm exploring an unexplored ground. I've been facing an issue for the last months and I'd like to have "open" feedback of anyone interested in this topic. Maybe it'll speed me up. The issue I'm facing is that (1) I haven't found enough diversity of HTTP request routers and (2) Boost.Http is a new thing and problems must be approached differently (what other HTTP library will let you do HTTP over uTP using Boost.Asio threading/async model?). Detailing the problem a little more: I categorize current HTTP request routers into two styles. The "tree style" is the style where you declare some paths to be handled and each request will be routed to at most one handler. You'll find this style usually when the author advertise a ReST support library (e.g.crow[1]). The "chained style" is the style where you declare a chain of <rule,handler> pairs (or anything in these lines) and one handler can "give up" and pass the route to the next in line. Rules in the "chained side" can overlap and an order exists (and must be explicit). You can find this style being used frequently in the Node.JS frameworks (e.g. connectjs[2]). You could reimplement these NodeJS APIs in C++ keeping a lot of the same look'n'feel. For instance, take a look at node.native[3]. I thought I could combine and allow both styles. Actually, Boost.Http don't force you to use any style and both could be used. However I wanted to implement both allowing some kind of interoperability and communication between them. There are a lot of open questions right now and I decided to implement both individually and only then come back trying to unify them. So, for now, my problem is designing the "chained style". Even implementing only "one style" I had open questions and I decided to draft an implementation to maybe give some light to my own mind. One thing that I was trying to address would be the "next" function. If you take a look at the connectjs library[2], you'll see that the "next" function is an argument passed to the handler and, if the handler wants to give up and pass the route to the next handler, it only needs to call "next". This behaviour could be emulated in C++ using std::function<>. An alternative design would be to make the handler return a bool. This is actually the design I've chose in Tufão[4] and I regret this decision to this date. The bad thing about this approach is the too-much-sync minded. If you need to communicate with a database to know whether you'll be able to handle the route then you need to block the whole thread under this approach. Knowing this is Boost and Boost is about serious C++ users I know I must be concerned about performance. Therefore, many may not like the std::function<> approach. It can imply some hidden allocation that you pay even if the handler is not going to give up on the route. Another approach would be to turn the handlers into template functors. However, this would be too much burden on the user. And if I chose this route, what would be the type of "next"? The approach I've chose was to encode the "next" function into the "request object". In Boost.Http, there is no "request object" like you'd be used to when using other APIs. Boost.Http exposes a socket and the socket will fill a message object of your choice (let's call it the input message) and later you pass it another message object to execute the reply (let's call it the output message). So the "next" function is really encoded in the input message. Other APIs use a passive style and constantly check if there is network activity and schedule new socket reads. Boost.Asio is more explicit and Boost.Http follows along. An active style is useful because it'll allow you to defer new operations to later when your server is under heavy load. Anyway, I felt that maybe I'll need a "done" function and I've added an empty one for now. I'll see if I'll really need it later when I integrate everything together. For now, just know that the "done" function does nothing. Anyway, this is my draft and I'd like to know your opinion: https://github.com/vinipsmaker/asiohttpserver/blob/router/example/router.cpp... You can see that I'm declaring a static router because most of the time you don't change the rules at runtime. This router is actually more difficult to design and it'll be easier to add a "dynamic router" later on. I also want to mention that I'm aware of another effort by another developer (Uisleandro) trying to add a router to Boost.Http: https://github.com/uisleandro/Router_for_Boost.Http I also want to mention that performance of the implementation isn't really something I care about for the draft. If it were at another place it could mean that I'm not interested in implementation feedback. However it doesn't mean that I know the best way to implement these APIs and I'm still interested in implementation feedback (even more because I don't remember if I ever implemented much TMP before). Some points that I'll tackle LATER will be: - A router is a handler too, then you can have nested routers. - The router doesn't take the rule, only the handler. Later, I'll make algorithms that adapts rules and conditionally call your handler or pass the route to the next handler. This design is more flexible and I wish I could also use it in "tree style too". - How to create Message types more easily? I've read about component-based architectures before, but I never really understood them. Is there any library that was proposed to Boost in these lines that I could take a look at? [1] https://github.com/ipkn/crow [2] https://github.com/senchalabs/connect#mount-middleware [3] https://github.com/d5/node.native [4] http://vinipsmaker.github.io/tufao/ref/1.x/class_tufao_1_1_http_server_reque... -- Vinícius dos Santos Oliveira https://vinipsmaker.github.io/