• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2      This file is part of libmicrohttpd
3      Copyright (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Lesser General Public
7      License as published by the Free Software Foundation; either
8      version 2.1 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Lesser General Public License for more details.
14 
15      You should have received a copy of the GNU Lesser General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 /**
21  * @file response.c
22  * @brief  Methods for managing response objects
23  * @author Daniel Pittman
24  * @author Christian Grothoff
25  */
26 
27 #include "internal.h"
28 #include "response.h"
29 
30 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
31 #ifndef WIN32_LEAN_AND_MEAN
32 #define WIN32_LEAN_AND_MEAN 1
33 #endif /* !WIN32_LEAN_AND_MEAN */
34 #include <windows.h>
35 #endif /* _WIN32 && MHD_W32_MUTEX_ */
36 #if defined(_WIN32)
37 #include <io.h> /* for lseek(), read() */
38 #endif /* _WIN32 */
39 
40 
41 /**
42  * Add a header or footer line to the response.
43  *
44  * @param response response to add a header to
45  * @param kind header or footer
46  * @param header the header to add
47  * @param content value to add
48  * @return #MHD_NO on error (i.e. invalid header or content format).
49  */
50 static int
add_response_entry(struct MHD_Response * response,enum MHD_ValueKind kind,const char * header,const char * content)51 add_response_entry (struct MHD_Response *response,
52 		    enum MHD_ValueKind kind,
53 		    const char *header,
54 		    const char *content)
55 {
56   struct MHD_HTTP_Header *hdr;
57 
58   if ( (NULL == response) ||
59        (NULL == header) ||
60        (NULL == content) ||
61        (0 == strlen (header)) ||
62        (0 == strlen (content)) ||
63        (NULL != strchr (header, '\t')) ||
64        (NULL != strchr (header, '\r')) ||
65        (NULL != strchr (header, '\n')) ||
66        (NULL != strchr (content, '\t')) ||
67        (NULL != strchr (content, '\r')) ||
68        (NULL != strchr (content, '\n')) )
69     return MHD_NO;
70   if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
71     return MHD_NO;
72   if (NULL == (hdr->header = strdup (header)))
73     {
74       free (hdr);
75       return MHD_NO;
76     }
77   if (NULL == (hdr->value = strdup (content)))
78     {
79       free (hdr->header);
80       free (hdr);
81       return MHD_NO;
82     }
83   hdr->kind = kind;
84   hdr->next = response->first_header;
85   response->first_header = hdr;
86   return MHD_YES;
87 }
88 
89 
90 /**
91  * Add a header line to the response.
92  *
93  * @param response response to add a header to
94  * @param header the header to add
95  * @param content value to add
96  * @return #MHD_NO on error (i.e. invalid header or content format).
97  * @ingroup response
98  */
99 int
MHD_add_response_header(struct MHD_Response * response,const char * header,const char * content)100 MHD_add_response_header (struct MHD_Response *response,
101                          const char *header, const char *content)
102 {
103   return add_response_entry (response,
104 			     MHD_HEADER_KIND,
105 			     header,
106 			     content);
107 }
108 
109 
110 /**
111  * Add a footer line to the response.
112  *
113  * @param response response to remove a header from
114  * @param footer the footer to delete
115  * @param content value to delete
116  * @return #MHD_NO on error (i.e. invalid footer or content format).
117  * @ingroup response
118  */
119 int
MHD_add_response_footer(struct MHD_Response * response,const char * footer,const char * content)120 MHD_add_response_footer (struct MHD_Response *response,
121                          const char *footer, const char *content)
122 {
123   return add_response_entry (response,
124 			     MHD_FOOTER_KIND,
125 			     footer,
126 			     content);
127 }
128 
129 
130 /**
131  * Delete a header (or footer) line from the response.
132  *
133  * @param response response to remove a header from
134  * @param header the header to delete
135  * @param content value to delete
136  * @return #MHD_NO on error (no such header known)
137  * @ingroup response
138  */
139 int
MHD_del_response_header(struct MHD_Response * response,const char * header,const char * content)140 MHD_del_response_header (struct MHD_Response *response,
141                          const char *header,
142 			 const char *content)
143 {
144   struct MHD_HTTP_Header *pos;
145   struct MHD_HTTP_Header *prev;
146 
147   if ( (NULL == header) || (NULL == content) )
148     return MHD_NO;
149   prev = NULL;
150   pos = response->first_header;
151   while (pos != NULL)
152     {
153       if ((0 == strcmp (header, pos->header)) &&
154           (0 == strcmp (content, pos->value)))
155         {
156           free (pos->header);
157           free (pos->value);
158           if (NULL == prev)
159             response->first_header = pos->next;
160           else
161             prev->next = pos->next;
162           free (pos);
163           return MHD_YES;
164         }
165       prev = pos;
166       pos = pos->next;
167     }
168   return MHD_NO;
169 }
170 
171 
172 /**
173  * Get all of the headers (and footers) added to a response.
174  *
175  * @param response response to query
176  * @param iterator callback to call on each header;
177  *        maybe NULL (then just count headers)
178  * @param iterator_cls extra argument to @a iterator
179  * @return number of entries iterated over
180  * @ingroup response
181  */
182 int
MHD_get_response_headers(struct MHD_Response * response,MHD_KeyValueIterator iterator,void * iterator_cls)183 MHD_get_response_headers (struct MHD_Response *response,
184                           MHD_KeyValueIterator iterator, void *iterator_cls)
185 {
186   struct MHD_HTTP_Header *pos;
187   int numHeaders = 0;
188 
189   for (pos = response->first_header; NULL != pos; pos = pos->next)
190     {
191       numHeaders++;
192       if ((NULL != iterator) &&
193           (MHD_YES != iterator (iterator_cls,
194                                 pos->kind, pos->header, pos->value)))
195         break;
196     }
197   return numHeaders;
198 }
199 
200 
201 /**
202  * Get a particular header (or footer) from the response.
203  *
204  * @param response response to query
205  * @param key which header to get
206  * @return NULL if header does not exist
207  * @ingroup response
208  */
209 const char *
MHD_get_response_header(struct MHD_Response * response,const char * key)210 MHD_get_response_header (struct MHD_Response *response,
211 			 const char *key)
212 {
213   struct MHD_HTTP_Header *pos;
214 
215   if (NULL == key)
216     return NULL;
217   for (pos = response->first_header; NULL != pos; pos = pos->next)
218     if (0 == strcmp (key, pos->header))
219       return pos->value;
220   return NULL;
221 }
222 
223 
224 /**
225  * Create a response object.  The response object can be extended with
226  * header information and then be used any number of times.
227  *
228  * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown
229  * @param block_size preferred block size for querying crc (advisory only,
230  *                   MHD may still call @a crc using smaller chunks); this
231  *                   is essentially the buffer size used for IO, clients
232  *                   should pick a value that is appropriate for IO and
233  *                   memory performance requirements
234  * @param crc callback to use to obtain response data
235  * @param crc_cls extra argument to @a crc
236  * @param crfc callback to call to free @a crc_cls resources
237  * @return NULL on error (i.e. invalid arguments, out of memory)
238  * @ingroup response
239  */
240 struct MHD_Response *
MHD_create_response_from_callback(uint64_t size,size_t block_size,MHD_ContentReaderCallback crc,void * crc_cls,MHD_ContentReaderFreeCallback crfc)241 MHD_create_response_from_callback (uint64_t size,
242                                    size_t block_size,
243                                    MHD_ContentReaderCallback crc,
244                                    void *crc_cls,
245                                    MHD_ContentReaderFreeCallback crfc)
246 {
247   struct MHD_Response *response;
248 
249   if ((NULL == crc) || (0 == block_size))
250     return NULL;
251   if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size)))
252     return NULL;
253   memset (response, 0, sizeof (struct MHD_Response));
254   response->fd = -1;
255   response->data = (void *) &response[1];
256   response->data_buffer_size = block_size;
257   if (MHD_YES != MHD_mutex_create_ (&response->mutex))
258     {
259       free (response);
260       return NULL;
261     }
262   response->crc = crc;
263   response->crfc = crfc;
264   response->crc_cls = crc_cls;
265   response->reference_count = 1;
266   response->total_size = size;
267   return response;
268 }
269 
270 
271 /**
272  * Set special flags and options for a response.
273  *
274  * @param response the response to modify
275  * @param flags to set for the response
276  * @param ... #MHD_RO_END terminated list of options
277  * @return #MHD_YES on success, #MHD_NO on error
278  */
279 int
MHD_set_response_options(struct MHD_Response * response,enum MHD_ResponseFlags flags,...)280 MHD_set_response_options (struct MHD_Response *response,
281                           enum MHD_ResponseFlags flags,
282                           ...)
283 {
284   va_list ap;
285   int ret;
286   enum MHD_ResponseOptions ro;
287 
288   ret = MHD_YES;
289   response->flags = flags;
290   va_start (ap, flags);
291   while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
292   {
293     switch (ro)
294     {
295     default:
296       ret = MHD_NO;
297       break;
298     }
299   }
300   va_end (ap);
301   return ret;
302 }
303 
304 
305 /**
306  * Given a file descriptor, read data from the file
307  * to generate the response.
308  *
309  * @param cls pointer to the response
310  * @param pos offset in the file to access
311  * @param buf where to write the data
312  * @param max number of bytes to write at most
313  * @return number of bytes written
314  */
315 static ssize_t
file_reader(void * cls,uint64_t pos,char * buf,size_t max)316 file_reader (void *cls, uint64_t pos, char *buf, size_t max)
317 {
318   struct MHD_Response *response = cls;
319   ssize_t n;
320 
321   (void) lseek (response->fd, pos + response->fd_off, SEEK_SET);
322   n = read (response->fd, buf, max);
323   if (0 == n)
324     return MHD_CONTENT_READER_END_OF_STREAM;
325   if (n < 0)
326     return MHD_CONTENT_READER_END_WITH_ERROR;
327   return n;
328 }
329 
330 
331 /**
332  * Destroy file reader context.  Closes the file
333  * descriptor.
334  *
335  * @param cls pointer to file descriptor
336  */
337 static void
free_callback(void * cls)338 free_callback (void *cls)
339 {
340   struct MHD_Response *response = cls;
341 
342   (void) close (response->fd);
343   response->fd = -1;
344 }
345 
346 
347 /**
348  * Create a response object.  The response object can be extended with
349  * header information and then be used any number of times.
350  *
351  * @param size size of the data portion of the response
352  * @param fd file descriptor referring to a file on disk with the
353  *        data; will be closed when response is destroyed;
354  *        fd should be in 'blocking' mode
355  * @param offset offset to start reading from in the file;
356  *        Be careful! `off_t` may have been compiled to be a
357  *        64-bit variable for MHD, in which case your application
358  *        also has to be compiled using the same options! Read
359  *        the MHD manual for more details.
360  * @return NULL on error (i.e. invalid arguments, out of memory)
361  * @ingroup response
362  */
363 struct MHD_Response *
MHD_create_response_from_fd_at_offset(size_t size,int fd,off_t offset)364 MHD_create_response_from_fd_at_offset (size_t size,
365 				       int fd,
366 				       off_t offset)
367 {
368   struct MHD_Response *response;
369 
370   response = MHD_create_response_from_callback (size,
371 						4 * 1024,
372 						&file_reader,
373 						NULL,
374 						&free_callback);
375   if (NULL == response)
376     return NULL;
377   response->fd = fd;
378   response->fd_off = offset;
379   response->crc_cls = response;
380   return response;
381 }
382 
383 
384 /**
385  * Create a response object.  The response object can be extended with
386  * header information and then be used any number of times.
387  *
388  * @param size size of the data portion of the response
389  * @param fd file descriptor referring to a file on disk with the data
390  * @return NULL on error (i.e. invalid arguments, out of memory)
391  * @ingroup response
392  */
393 struct MHD_Response *
MHD_create_response_from_fd(size_t size,int fd)394 MHD_create_response_from_fd (size_t size,
395 			     int fd)
396 {
397   return MHD_create_response_from_fd_at_offset (size, fd, 0);
398 }
399 
400 
401 /**
402  * Create a response object.  The response object can be extended with
403  * header information and then be used any number of times.
404  *
405  * @param size size of the @a data portion of the response
406  * @param data the data itself
407  * @param must_free libmicrohttpd should free data when done
408  * @param must_copy libmicrohttpd must make a copy of @a data
409  *        right away, the data maybe released anytime after
410  *        this call returns
411  * @return NULL on error (i.e. invalid arguments, out of memory)
412  * @deprecated use #MHD_create_response_from_buffer instead
413  * @ingroup response
414  */
415 struct MHD_Response *
MHD_create_response_from_data(size_t size,void * data,int must_free,int must_copy)416 MHD_create_response_from_data (size_t size,
417                                void *data, int must_free, int must_copy)
418 {
419   struct MHD_Response *response;
420   void *tmp;
421 
422   if ((NULL == data) && (size > 0))
423     return NULL;
424   if (NULL == (response = malloc (sizeof (struct MHD_Response))))
425     return NULL;
426   memset (response, 0, sizeof (struct MHD_Response));
427   response->fd = -1;
428   if (MHD_YES != MHD_mutex_create_ (&response->mutex))
429     {
430       free (response);
431       return NULL;
432     }
433   if ((must_copy) && (size > 0))
434     {
435       if (NULL == (tmp = malloc (size)))
436         {
437           (void) MHD_mutex_destroy_ (&response->mutex);
438           free (response);
439           return NULL;
440         }
441       memcpy (tmp, data, size);
442       must_free = MHD_YES;
443       data = tmp;
444     }
445   response->crc = NULL;
446   response->crfc = must_free ? &free : NULL;
447   response->crc_cls = must_free ? data : NULL;
448   response->reference_count = 1;
449   response->total_size = size;
450   response->data = data;
451   response->data_size = size;
452   return response;
453 }
454 
455 
456 /**
457  * Create a response object.  The response object can be extended with
458  * header information and then be used any number of times.
459  *
460  * @param size size of the data portion of the response
461  * @param buffer size bytes containing the response's data portion
462  * @param mode flags for buffer management
463  * @return NULL on error (i.e. invalid arguments, out of memory)
464  * @ingroup response
465  */
466 struct MHD_Response *
MHD_create_response_from_buffer(size_t size,void * buffer,enum MHD_ResponseMemoryMode mode)467 MHD_create_response_from_buffer (size_t size,
468 				 void *buffer,
469 				 enum MHD_ResponseMemoryMode mode)
470 {
471   return MHD_create_response_from_data (size,
472 					buffer,
473 					mode == MHD_RESPMEM_MUST_FREE,
474 					mode == MHD_RESPMEM_MUST_COPY);
475 }
476 
477 
478 /**
479  * Destroy a response object and associated resources.  Note that
480  * libmicrohttpd may keep some of the resources around if the response
481  * is still in the queue for some clients, so the memory may not
482  * necessarily be freed immediatley.
483  *
484  * @param response response to destroy
485  * @ingroup response
486  */
487 void
MHD_destroy_response(struct MHD_Response * response)488 MHD_destroy_response (struct MHD_Response *response)
489 {
490   struct MHD_HTTP_Header *pos;
491 
492   if (NULL == response)
493     return;
494   (void) MHD_mutex_lock_ (&response->mutex);
495   if (0 != --(response->reference_count))
496     {
497       (void) MHD_mutex_unlock_ (&response->mutex);
498       return;
499     }
500   (void) MHD_mutex_unlock_ (&response->mutex);
501   (void) MHD_mutex_destroy_ (&response->mutex);
502   if (response->crfc != NULL)
503     response->crfc (response->crc_cls);
504   while (NULL != response->first_header)
505     {
506       pos = response->first_header;
507       response->first_header = pos->next;
508       free (pos->header);
509       free (pos->value);
510       free (pos);
511     }
512   free (response);
513 }
514 
515 
516 void
MHD_increment_response_rc(struct MHD_Response * response)517 MHD_increment_response_rc (struct MHD_Response *response)
518 {
519   (void) MHD_mutex_lock_ (&response->mutex);
520   (response->reference_count)++;
521   (void) MHD_mutex_unlock_ (&response->mutex);
522 }
523 
524 
525 /* end of response.c */
526