Blame doc/chapters/processingpost.inc

Packit 875988
The previous chapters already have demonstrated a variety of possibilities to send information 
Packit 875988
to the HTTP server, but it is not recommended that the @emph{GET} method is used to alter the way
Packit 875988
the server operates. To induce changes on the server, the @emph{POST} method is preferred over
Packit 875988
and is much more powerful than @emph{GET} and will be introduced in this chapter.
Packit 875988
Packit 875988
We are going to write an application that asks for the visitor's name and, after the user has posted it,
Packit 875988
composes an individual response text. Even though it was not mandatory to use the @emph{POST} method here,
Packit 875988
as there is no permanent change caused by the POST, it is an illustrative example on how to share data
Packit 875988
between different functions for the same connection. Furthermore, the reader should be able to extend
Packit 875988
it easily.
Packit 875988
Packit 875988
@heading GET request
Packit 875988
When the first @emph{GET} request arrives, the server shall respond with a HTML page containing an
Packit 875988
edit field for the name.
Packit 875988
Packit 875988
@verbatim
Packit 875988
const char* askpage = "<html><body>\
Packit 875988
                       What's your name, Sir?
\
Packit 875988
                       <form action=\"/namepost\" method=\"post\">\
Packit 875988
                       
Packit 875988
                       <input type=\"submit\" value=\" Send \"></form>\
Packit 875988
                       </body></html>";
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
The @code{action} entry is the @emph{URI} to be called by the browser when posting, and the
Packit 875988
@code{name} will be used later to be sure it is the editbox's content that has been posted.
Packit 875988
Packit 875988
We also prepare the answer page, where the name is to be filled in later, and an error page 
Packit 875988
as the response for anything but proper @emph{GET} and @emph{POST} requests:
Packit 875988
Packit 875988
@verbatim
Packit 875988
const char* greatingpage="<html><body>

Welcome, %s!</center>

</body></html>";
Packit 875988
Packit 875988
const char* errorpage="<html><body>This doesn't seem to be right.</body></html>";
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
Whenever we need to send a page, we use an extra function
Packit 875988
@code{int send_page(struct MHD_Connection *connection, const char* page)}
Packit 875988
for this, which does not contain anything new and whose implementation is therefore 
Packit 875988
not discussed further in the tutorial.
Packit 875988
Packit 875988
Packit 875988
@heading POST request
Packit 875988
Posted data can be of arbitrary and considerable size; for example, if a user uploads a big
Packit 875988
image to the server. Similar to the case of the header fields, there may also be different streams
Packit 875988
of posted data, such as one containing the text of an editbox and another the state of a button.
Packit 875988
Likewise, we will have to register an iterator function that is going to be called maybe several times 
Packit 875988
not only if there are different POSTs but also if one POST has only been received partly yet and
Packit 875988
needs processing before another chunk can be received.
Packit 875988
Packit 875988
Such an iterator function is called by a @emph{postprocessor}, which must be created upon arriving
Packit 875988
of the post request.  We want the iterator function to read the first post data which is tagged
Packit 875988
@code{name} and to create an individual greeting string based on the template and the name. 
Packit 875988
But in order to pass this string to other functions and still be able to differentiate different
Packit 875988
connections, we must first define a structure to share the information, holding the most import entries.
Packit 875988
Packit 875988
@verbatim
Packit 875988
struct connection_info_struct
Packit 875988
{
Packit 875988
  int connectiontype;
Packit 875988
  char *answerstring;
Packit 875988
  struct MHD_PostProcessor *postprocessor; 
Packit 875988
};
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
With these information available to the iterator function, it is able to fulfill its task. 
Packit 875988
Once it has composed the greeting string, it returns @code{MHD_NO} to inform the post processor
Packit 875988
that it does not need to be called again. Note that this function does not handle processing
Packit 875988
of data for the same @code{key}. If we were to expect that the name will be posted in several
Packit 875988
chunks, we had to expand the namestring dynamically as additional parts of it with the same @code{key}
Packit 875988
came in. But in this example, the name is assumed to fit entirely inside one single packet.
Packit 875988
Packit 875988
@verbatim
Packit 875988
static int 
Packit 875988
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
Packit 875988
              const char *filename, const char *content_type,
Packit 875988
              const char *transfer_encoding, const char *data, 
Packit 875988
	      uint64_t off, size_t size)
