Bug? Getting parameter and receiving data on post

699 views
Skip to first unread message

Paulo Leonardo

unread,
Aug 15, 2014, 1:15:08 PM8/15/14
to cive...@googlegroups.com
Hello!

I was trying to read a parameter from a request (using CivetServer:getParam) and read data (json) from the request.
However i realised that i cannot do the two things on the same request.
I believe that this is some kind of bug.

I wrote this code to illustrate the problem:

bool handlePost(CivetServer *server, struct mg_connection *conn){
        string param;
        //get Parameter
        CivetServer::getParam(conn, "someParam", param);

        char post_data[1024];
        int post_data_len;
 
        // Read data
        post_data_len = mg_read(conn, post_data, sizeof(post_data));

        // Send reply to the client
        mg_printf(conn, "HTTP/1.0 200 OK\r\n"
                "Content-Type: text/plain\r\n\r\n"
                "Param: [%s]\n"
                "Post Data: %s\n", param.c_str(), post_data);

        return true;
    }

Using 'curl' i did these tests (commands in bold):

$ curl 10.9.99.96:8081/test?someParam=something -d ''
Param: [something]
Post Data:

$ curl 10.9.99.96:8081/test?someParam=something -d 'data'
Param: []
Post Data:

$ curl 10.9.99.96:8081/test -d 'data'
Param: []
Post Data:

$ curl 10.9.99.96:8081/test -d 'someParam=something'
Param: [something]
Post Data:

$ curl 10.9.99.96:8081/test -d 'someParam=something' -d 'otherParam=anything'
Param: [something]
Post Data:

As you can see, the data from the request is never read. And the parameter from query ('?someParam=something') is only read when there is no data on the request.

I hope this helps.

Paulo Leonardo

bel

unread,
Aug 15, 2014, 4:27:42 PM8/15/14
to cive...@googlegroups.com
CivetServer::getParam is explicitly designed to read the parameters of a HTML form.
A form may look like this (http://www.w3schools.com/html/html_forms.asp):
<form name="input" action="demo_form_action.asp" method="get">
Username: <input type="text" name="user">
<input type="submit" value="Submit">
</form>

If you enter "abcd" in the field, the submit button will lead to a GET request to http://www.w3schools.com/html/demo_form_action.asp?user=abcd
The GET request does not have body data, so mg_read will not return any data.
CivetServer::getParam(conn, "user", param) will give you param=="abcd"

Alternatively, you could use method="post" in the form definition above. In this case, the submit button will lead to a POST request to http://www.w3schools.com/html/demo_form_action.asp (without ?user=abcd), but the extra header field "Content-Length: 9" and 9 bytes body data user=abcd.
However CivetServer::getParam(conn, "user", param) will give you param=="abcd" again.

Calling CiverServer::getParam will consume all the body data, so your subsequent call to mg_read will not get anything anymore.

I do not use curl myself, so I am not sure what curl does. How does curl decide whether GET or POST is used?
Everything above is valid for browsers that implement forms, and CivetServer::getParam(conn, ...) is adapted to exactly this use case.
In every other case, you should use mg_read to read the body data and mg_get_request_info(conn)->query_string to get the ?user=abcd from the url - there are never both in a HTML form.
You can use CivetServer::getParam(const char *data, size_t data_len, ...), based on the data not the connection, to split the arguments later.


bel

unread,
Aug 15, 2014, 6:18:25 PM8/15/14
to cive...@googlegroups.com


On Friday, August 15, 2014 7:15:08 PM UTC+2, Paulo Leonardo wrote:
Hello!

I was trying to read a parameter from a request (using CivetServer:getParam) and read data (json) from the request.
However i realised that i cannot do the two things on the same request


You can do that in the following way (untested):
    struct mg_request_info *ri = mg_get_request_info(conn);
    assert(ri != NULL);
    getParam(ri->query_string, strlen(ri->query_string), "someParam", someParamValue, 0);
    getParam(ri->query_string, strlen(ri->query_string), "otherParam", otherParamValue, 0);
    const char * con_len_str = mg_get_header(conn, "Content-Length");
    int con_len = atoi(con_len_str);
    assert(con_len>=0);
    post_data = new char[con_len+1];
    bytes_read = mg_read(conn, post_data, con_len);
    post_data[bytes_read+1]=0;
    JSON jsondata(post_data);

Paulo Leonardo

unread,
Aug 15, 2014, 7:08:18 PM8/15/14
to cive...@googlegroups.com
Thanks for the reply! ^^
And sorry for the false alarm.

I didn't know that CivetServer::getParam(conn, ...)
is specific to handle webforms.
May be useful to distinguish (at least on documentation) how to get parameters from query and from forms.

By the way, on this example that you posted. This 'JSON' object is from what library? Because i am looking for one.

Thanks!

Paulo



--
Sourceforge
https://sourceforge.net/projects/civetweb/
---
You received this message because you are subscribed to the Google Groups "civetweb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to civetweb+u...@googlegroups.com.
To post to this group, send email to cive...@googlegroups.com.
Visit this group at http://groups.google.com/group/civetweb.
To view this discussion on the web visit https://groups.google.com/d/msgid/civetweb/f4dd3be6-369f-4204-a384-fa6531aba47a%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

bel

unread,
Aug 15, 2014, 7:33:17 PM8/15/14
to cive...@googlegroups.com


On Saturday, August 16, 2014 1:08:18 AM UTC+2, Paulo Leonardo wrote:
I didn't know that CivetServer::getParam(conn, ...)
is specific to handle webforms.
May be useful to distinguish (at least on documentation) how to get parameters from query and from forms.

It's not obvious from the function name (I did not choose it) - "getHTMLFormParams" would be better.
However, I already added a few comment lines to the *.h file.



On Saturday, August 16, 2014 1:08:18 AM UTC+2, Paulo Leonardo wrote:
By the way, on this example that you posted. This 'JSON' object is from what library? Because i am looking for one.

This was just an example. I usually parse JSON objects in Lua - Lua is much better in string processing than C.
There are quite some libraries for C++: http://stackoverflow.com/questions/245973/whats-the-best-c-json-parser
There is a C++ JSON library from sunsetbrew, who is working on Civetweb as well (https://github.com/sunsetbrew/jsonhandle) - maybe he can give you more infos on this, and maybe he already used it together with Civetweb.
I always use a Lua state as an additional layer between web requests and C data or C++ objects, so I can just use get/set methods to access C++ object data and do all the communication encoding/decoding in Lua. Thus, I can change the web protocol without changing the C/C++ code. However, this would be more than just a one line example.

Reply all
Reply to author
Forward
0 new messages