From: Dean M. C. B. <dmb...@fr...> - 2008-03-26 09:56:04
|
> -----Original Message----- > From: cpp...@li... > [mailto:cpp...@li...] On > Behalf Of Darren Garvey > Sent: Wednesday, March 26, 2008 4:12 AM > To: C++ Networking Library Developers Mailing List > Subject: Re: [cpp-netlib-devel] Boost.CGI Merger (WAS RE: > Nearly time tostart merging?) > > > > On 25/03/2008, Dean Michael C. Berris <dmb...@fr...> wrote: > > > > -----Original Message----- > > From: cpp...@li... > > [mailto:cpp...@li...] On > > Behalf Of Darren Garvey > > > > > Perhaps we can open discussion about where things should and > > shouldn't align and how best to do that? It'll be summer > > before I have any real time to spend on this, but I'm really > > keen that we can make some progress on this. > > > > Like Glyn, I'll try looking into the code. However, I > may very well be > concentrating more in helping out Mike with the integration of > pion-net's HTTP code into the library. It would be a > dream come true if > somehow the HTTP message code we're developing will be > the same one the > CGI library will be using! :) > > > This is the code in (SVN_ROOT)/branches/http_integration/ ? > I've had a brief look at it a couple of times, it has great > potential. I think the first steps towards integration of the > CGI library is to start using the basic_message<> class, > which I think should be pretty straight-forward. > Great! :) > > > > P.S. > > > > Ideas: > > * add a form_parser class (as part of the public API) > > - use Boost.Spirit > > - should read/parse multipart/form-data regardless > of request type. > > - should allow incremental reading/parsing of > individual form parts > > I like this. :) > > We can even do this using the TDD approach where we can > write the unit > test(s) independent of any subsystem, and develop the > parser(s) to > implement to make the unit tests pass. This way, the > compliance to > parsing multipart/form-data can be developed independently. > > > Exactly! All this requires is using Boost.Asio's > (A)Sync(Read|Write)Stream concepts, so shouldn't require too > much isolated code. > Sounds like a plan to me. :) > > > > * add a param class > > - holds a boost::iterator_range to the data > > - convertible to std::string subject to a macro condition > > (aka. taint mode) > > - allows easy case-insensitive comparison (possibly using > > Boost.String_algo? Or the netlib transform meta-functions?) > > - allows compile-time checking of its source (eg. > > env/GET/POST) to protect against XSS vulnerabilities. > > - allows easy lexical casting (eg. param::as<>) > > > > I don't really understand what you mean by this, but if > you mean 'param' > in the query string parameter case, then this may be a > good idea. I > don't see though if using Boost.Any might make more > sense for some > people who want the dynamic-ness (if there's such a > thing) of the value. > > > I was referring to a possible container for any/all parsed > request data. The idea is that data can be read directly into > a basic_message<> and when it's parsed, the name/values of > each 'request variable' is stored in a container that just > *points* to the data, without copying it. > > The `param` (or `basic_param<>`) class would be little more > than a cheap-to-copy drop-in replacement for std::string that > supplied minimal networking-related member functions (eg. a > case-insensitive operator==() and nested typedefs like ::source_type). > > I just wrote a load about how it might work, but it might be > better if I threw together an implementation, rather than > rambling on about what it could do! > Sounds like a good plan to me too. :) I'm not really sure if copying strings is really too inefficient compared to using iterator pairs. Although this may be 'premature optimization', it would be good to have at some point I guess. > [snip] > > > I wasn't too sure about the as<> member function myself > either, but several people requested it and the idea already > has precedence in boost libraries, although I forget which > ones right now. Perhaps it would be better to have an > 'as<>-less' network::basic_param<> and then a > cgi::basic_param<> which derives from the former and adds the > as<> member function..? > > What do you think? * > I'd first like to see a use case for the basic_param<> idea -- as far as I see it in my head, a parameter is just a string. Although a string can be referred to with just a pair of iterators marking the beginning and the 'past end' position of a string of characters, I may need some convincing for the creation of a specialized type for iterator ranges. Wouldn't a Boost.Range work with boost::lexical_cast<...>(...) ? > > > > * add prepare/consume/commit member functions to > > network::basic_message<> > > - functions like in asio::streambuf. > > - would allow reading data straight from a > > (asio)(A)SyncReadStream (eg. a socket), without need > for buffering > > - could help with incremental parsing and/or making > > form_parser class request-agnostic > > > > My suggestion instead of overloading the interface of > basic_message<> is > to define adaptors. > > > Ahh, interesting... > > > > It should be feasible to have a > 'streamed<basic_message<> >' or 'async<basic_message<> > >' instance which > would decorate the functionality of the basic_message > encapsulated > within the instance. That way it can still be converted > into and is > still interface compatible to basic_message<>, but adds > functionality > that's typically not inherent in the actual message. > > > ... and supplies reusable components too. :) > > > > streamed<basic_message<http::message_tag> > streamed_message; > std::string body_line; > getline(body(body_stream), body_line); // synchronously > wait for the > first body line to be streamed > > async<basic_message<http::message_tag> > async_message; > future<std::string> body_line = body(async_message); > // at some point in time > cout << body_line.get(); > > This keeps the basic_message<> interface intact and the > usage semantics > consistent. What do you think? :D > > > This sounds like a good idea. For a readable basic_message<> > - ie. with the only addition being member functions > prepare/commit/consume - how about storage<basic_message<>> ? > This would allow direct reading/writing to/from the message with Asio. > I'm not very familiar with the idea of 'storage<basic_message<> >', can you elaborate on that? > > > > P.P.S. > > > > The basic_message<> class has embedded _source/_destination > > parameters. These aren't particularly relevant to > > CGI/FastCGI/SCGI and they imply a close relation between the > > payload of an HTTP message and its source/destination, which > > might not always be a 1:1 relationship. I wonder if they > > should be moved out of the basic_message<> class to some > > higher-level abstraction? > > This may be a good idea, but it's possible to actually > use SFINAE or a > cgi::message_tag to specialize on the basic_message<>'s internal > representation while keeping it consistent. For > example, you can disable > using SFINAE the interface to accessing (and presence of) the > _source/_destination parameters. > > > Yeah, this is possible, but do you not think the > basic_message<> class should be as minimal as possible? In > the HTTP case you could possibly use something like: > > template<> > class basic_message<http::message_tag> > : basic_message<tags::default_> // this might be wrong { > std::string _source; > std::string _destination; > public: > std::string& source() const { return _source; } > std::string& destination() const { return _destination; } }; > > > We could then build up a message-type 'stack' on top of this > for the HTTP-based protocols and other 'stacks' for any other ones. > But this approach would break things because: basic_message<http::message_tag> http_message; basic_message<tags::default_> & message(http_message); message.source() = "Hello, World!"; assert(http_message.source() == message.source()); // will fail The suggestion is to do something like: template <> struct basic_message<cgi::message_tag> { ... // copy constructor template <typename Tag> basic_message(basic_message<Tag> const & other) : _source(other.source()), _destination(other.destination()), ... { }; ... }; >From within the specialization, you have the chance to do almost whatever you want with the internal implementation and external interface -- add more methods and what not -- while keeping compatibility with the interface of the basic_message. :) > > > What do you think Darren? I hope these make sense! :) > > > It all sounds very interesting. I wish I had some time to > start on it now! > Don't we all? ;) > Cheers, > Darren > > [*] From early discussion for the CGI library, some people > talked about embedded system support. They seem to prefer > very tight controls on memory allocation, so avoiding copying > might make these use-cases easier to support... > > Ah, that makes sense. Even so, parameterizing the allocator is another way to go about embedded system support. This is not one of the main concerns for designing the C++ Netlib _yet_, though if there's enough user demand for it and enough interest in making your phone/watch/stereo/tv/switch/router have an HTTP cilent/server, then that should be doable as well. :D -- Dean Michael Berris Software Engineer, Friendster, Inc. <dmb...@fr...> +639287291459 |