libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] post processing question


From: Christian Grothoff
Subject: Re: [libmicrohttpd] post processing question
Date: Fri, 31 Aug 2012 14:55:47 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.4) Gecko/20120510 Icedove/10.0.4

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]