Packit 875988
{
Packit 875988
  struct connection_info_struct *con_info = coninfo_cls;
Packit 875988
Packit 875988
  if (0 == strcmp (key, "name"))
Packit 875988
    {
Packit 875988
      if ((size > 0) && (size <= MAXNAMESIZE))
Packit 875988
        {
Packit 875988
          char *answerstring;
Packit 875988
          answerstring = malloc (MAXANSWERSIZE);
Packit 875988
          if (!answerstring) return MHD_NO;
Packit 875988
      
Packit 875988
          snprintf (answerstring, MAXANSWERSIZE, greatingpage, data);
Packit 875988
          con_info->answerstring = answerstring;      
Packit 875988
        } 
Packit 875988
      else con_info->answerstring = NULL;
Packit 875988
Packit 875988
      return MHD_NO;
Packit 875988
    }
Packit 875988
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
Once a connection has been established, it can be terminated for many reasons. As these
Packit 875988
reasons include unexpected events, we have to register another function that cleans up any resources
Packit 875988
that might have been allocated for that connection by us, namely the post processor and the greetings
Packit 875988
string. This cleanup function must take into account that it will also be called for finished 
Packit 875988
requests other than @emph{POST} requests.
Packit 875988
Packit 875988
@verbatim
Packit 875988
void request_completed (void *cls, struct MHD_Connection *connection, 
Packit 875988
     		        void **con_cls,
Packit 875988
                        enum MHD_RequestTerminationCode toe)
Packit 875988
{
Packit 875988
  struct connection_info_struct *con_info = *con_cls;
Packit 875988
Packit 875988
  if (NULL == con_info) return;
Packit 875988
  if (con_info->connectiontype == POST)
Packit 875988
    {
Packit 875988
      MHD_destroy_post_processor (con_info->postprocessor);        
Packit 875988
      if (con_info->answerstring) free (con_info->answerstring);
Packit 875988
    }
Packit 875988
  
Packit 875988
  free (con_info);
Packit 875988
  *con_cls = NULL;   
Packit 875988
}
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
@emph{GNU libmicrohttpd} is informed that it shall call the above function when the daemon is started
Packit 875988
in the main function.
Packit 875988
Packit 875988
@verbatim
Packit 875988
...
Packit 875988
daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
Packit 875988
                           &answer_to_connection, NULL, 
Packit 875988
			   MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
Packit 875988
			   MHD_OPTION_END);
Packit 875988
...
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
@heading Request handling
Packit 875988
With all other functions prepared, we can now discuss the actual request handling.
Packit 875988
Packit 875988
On the first iteration for a new request, we start by allocating a new instance of a 
Packit 875988
@code{struct connection_info_struct} structure, which will store all necessary information for later
Packit 875988
iterations and other functions.
Packit 875988
Packit 875988
@verbatim
Packit 875988
static int 
Packit 875988
answer_to_connection (void *cls, struct MHD_Connection *connection, 
Packit 875988
		      const char *url, 
Packit 875988
                      const char *method, const char *version, 
Packit 875988
		      const char *upload_data, 
Packit 875988
                      size_t *upload_data_size, void **con_cls)
Packit 875988
{
Packit 875988
  if(NULL == *con_cls) 
Packit 875988
    {
Packit 875988
      struct connection_info_struct *con_info;
Packit 875988
Packit 875988
      con_info = malloc (sizeof (struct connection_info_struct));
Packit 875988
      if (NULL == con_info) return MHD_NO;
Packit 875988
      con_info->answerstring = NULL;
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
If the new request is a @emph{POST}, the postprocessor must be created now. In addition, the type
Packit 875988
of the request is stored for convenience.
Packit 875988
@verbatim
Packit 875988
      if (0 == strcmp (method, "POST")) 
Packit 875988
        {      
Packit 875988
          con_info->postprocessor 
Packit 875988
	    = MHD_create_post_processor (connection, POSTBUFFERSIZE, 
Packit 875988
                                         iterate_post, (void*) con_info);   
Packit 875988
Packit 875988
          if (NULL == con_info->postprocessor) 
Packit 875988
            {
Packit 875988
              free (con_info); 
Packit 875988
              return MHD_NO;
Packit 875988
            }
Packit 875988
          con_info->connectiontype = POST;
Packit 875988
        } 
Packit 875988
      else con_info->connectiontype = GET;
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
The address of our structure will both serve as the indicator for successive iterations and to remember
Packit 875988
the particular details about the connection.
Packit 875988
@verbatim
Packit 875988
      *con_cls = (void*) con_info; 
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
The rest of the function will not be executed on the first iteration. A @emph{GET} request is easily
Packit 875988
satisfied by sending the question form.
Packit 875988
@verbatim
Packit 875988
  if (0 == strcmp (method, "GET")) 
Packit 875988
    {
Packit 875988
      return send_page (connection, askpage);     
Packit 875988
    } 
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
In case of @emph{POST}, we invoke the post processor for as long as data keeps incoming, setting
Packit 875988
@code{*upload_data_size} to zero in order to indicate that we have processed---or at least have
Packit 875988
considered---all of it.
Packit 875988
@verbatim
Packit 875988
  if (0 == strcmp (method, "POST")) 
Packit 875988
    {
Packit 875988
      struct connection_info_struct *con_info = *con_cls;
Packit 875988
Packit 875988
      if (*upload_data_size != 0) 
Packit 875988
        {
Packit 875988
          MHD_post_process (con_info->postprocessor, upload_data,	
Packit 875988
	                    *upload_data_size);
Packit 875988
          *upload_data_size = 0;
Packit 875988
          
Packit 875988
          return MHD_YES;
Packit 875988
        } 
Packit 875988
      else if (NULL != con_info->answerstring) 
Packit 875988
        return send_page (connection, con_info->answerstring);
Packit 875988
    } 
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
Finally, if they are neither @emph{GET} nor @emph{POST} requests, the error page is returned.
Packit 875988
@verbatim
Packit 875988
  return send_page(connection, errorpage); 
Packit 875988
}
Packit 875988
@end verbatim
Packit 875988
@noindent
Packit 875988
Packit 875988
These were the important parts of the program @code{simplepost.c}.