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