[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [libmicrohttpd] post processing question
From: |
Martin Velek |
Subject: |
Re: [libmicrohttpd] post processing question |
Date: |
Fri, 31 Aug 2012 16:02:08 +0200 |
Nice,
your advice manipulated me into moving basic auth and page check into
the first call of AccessHandlerCallback.
Thank you
Martin
On Fri, Aug 31, 2012 at 2:55 PM, Christian Grothoff
<address@hidden> wrote:
> The correct way is to send the error responds upon the very first callback
> to your handler
> (the one where "*con_cls" is usually still NULL and where 0 ==
> *upload_data_size). This will then send the error code to the client
> instead of the (otherwise auto-generated) "100 CONTINUE". As a result, HTTP
> 1.1-clients would not perform the upload. You might want to read up on "100
> CONTINUE" in HTTP for details.
>
> Happy hacking!
>
> Christian
>
>
> On 08/31/2012 02:39 PM, Martin Velek wrote:
>>
>> May I a question?
>>
>> How to correctly refuse the POST request in my situation when the url
>> file is not found? I have looked into the refuse_post_example.c but I
>> am not more clever than before.
>>
>> When I create a respond "file not found" (fileserver_example.c) for
>> POST requests, it fails on checking in MHD_queue_response and MHD_NO
>> is returned.
>> file: connection.c
>> #246 ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state)&&
>> #247 (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
>> connection->state is MHD_CONNECTION_CONTINUE_SENT
>>
>> and the connection is reset. Probably it is due to continual sending
>> data from POST request.
>>
>> I have created this code to overcome it:
>>
>> if(true == page_not_found)
>> {
>> if (0 == strcmp(method, MHD_HTTP_METHOD_GET))
>> generate_no_page_found_response();
>> }
>> else if((0 == strcmp(method, MHD_HTTP_METHOD_POST)))
>> {
>> if (0 != *upload_data_size)
>> {
>> *upload_data_size = 0; // pretend we have processed data.
>> return MHD_YES; // OK
>> }
>> else
>> generate_no_page_found_response(); // last request data.
>> }//else if((0 == strcmp(method, MHD_HTTP_METHOD_POST)))
>> }//if(true == page_not_found)
>>
>> There is a drawback, the client send waste data to server. On the
>> contrary, the same behavior is implemented on many server, e.g.
>> wget www.google.cz/dasfasdf --post-file=/tmp/very_big_file.
>>
>> Any ideas how to handle POST requests?
>>
>> Thank you
>> Martin
>>
>> On Wed, Aug 29, 2012 at 11:51 AM, Christian Grothoff
>> <address@hidden> wrote:
>>>
>>> Dear Martin,
>>>
>>> You can totally do it later (the disadvantage being that then the client
>>> will have started the upload, and if you're then out-of-memory and cannot
>>> handle the request, bandwidth will be wasted). So the question is if it
>>> is
>>> worse to put the test on filepost1 vs. filepost2 into the PP callback vs.
>>> delaying creating the PP. That's a very minor engineering decision IMO.
>>>
>>> You also do not have to use the post processor at all --- if you are in a
>>> setting where parsing of the upload data is not required or trivial, you
>>> can
>>> also handle it yourself and never create a post processor. For very,
>>> very
>>> small systems (< 128k RAM/ROM), this might be the best option.
>>>
>>> Happy hacking!
>>>
>>> Christian
>>>
>>>
>>> On 08/29/2012 11:42 AM, Martin Velek wrote:
>>>>
>>>> Hello,
>>>>
>>>> is it mandatory to create MHD_create_post_processor during the first
>>>> call of function MHD_AccessHandlerCallback? In all post examples, it
>>>> is done in if (NULL == *con_cls){ ... }.
>>>>
>>>> Or can I create it later (second call of MHD_AccessHandlerCallback)?:
>>>> if (0 == strcmp (method, "POST"))
>>>> {
>>>> if(false == was_not_alredy_created)
>>>> {
>>>> con_info->postprocessor = MHD_create_post_processor
>>>> (connection, POSTBUFFERSIZE, iterate_post, (void *) con_info);
>>>> }
>>>> if (0 != *upload_data_size)
>>>> {
>>>> MHD_post_process (con_info->postprocessor, upload_data,
>>>> *upload_data_size);
>>>> *upload_data_size = 0;
>>>> return MHD_YES;
>>>> }
>>>> }
>>>>
>>>> Thanks You for answer(s)
>>>> Martin
>>>>
>>>> -------------------------------- A very very long reason
>>>> --------------------------
>>>> I am trying to create a small web server based on libmicrohttpd
>>>> handling also SSI and CGI requests (a function which returns buffer).
>>>> It offers own interface e.g. only http_server_start(). Internals of
>>>> Libmicrohttpd are mostly hidden, e.g. the function
>>>> http_server_set_credentials(const char * username, const char *
>>>> password) sets user and password for basic http auth and
>>>> http_server_setup_handler() sets user callback for handling requests.
>>>>
>>>> My AccessHandlerCallback is a static function and call user's callback.
>>>>
>>>> #define HTTP_NEW_CONNECTION ((void *)(~0))
>>>> static int AccessHandlerCallback(void *cls, struct MHD_Connection
>>>> *connection,
>>>> const char *url, const char *method, const char
>>>> *version,
>>>> const char *upload_data, size_t *upload_data_size, void
>>>> **con_cls) {
>>>>
>>>> int ret = MHD_NO;
>>>> char *user = NULL;
>>>> char *pass = NULL;
>>>>
>>>> if (NULL == *con_cls)
>>>> {
>>>> /*
>>>> * Thus, we will generate no response until the
>>>> parameter
>>>> is
>>>> non-null—implying the callback was called before at least once.
>>>> * We do not need to share information between
>>>> different
>>>> calls of
>>>> the callback, so we can set the parameter to any adress
>>>> * that is assured to be not null.
>>>> */
>>>> *con_cls = HTTP_NEW_CONNECTION;
>>>> return MHD_YES;
>>>> }
>>>> // get username and password
>>>> user = MHD_basic_auth_get_username_password (connection,&pass);
>>>> // check if it is valid
>>>> if (false == check_credentials(user, pass))
>>>> {
>>>> // no, send denied reply
>>>> struct MHD_Response * response =
>>>> MHD_create_response_from_buffer(strlen(AUTH_FAIL_PAGE), (void *)
>>>> AUTH_FAIL_PAGE, MHD_RESPMEM_PERSISTENT);
>>>> MHD_add_response_header (response,
>>>> MHD_HTTP_HEADER_CONTENT_TYPE,
>>>> "text/html""; charset=iso-8859-2");
>>>> // Set headers to always close connection
>>>> MHD_add_response_header
>>>> (response,MHD_HTTP_HEADER_CONNECTION, "close");
>>>> ret = MHD_queue_basic_auth_fail_response(connection,
>>>> AUTHENTICATION_REALM_MESSAGE, response);
>>>> MHD_destroy_response (response);
>>>> }
>>>> else
>>>> {
>>>> if(NULL != url_handler.url_callback)
>>>> {
>>>> ret = url_handler.url_callback(connection,
>>>> url_handler.url_callback_cls, url, method, upload_data,
>>>> upload_data_size, con_cls);
>>>> }
>>>> else
>>>> {
>>>> ret = MHD_NO;
>>>> }
>>>> }
>>>> // Dealocate because of MHD.
>>>> free (user);
>>>> free (pass);
>>>>
>>>> return ret;
>>>> }
>>>>
>>>> I would like to handle more than one page (1 ... n files) e.g. from
>>>> this GET request.
>>>>
>>>> "<html><body>Upload a file, please!<br>
>>>> <form action=\"/filepost1\" method=\"post\"
>>>> enctype=\"multipart/form-data\">
>>>> <input name=\"file\" type=\"file\">
>>>> <input type=\"submit\" value=\" Send \"></form>
>>>>
>>>> <form action=\"/filepost2\" method=\"post\"
>>>> enctype=\"multipart/form-data\">
>>>> <input name=\"file\" type=\"file\">
>>>> <input type=\"submit\" value=\" Send \"></form>
>>>>
>>>> </body></html>";
>>>>
>>>> Both files /filepost1 and /filepost2 have different
>>>> MHD_PostDataIterator, filepost1 stores file onto harddisk, filepost2
>>>> to memory.
>>>>
>>>> Which MHD_PostDataIterator will be used, it is defined in a user
>>>> callback called from AccessHandlerCallback. This is the reason of my
>>>> question.
>>>>
>>>
>
>