libmicrohttpd
[Top][All Lists]
Advanced

[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.
>>>>
>>>
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]