GNU libmicrohttpd  0.9.29
response.c
Go to the documentation of this file.
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 
27 #define MHD_NO_DEPRECATION 1
28 
29 #include "internal.h"
30 #include "response.h"
31 #include "mhd_limits.h"
32 
33 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
34 #ifndef WIN32_LEAN_AND_MEAN
35 #define WIN32_LEAN_AND_MEAN 1
36 #endif /* !WIN32_LEAN_AND_MEAN */
37 #include <windows.h>
38 #endif /* _WIN32 && MHD_W32_MUTEX_ */
39 #if defined(_WIN32)
40 #include <io.h> /* for lseek(), read() */
41 #endif /* _WIN32 */
42 
43 
53 static int
54 add_response_entry (struct MHD_Response *response,
55  enum MHD_ValueKind kind,
56  const char *header,
57  const char *content)
58 {
59  struct MHD_HTTP_Header *hdr;
60 
61  if ( (NULL == response) ||
62  (NULL == header) ||
63  (NULL == content) ||
64  (0 == strlen (header)) ||
65  (0 == strlen (content)) ||
66  (NULL != strchr (header, '\t')) ||
67  (NULL != strchr (header, '\r')) ||
68  (NULL != strchr (header, '\n')) ||
69  (NULL != strchr (content, '\t')) ||
70  (NULL != strchr (content, '\r')) ||
71  (NULL != strchr (content, '\n')) )
72  return MHD_NO;
73  if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
74  return MHD_NO;
75  if (NULL == (hdr->header = strdup (header)))
76  {
77  free (hdr);
78  return MHD_NO;
79  }
80  if (NULL == (hdr->value = strdup (content)))
81  {
82  free (hdr->header);
83  free (hdr);
84  return MHD_NO;
85  }
86  hdr->kind = kind;
87  hdr->next = response->first_header;
88  response->first_header = hdr;
89  return MHD_YES;
90 }
91 
92 
102 int
104  const char *header, const char *content)
105 {
106  return add_response_entry (response,
108  header,
109  content);
110 }
111 
112 
122 int
124  const char *footer, const char *content)
125 {
126  return add_response_entry (response,
128  footer,
129  content);
130 }
131 
132 
142 int
144  const char *header,
145  const char *content)
146 {
147  struct MHD_HTTP_Header *pos;
148  struct MHD_HTTP_Header *prev;
149 
150  if ( (NULL == header) || (NULL == content) )
151  return MHD_NO;
152  prev = NULL;
153  pos = response->first_header;
154  while (pos != NULL)
155  {
156  if ((0 == strcmp (header, pos->header)) &&
157  (0 == strcmp (content, pos->value)))
158  {
159  free (pos->header);
160  free (pos->value);
161  if (NULL == prev)
162  response->first_header = pos->next;
163  else
164  prev->next = pos->next;
165  free (pos);
166  return MHD_YES;
167  }
168  prev = pos;
169  pos = pos->next;
170  }
171  return MHD_NO;
172 }
173 
174 
185 int
187  MHD_KeyValueIterator iterator, void *iterator_cls)
188 {
189  struct MHD_HTTP_Header *pos;
190  int numHeaders = 0;
191 
192  for (pos = response->first_header; NULL != pos; pos = pos->next)
193  {
194  numHeaders++;
195  if ((NULL != iterator) &&
196  (MHD_YES != iterator (iterator_cls,
197  pos->kind, pos->header, pos->value)))
198  break;
199  }
200  return numHeaders;
201 }
202 
203 
212 const char *
214  const char *key)
215 {
216  struct MHD_HTTP_Header *pos;
217 
218  if (NULL == key)
219  return NULL;
220  for (pos = response->first_header; NULL != pos; pos = pos->next)
221  if (0 == strcmp (key, pos->header))
222  return pos->value;
223  return NULL;
224 }
225 
226 
243 struct MHD_Response *
245  size_t block_size,
247  void *crc_cls,
249 {
250  struct MHD_Response *response;
251 
252  if ((NULL == crc) || (0 == block_size))
253  return NULL;
254  if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size)))
255  return NULL;
256  memset (response, 0, sizeof (struct MHD_Response));
257  response->fd = -1;
258  response->data = (void *) &response[1];
259  response->data_buffer_size = block_size;
260  if (MHD_YES != MHD_mutex_create_ (&response->mutex))
261  {
262  free (response);
263  return NULL;
264  }
265  response->crc = crc;
266  response->crfc = crfc;
267  response->crc_cls = crc_cls;
268  response->reference_count = 1;
269  response->total_size = size;
270  return response;
271 }
272 
273 
282 int
285  ...)
286 {
287  va_list ap;
288  int ret;
289  enum MHD_ResponseOptions ro;
290 
291  ret = MHD_YES;
292  response->flags = flags;
293  va_start (ap, flags);
294  while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
295  {
296  switch (ro)
297  {
298  default:
299  ret = MHD_NO;
300  break;
301  }
302  }
303  va_end (ap);
304  return ret;
305 }
306 
307 
318 static ssize_t
319 file_reader (void *cls, uint64_t pos, char *buf, size_t max)
320 {
321  struct MHD_Response *response = cls;
322  ssize_t n;
323  const int64_t offset64 = (int64_t)(pos + response->fd_off);
324 
325  if (offset64 < 0)
326  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
327 
328 #if defined(HAVE_LSEEK64)
329  if (lseek64 (response->fd, offset64, SEEK_SET) != offset64)
330  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
331 #elif defined(HAVE___LSEEKI64)
332  if (_lseeki64 (response->fd, offset64, SEEK_SET) != offset64)
333  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
334 #else /* !HAVE___LSEEKI64 */
335  if (sizeof(off_t) < sizeof(uint64_t) && offset64 > (uint64_t)INT32_MAX)
336  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
337 
338  if (lseek (response->fd, (off_t)offset64, SEEK_SET) != (off_t)offset64)
339  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
340 #endif
341 
342 #ifndef _WIN32
343  if (max > SSIZE_MAX)
344  max = SSIZE_MAX;
345 
346  n = read (response->fd, buf, max);
347 #else /* _WIN32 */
348  if (max > INT32_MAX)
349  max = INT32_MAX;
350 
351  n = read (response->fd, buf, (unsigned int)max);
352 #endif /* _WIN32 */
353 
354  if (0 == n)
356  if (n < 0)
358  return n;
359 }
360 
361 
368 static void
369 free_callback (void *cls)
370 {
371  struct MHD_Response *response = cls;
372 
373  (void) close (response->fd);
374  response->fd = -1;
375 }
376 
377 #undef MHD_create_response_from_fd_at_offset
378 
395 struct MHD_Response *
397  int fd,
398  off_t offset)
399 {
400  return MHD_create_response_from_fd_at_offset64 (size, fd, offset);
401 }
402 
403 
420 _MHD_EXTERN struct MHD_Response *
422  int fd,
423  uint64_t offset)
424 {
425  struct MHD_Response *response;
426 
427 #if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
428  if (sizeof(uint64_t) > sizeof(off_t) &&
429  (size > (uint64_t)INT32_MAX || offset > (uint64_t)INT32_MAX || (size + offset) >= (uint64_t)INT32_MAX))
430  return NULL;
431 #endif
432  if ((int64_t)size < 0 || (int64_t)offset < 0 || (int64_t)(size + offset) < 0)
433  return NULL;
434 
435  response = MHD_create_response_from_callback (size,
436  4 * 1024,
437  &file_reader,
438  NULL,
439  &free_callback);
440  if (NULL == response)
441  return NULL;
442  response->fd = fd;
443  response->fd_off = offset;
444  response->crc_cls = response;
445  return response;
446 }
447 
448 
458 struct MHD_Response *
460  int fd)
461 {
462  return MHD_create_response_from_fd_at_offset64 (size, fd, 0);
463 }
464 
465 
479 _MHD_EXTERN struct MHD_Response *
481  int fd)
482 {
483  return MHD_create_response_from_fd_at_offset64 (size, fd, 0);
484 }
485 
486 
501 struct MHD_Response *
503  void *data, int must_free, int must_copy)
504 {
505  struct MHD_Response *response;
506  void *tmp;
507 
508  if ((NULL == data) && (size > 0))
509  return NULL;
510  if (NULL == (response = malloc (sizeof (struct MHD_Response))))
511  return NULL;
512  memset (response, 0, sizeof (struct MHD_Response));
513  response->fd = -1;
514  if (MHD_YES != MHD_mutex_create_ (&response->mutex))
515  {
516  free (response);
517  return NULL;
518  }
519  if ((must_copy) && (size > 0))
520  {
521  if (NULL == (tmp = malloc (size)))
522  {
523  (void) MHD_mutex_destroy_ (&response->mutex);
524  free (response);
525  return NULL;
526  }
527  memcpy (tmp, data, size);
528  must_free = MHD_YES;
529  data = tmp;
530  }
531  response->crc = NULL;
532  response->crfc = must_free ? &free : NULL;
533  response->crc_cls = must_free ? data : NULL;
534  response->reference_count = 1;
535  response->total_size = size;
536  response->data = data;
537  response->data_size = size;
538  return response;
539 }
540 
541 
552 struct MHD_Response *
554  void *buffer,
555  enum MHD_ResponseMemoryMode mode)
556 {
557  return MHD_create_response_from_data (size,
558  buffer,
559  mode == MHD_RESPMEM_MUST_FREE,
560  mode == MHD_RESPMEM_MUST_COPY);
561 }
562 
563 
573 void
575 {
576  struct MHD_HTTP_Header *pos;
577 
578  if (NULL == response)
579  return;
580  (void) MHD_mutex_lock_ (&response->mutex);
581  if (0 != --(response->reference_count))
582  {
583  (void) MHD_mutex_unlock_ (&response->mutex);
584  return;
585  }
586  (void) MHD_mutex_unlock_ (&response->mutex);
587  (void) MHD_mutex_destroy_ (&response->mutex);
588  if (response->crfc != NULL)
589  response->crfc (response->crc_cls);
590  while (NULL != response->first_header)
591  {
592  pos = response->first_header;
593  response->first_header = pos->next;
594  free (pos->header);
595  free (pos->value);
596  free (pos);
597  }
598  free (response);
599 }
600 
601 
602 void
604 {
605  (void) MHD_mutex_lock_ (&response->mutex);
606  (response->reference_count)++;
607  (void) MHD_mutex_unlock_ (&response->mutex);
608 }
609 
610 
611 /* end of response.c */
int(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
Definition: microhttpd.h:1415
int MHD_set_response_options(struct MHD_Response *response, enum MHD_ResponseFlags flags,...)
Definition: response.c:283
uint64_t total_size
Definition: internal.h:289
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_callback(uint64_t size, size_t block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc)
Definition: response.c:244
uint64_t fd_off
Definition: internal.h:300
static void free_callback(void *cls)
Definition: response.c:369
void * data
Definition: microhttpd.h:2035
_MHD_EXTERN int MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:103
#define NULL
Definition: reason_phrase.c:30
void int int must_copy
Definition: microhttpd.h:2035
MHD_ContentReaderFreeCallback crfc
Definition: internal.h:278
void(* MHD_ContentReaderFreeCallback)(void *cls)
Definition: microhttpd.h:1482
static ssize_t file_reader(void *cls, uint64_t pos, char *buf, size_t max)
Definition: response.c:319
#define MHD_YES
Definition: microhttpd.h:138
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd64(uint64_t size, int fd)
Definition: response.c:480
size_t data_size
Definition: internal.h:306
enum MHD_ValueKind kind
Definition: internal.h:238
struct MHD_HTTP_Header * first_header
Definition: internal.h:254
char * value
Definition: internal.h:232
Methods for managing response objects.
Signatures for IO functions.
MHD_ResponseOptions
Definition: microhttpd.h:1972
size_t data_buffer_size
Definition: internal.h:311
int fd
Definition: microhttpd.h:2145
internal shared structures
_MHD_EXTERN int MHD_add_response_footer(struct MHD_Response *response, const char *footer, const char *content)
Definition: response.c:123
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd_at_offset64(uint64_t size, int fd, uint64_t offset)
Definition: response.c:421
#define _MHD_EXTERN
Definition: microhttpd.h:175
ssize_t(* MHD_ContentReaderCallback)(void *cls, uint64_t pos, char *buf, size_t max)
Definition: microhttpd.h:1466
unsigned int reference_count
Definition: internal.h:317
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition: response.c:574
void MHD_increment_response_rc(struct MHD_Response *response)
Definition: response.c:603
void int must_free
Definition: microhttpd.h:2035
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:164
struct MHD_Response * MHD_create_response_from_data(size_t size, void *data, int must_free, int must_copy)
Definition: response.c:502
MHD_ValueKind
Definition: microhttpd.h:997
limits values definitions
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd(size_t size, int fd)
Definition: response.c:459
#define INT32_MAX
Definition: mhd_limits.h:44
int off_t offset
Definition: microhttpd.h:2145
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition: response.c:553
static int add_response_entry(struct MHD_Response *response, enum MHD_ValueKind kind, const char *header, const char *content)
Definition: response.c:54
char * header
Definition: internal.h:227
enum MHD_ResponseFlags flags
Definition: internal.h:327
struct MHD_HTTP_Header * next
Definition: internal.h:221
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:165
MHD_ContentReaderCallback crc
Definition: internal.h:272
void * crc_cls
Definition: internal.h:266
MHD_mutex_ mutex
Definition: internal.h:284
char * data
Definition: internal.h:260
_MHD_EXTERN int MHD_del_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition: response.c:143
#define MHD_NO
Definition: microhttpd.h:143
MHD_ResponseFlags
Definition: microhttpd.h:1952
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition: response.c:213
struct MHD_Response * MHD_create_response_from_fd_at_offset(size_t size, int fd, off_t offset)
Definition: response.c:396
_MHD_EXTERN int MHD_get_response_headers(struct MHD_Response *response, MHD_KeyValueIterator iterator, void *iterator_cls)
Definition: response.c:186
MHD_ResponseMemoryMode
Definition: microhttpd.h:2045