aboutsummaryrefslogtreecommitdiff
path: root/doc/chapters/processingpost.inc
blob: 8f0dc7d8c8944242ef401be1c3f5d820a049653b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
The previous chapters already have demonstrated a variety of possibilities to send information 
to the HTTP server, but it is not recommended that the @emph{GET} method is used to alter the way
the server operates. To induce changes on the server, the @emph{POST} method is preferred over
and is much more powerful than @emph{GET} and will be introduced in this chapter.

We are going to write an application that asks for the visitor's name and, after the user has posted it,
composes an individual response text. Even though it was not mandatory to use the @emph{POST} method here,
as there is no permanent change caused by the POST, it is an illustrative example on how to share data
between different functions for the same connection. Furthermore, the reader should be able to extend
it easily.

@heading GET request
When the first @emph{GET} request arrives, the server shall respond with a HTML page containing an
edit field for the name.

@verbatim
const char* askpage = "<html><body>\
                       What's your name, Sir?<br>\
                       <form action=\"/namepost\" method=\"post\">\
                       <input name=\"name\" type=\"text\"\
                       <input type=\"submit\" value=\" Send \"></form>\
                       </body></html>";
@end verbatim
@noindent

The @code{action} entry is the @emph{URI} to be called by the browser when posting, and the
@code{name} will be used later to be sure it is the editbox's content that has been posted.

We also prepare the answer page, where the name is to be filled in later, and an error page 
as the response for anything but proper @emph{GET} and @emph{POST} requests:

@verbatim
const char* greatingpage="<html><body><h1>Welcome, %s!</center></h1></body></html>";

const char* errorpage="<html><body>This doesn't seem to be right.</body></html>";
@end verbatim
@noindent

Whenever we need to send a page, we use an extra function
@code{int send_page(struct MHD_Connection *connection, const char* page)}
for this, which does not contain anything new and whose implementation is therefore 
not discussed further in the tutorial.


@heading POST request
Posted data can be of arbitrary and considerable size; for example, if a user uploads a big
image to the server. Similar to the case of the header fields, there may also be different streams
of posted data, such as one containing the text of an editbox and another the state of a button.
Likewise, we will have to register an iterator function that is going to be called maybe several times 
not only if there are different POSTs but also if one POST has only been received partly yet and
needs processing before another chunk can be received.

Such an iterator function is called by a @emph{postprocessor}, which must be created upon arriving
of the post request.  We want the iterator function to read the first post data which is tagged
@code{name} and to create an individual greeting string based on the template and the name. 
But in order to pass this string to other functions and still be able to differentiate different
connections, we must first define a structure to share the information, holding the most import entries.

@verbatim
struct connection_info_struct
{
  int connectiontype;
  char *answerstring;
  struct MHD_PostProcessor *postprocessor; 
};
@end verbatim
@noindent

With these information available to the iterator function, it is able to fulfill its task. 
Once it has composed the greeting string, it returns @code{MHD_NO} to inform the post processor
that it does not need to be called again. Note that this function does not handle processing
of data for the same @code{key}. If we were to expect that the name will be posted in several
chunks, we had to expand the namestring dynamically as additional parts of it with the same @code{key}
came in. But in this example, the name is assumed to fit entirely inside one single packet.

@verbatim
static int 
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
              const char *filename, const char *content_type,
              const char *transfer_encoding, const char *data, 
	      uint64_t off, size_t size)
{
  struct connection_info_struct *con_info = coninfo_cls;

  if (0 == strcmp (key, "name"))
    {
      if ((size > 0) && (size <= MAXNAMESIZE))
        {
          char *answerstring;
          answerstring = malloc (MAXANSWERSIZE);
          if (!answerstring) return MHD_NO;
      
          snprintf (answerstring, MAXANSWERSIZE, greatingpage, data);
          con_info->answerstring = answerstring;      
        } 
      else con_info->answerstring = NULL;

      return MHD_NO;
    }

  return MHD_YES;
}
@end verbatim
@noindent

Once a connection has been established, it can be terminated for many reasons. As these
reasons include unexpected events, we have to register another function that cleans up any resources
that might have been allocated for that connection by us, namely the post processor and the greetings
string. This cleanup function must take into account that it will also be called for finished 
requests other than @emph{POST} requests.

@verbatim
void request_completed (void *cls, struct MHD_Connection *connection, 
     		        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
{
  struct connection_info_struct *con_info = *req_cls;

  if (NULL == con_info) return;
  if (con_info->connectiontype == POST)
    {
      MHD_destroy_post_processor (con_info->postprocessor);        
      if (con_info->answerstring) free (con_info->answerstring);
    }
  
  free (con_info);
  *req_cls = NULL;   
}
@end verbatim
@noindent

@emph{GNU libmicrohttpd} is informed that it shall call the above function when the daemon is started
in the main function.

@verbatim
...
daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
                           &answer_to_connection, NULL, 
			   MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
			   MHD_OPTION_END);
...
@end verbatim
@noindent

@heading Request handling
With all other functions prepared, we can now discuss the actual request handling.

On the first iteration for a new request, we start by allocating a new instance of a 
@code{struct connection_info_struct} structure, which will store all necessary information for later
iterations and other functions.

@verbatim
static int 
answer_to_connection (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 **req_cls)
{
  if(NULL == *req_cls) 
    {
      struct connection_info_struct *con_info;

      con_info = malloc (sizeof (struct connection_info_struct));
      if (NULL == con_info) return MHD_NO;
      con_info->answerstring = NULL;
@end verbatim
@noindent

If the new request is a @emph{POST}, the postprocessor must be created now. In addition, the type
of the request is stored for convenience.
@verbatim
      if (0 == strcmp (method, "POST")) 
        {      
          con_info->postprocessor 
	    = MHD_create_post_processor (connection, POSTBUFFERSIZE, 
                                         iterate_post, (void*) con_info);   

          if (NULL == con_info->postprocessor) 
            {
              free (con_info); 
              return MHD_NO;
            }
          con_info->connectiontype = POST;
        } 
      else con_info->connectiontype = GET;
@end verbatim
@noindent

The address of our structure will both serve as the indicator for successive iterations and to remember
the particular details about the connection.
@verbatim
      *req_cls = (void*) con_info; 
      return MHD_YES;
    }
@end verbatim
@noindent

The rest of the function will not be executed on the first iteration. A @emph{GET} request is easily
satisfied by sending the question form.
@verbatim
  if (0 == strcmp (method, "GET")) 
    {
      return send_page (connection, askpage);     
    } 
@end verbatim
@noindent

In case of @emph{POST}, we invoke the post processor for as long as data keeps incoming, setting
@code{*upload_data_size} to zero in order to indicate that we have processed---or at least have
considered---all of it.
@verbatim
  if (0 == strcmp (method, "POST")) 
    {
      struct connection_info_struct *con_info = *req_cls;

      if (*upload_data_size != 0) 
        {
          MHD_post_process (con_info->postprocessor, upload_data,	
	                    *upload_data_size);
          *upload_data_size = 0;
          
          return MHD_YES;
        } 
      else if (NULL != con_info->answerstring) 
        return send_page (connection, con_info->answerstring);
    } 
@end verbatim
@noindent

Finally, if they are neither @emph{GET} nor @emph{POST} requests, the error page is returned.
@verbatim
  return send_page(connection, errorpage); 
}
@end verbatim
@noindent

These were the important parts of the program @code{simplepost.c}.