Boost logo

Boost :

From: Darren Garvey (lists.drrngrvy_at_[hidden])
Date: 2007-08-19 21:07:56


Hi Phil,

On 19/08/07, Phil Endecott <spam_from_boost_dev_at_[hidden] > wrote:

> > That's because form/environment data are 'meta-variables', according to
> the
> > CGI specification.
>
> Hmm, you mean rfc3875 section 4.1 "Request Meta-Variables"?

Yep.

Most of the stuff that that section is describing really is meta-data, i.e.
> data-about-the-data; e.g. the IP address of the HTTP client and the id
> of the user. Section 4.2 describes the contents of the HTML form where
> it's called simply "request data".
>
> At least, that's the case for POST data. For GET data, it's true that
> the form data is in QUERY_STRING which the spec groups with the
> meta-data, and according to section 4.3.1 "The GET method indicates
> that the script should produce a document based on the meta-variable
> values." But you're hiding the difference between GET and POST form
> data, and I suggest that you apply common sense rather than just
> copying the spec: call the meta-data meta-data, and call the data data.

What you say makes perfect sense, unfortunately... To be honest, the reason
for referring to the data as 'meta-data' is because I thought having getter
functions called 'meta_*' was the least ambiguous way to do it (and
obviously I thought the term was accurate). The 'get' and 'post' keywords
seem to make most alternatives sound like they're doing something they're
not.

The previous iteration used:

var<GET>()
var<POST>()
...

The change of heart came because that gets very ugly when you need to use
qualified names. Still, if calling them all meta_* is plain wrong, then it
has to change.

- I think it's important, especially for a Boost library, that you
> supply standard-library-like interfaces where possible. For example, I
> would like to see the form variables having a std::map-like interface.
> (This would be most easily achieved by actually making them a std::map,
> but if you choose some other implementation structure then you can use
> Boost.Iterator to help with the interface). This would allow me to
> iterate through them. At present, I don't think you have a way to get
> the names of all the form variables.

Oops, forgot to document this! There is a way to do this actually:

cgi::request req;
cgi::map& form_map = req.meta_form();

cgi::map is a typedef for map<string,string> for now, but this should
probably be a multimap. I've made a note about where this might be heading
in the 'future development' section of the docs (linked from the first
page). Note that this can't currently be used for environment variables:
this will probably change, but with the warning that it's going to be much
slower for standard CGI.

> - I don't see a way to use the form data parsers independently. For
> example, if I write my own code for an Apache module or a stand-alone
> HTTP server, I would like to be able to invoke your parser to decipher
> the urlencoded or multipart/form-data from a string that I supply. You
> could provide this as an independent header file.
>
Currently it's an implementation detail. It would be nice to make this
visible to library users, but I'm not sure what we're using now is generic
enough to make that sensible. We'll see, I suppose. :)

> - In the '10 minute intro', you have:
> std::string user_name( req.meta_cookie("user_name") );
> if (!user_name.empty()) { ....
> So is it impossible to distinguish between an empty string and a form
> or cookie value not being set?
>
Not really... I was thinking about this earlier and it could be done easily
enough (I won't go into it, if you don't mind), but it would be a bit ugly,
say something like:

std::string name( req.meta_get("name") );
if (req.is_unset(name))
  // var was not set

There are a couple of other possibilities, one of which is to use a
`cgi::param` instead of `std::string`s. Then you could do:

cgi::param& name = req.meta_form("name");
if (name.empty()) // `name` contains no data
  if (name.unset()) // "name" is not a form variable

Another option is to set the error_code value to something like error::unset
in the case where the error-checked version of meta_* is used:

boost::system::error_code ec;
std::string name( req.meta_post("name", ec) );
if (name.empty()) // `name` contains no data
  if (ec ==error::unset) // "name" is not a POST variable

Thoughts?

> - I'm not sure about the idea of sending the response to the request
> object. I would think of the request object as a const thing. When I see
> req << "something..."
> I thing that that's something that should only happen when the
> request object is being created e.g. to set the POST data. In my apps
> I have always had a handler function that returns a response:
> HTTP::Response handle ( const HTTP::Request& req ) { ... }
> but this doesn't fit as well into your arrangement.
>
I'm not sure I follow. The request object doesn't support operator<<. You
write to a request by using something like:

cgi::request req;
std::string response("Content-type: text/plain\r\n\r\nHello");
// variation 1
cgi::write(req, cgi::buffer(response));
// variation 2
cgi::async_write(req, cgi::buffer(response));
// variation 3
cgi::reply rep;
rep<< response;
rep.send(req);

Perhaps the docs are misleading?

> Perhaps you need
> a "Message" object to contain a request and the corresponding
> response? ("Message" is the RFC2616 term for a request/response pair.)
>
As it develops, it seems more sensible to drop the 'reply' object entirely
and provide a single iostream interface on top of the request, much like
there is an iostream above a tcp::socket in Boost.Asio: That design has been
approved by boost members already and seems to work quite nicely.

> - The term "Response" is normally used rather than "Reply" (e.g. in the
> HTTP spec).
>
Noted, thanks.

> - For multipart/form-data, each form variable has some associated
> metadata; e.g. for a file upload, the filename and possibly the mime
> type are supplied by the browser, and the charset may be indicated for
> other variables. I don't see any way to get at this.
>
That's because there isn't. ;) You can expect this to be available
eventually.

Thanks for the pointers,
Darren


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk