GNU libmicrohttpd 0.9.77
Loading...
Searching...
No Matches
response.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2021 Daniel Pittman and Christian Grothoff
4 Copyright (C) 2015-2021 Evgeny Grin (Karlson2k)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
28#define MHD_NO_DEPRECATION 1
29
30#include "mhd_options.h"
31#ifdef HAVE_SYS_IOCTL_H
32#include <sys/ioctl.h>
33#endif /* HAVE_SYS_IOCTL_H */
34#if defined(_WIN32) && ! defined(__CYGWIN__)
35#include <windows.h>
36#endif /* _WIN32 && !__CYGWIN__ */
37
38#include "internal.h"
39#include "response.h"
40#include "mhd_limits.h"
41#include "mhd_sockets.h"
42#include "mhd_itc.h"
43#include "mhd_str.h"
44#include "connection.h"
45#include "memorypool.h"
46#include "mhd_send.h"
47#include "mhd_compat.h"
48#include "mhd_assert.h"
49
50
51#if defined(MHD_W32_MUTEX_)
52#ifndef WIN32_LEAN_AND_MEAN
53#define WIN32_LEAN_AND_MEAN 1
54#endif /* !WIN32_LEAN_AND_MEAN */
55#include <windows.h>
56#endif /* MHD_W32_MUTEX_ */
57#if defined(_WIN32)
58#include <io.h> /* for lseek(), read() */
59#endif /* _WIN32 */
60
61
66#ifndef MHD_FILE_READ_BLOCK_SIZE
67#ifdef _WIN32
68#define MHD_FILE_READ_BLOCK_SIZE 16384 /* 16k */
69#else /* _WIN32 */
70#define MHD_FILE_READ_BLOCK_SIZE 4096 /* 4k */
71#endif /* _WIN32 */
72#endif /* !MHD_FD_BLOCK_SIZE */
73
77#define _MHD_insert_header_first(presponse, phdr) do { \
78 mhd_assert (NULL == phdr->next); \
79 mhd_assert (NULL == phdr->prev); \
80 if (NULL == presponse->first_header) \
81 { \
82 mhd_assert (NULL == presponse->last_header); \
83 presponse->first_header = phdr; \
84 presponse->last_header = phdr; \
85 } \
86 else \
87 { \
88 mhd_assert (NULL != presponse->last_header); \
89 presponse->first_header->prev = phdr; \
90 phdr->next = presponse->first_header; \
91 presponse->first_header = phdr; \
92 } \
93} while (0)
94
98#define _MHD_insert_header_last(presponse, phdr) do { \
99 mhd_assert (NULL == phdr->next); \
100 mhd_assert (NULL == phdr->prev); \
101 if (NULL == presponse->last_header) \
102 { \
103 mhd_assert (NULL == presponse->first_header); \
104 presponse->last_header = phdr; \
105 presponse->first_header = phdr; \
106 } \
107 else \
108 { \
109 mhd_assert (NULL != presponse->first_header); \
110 presponse->last_header->next = phdr; \
111 phdr->prev = presponse->last_header; \
112 presponse->last_header = phdr; \
113 } \
114} while (0)
115
116
120#define _MHD_remove_header(presponse, phdr) do { \
121 mhd_assert (NULL != presponse->first_header); \
122 mhd_assert (NULL != presponse->last_header); \
123 if (NULL == phdr->prev) \
124 { \
125 mhd_assert (phdr == presponse->first_header); \
126 presponse->first_header = phdr->next; \
127 } \
128 else \
129 { \
130 mhd_assert (phdr != presponse->first_header); \
131 mhd_assert (phdr == phdr->prev->next); \
132 phdr->prev->next = phdr->next; \
133 } \
134 if (NULL == phdr->next) \
135 { \
136 mhd_assert (phdr == presponse->last_header); \
137 presponse->last_header = phdr->prev; \
138 } \
139 else \
140 { \
141 mhd_assert (phdr != presponse->last_header); \
142 mhd_assert (phdr == phdr->next->prev); \
143 phdr->next->prev = phdr->prev; \
144 } \
145} while (0)
146
156static enum MHD_Result
158 enum MHD_ValueKind kind,
159 const char *header,
160 const char *content)
161{
162 struct MHD_HTTP_Header *hdr;
163
164 if ( (NULL == response) ||
165 (NULL == header) ||
166 (NULL == content) ||
167 (0 == header[0]) ||
168 (0 == content[0]) ||
169 (NULL != strchr (header, '\t')) ||
170 (NULL != strchr (header, ' ')) ||
171 (NULL != strchr (header, '\r')) ||
172 (NULL != strchr (header, '\n')) ||
173 (NULL != strchr (content, '\r')) ||
174 (NULL != strchr (content, '\n')) )
175 return MHD_NO;
176 if (NULL == (hdr = MHD_calloc_ (1, sizeof (struct MHD_HTTP_Header))))
177 return MHD_NO;
178 if (NULL == (hdr->header = strdup (header)))
179 {
180 free (hdr);
181 return MHD_NO;
182 }
183 hdr->header_size = strlen (header);
184 if (NULL == (hdr->value = strdup (content)))
185 {
186 free (hdr->header);
187 free (hdr);
188 return MHD_NO;
189 }
190 hdr->value_size = strlen (content);
191 hdr->kind = kind;
192 _MHD_insert_header_last (response, hdr);
193 return MHD_YES;
194}
195
196
208static enum MHD_Result
210 const char *value)
211{
212 static const char *key = MHD_HTTP_HEADER_CONNECTION;
214 static const size_t key_len =
216 size_t value_len;
217 size_t old_value_len;
218 size_t buf_size;
219 ssize_t norm_len;
220 char *buf;
221 struct MHD_HTTP_Header *hdr;
222 bool value_has_close;
223 bool already_has_close;
224 size_t pos = 0;
226 if ( (NULL != strchr (value, '\r')) ||
227 (NULL != strchr (value, '\n')) )
228 return MHD_NO;
229
230 if (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
231 {
233 key, key_len);
234 already_has_close =
235 (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE));
236 mhd_assert (already_has_close == (0 == memcmp (hdr->value, "close", 5)));
237 mhd_assert (NULL != hdr);
238 }
239 else
240 {
241 hdr = NULL;
242 already_has_close = false;
245 key, key_len));
247 }
248 if (NULL != hdr)
249 old_value_len = hdr->value_size + 2; /* additional size for ", " */
250 else
251 old_value_len = 0;
252
253 value_len = strlen (value);
254 if (value_len >= SSIZE_MAX)
255 return MHD_NO;
256 /* Additional space for normalisation and zero-termination*/
257 norm_len = (ssize_t) (value_len + value_len / 2 + 1);
258 buf_size = old_value_len + (size_t) norm_len;
259
260 buf = malloc (buf_size);
261 if (NULL == buf)
262 return MHD_NO;
263 /* Remove "close" token (if any), it will be moved to the front */
264 value_has_close = MHD_str_remove_token_caseless_ (value, value_len, "close",
266 "close"),
267 buf + old_value_len,
268 &norm_len);
269#ifdef UPGRADE_SUPPORT
270 if ( (NULL != response->upgrade_handler) && value_has_close)
271 { /* The "close" token cannot be used with connection "upgrade" */
272 free (buf);
273 return MHD_NO;
274 }
275#endif /* UPGRADE_SUPPORT */
276 mhd_assert (0 <= norm_len);
277 if (0 > norm_len)
278 norm_len = 0; /* Must never happen */
279 if (0 != norm_len)
280 {
281 size_t len = norm_len;
282 MHD_str_remove_tokens_caseless_ (buf + old_value_len, &len,
283 "keep-alive",
284 MHD_STATICSTR_LEN_ ("keep-alive"));
285 norm_len = (ssize_t) len;
286 }
287 if (0 == norm_len)
288 { /* New value is empty after normalisation */
289 if (! value_has_close)
290 { /* The new value had no tokens */
291 free (buf);
292 return MHD_NO;
293 }
294 if (already_has_close)
295 { /* The "close" token is already present, nothing to modify */
296 free (buf);
297 return MHD_YES;
298 }
299 }
300 /* Add "close" token if required */
301 if (value_has_close && ! already_has_close)
302 {
303 /* Need to insert "close" token at the first position */
304 mhd_assert (buf_size >= old_value_len + (size_t) norm_len \
305 + MHD_STATICSTR_LEN_ ("close, ") + 1);
306 if (0 != norm_len)
307 memmove (buf + MHD_STATICSTR_LEN_ ("close, ") + old_value_len,
308 buf + old_value_len, norm_len + 1);
309 memcpy (buf, "close", MHD_STATICSTR_LEN_ ("close"));
310 pos += MHD_STATICSTR_LEN_ ("close");
311 }
312 /* Add old value tokens (if any) */
313 if (0 != old_value_len)
314 {
315 if (0 != pos)
316 {
317 buf[pos++] = ',';
318 buf[pos++] = ' ';
319 }
320 memcpy (buf + pos, hdr->value,
321 hdr->value_size);
322 pos += hdr->value_size;
323 }
324 /* Add new value token (if any) */
325 if (0 != norm_len)
326 {
327 if (0 != pos)
328 {
329 buf[pos++] = ',';
330 buf[pos++] = ' ';
331 }
332 /* The new value tokens must be already at the correct position */
333 mhd_assert ((value_has_close && ! already_has_close) ? \
334 (MHD_STATICSTR_LEN_ ("close, ") + old_value_len == pos) : \
335 (old_value_len == pos));
336 pos += (size_t) norm_len;
337 }
338 mhd_assert (buf_size > pos);
339 buf[pos] = 0; /* Null terminate the result */
340
341 if (NULL == hdr)
342 {
343 struct MHD_HTTP_Header *new_hdr;
344 /* Create new response header entry */
345 new_hdr = MHD_calloc_ (1, sizeof (struct MHD_HTTP_Header));
346 if (NULL != new_hdr)
347 {
348 new_hdr->header = malloc (key_len + 1);
349 if (NULL != new_hdr->header)
350 {
351 memcpy (new_hdr->header, key, key_len + 1);
352 new_hdr->header_size = key_len;
353 new_hdr->value = buf;
354 new_hdr->value_size = pos;
355 new_hdr->kind = MHD_HEADER_KIND;
356 if (value_has_close)
359 else
361 _MHD_insert_header_first (response, new_hdr);
362 return MHD_YES;
363 }
364 free (new_hdr);
365 }
366 free (buf);
367 return MHD_NO;
368 }
369
370 /* Update existing header entry */
371 free (hdr->value);
372 hdr->value = buf;
373 hdr->value_size = pos;
374 if (value_has_close && ! already_has_close)
376 return MHD_YES;
377}
378
379
389static enum MHD_Result
391 const char *value)
392{
393 struct MHD_HTTP_Header *hdr;
399 if (NULL == hdr)
400 return MHD_NO;
401
403 strlen (value)))
404 return MHD_NO;
405 if (0 == hdr->value_size)
406 {
407 _MHD_remove_header (response, hdr);
408 free (hdr->value);
409 free (hdr->header);
410 free (hdr);
411 response->flags_auto &=
414 }
415 else
416 {
417 hdr->value[hdr->value_size] = 0; /* Null-terminate the result */
418 if (0 != (response->flags_auto
420 {
421 if (MHD_STATICSTR_LEN_ ("close") == hdr->value_size)
422 {
423 if (0 != memcmp (hdr->value, "close", MHD_STATICSTR_LEN_ ("close")))
424 response->flags_auto &=
426 }
427 else if (MHD_STATICSTR_LEN_ ("close, ") < hdr->value_size)
428 {
429 if (0 != memcmp (hdr->value, "close, ",
430 MHD_STATICSTR_LEN_ ("close, ")))
431 response->flags_auto &=
433 }
434 else
435 response->flags_auto &=
437 }
438 }
439 return MHD_YES;
440}
441
442
492enum MHD_Result
494 const char *header,
495 const char *content)
496{
498 return add_response_header_connection (response, content);
499
502 {
503 if (! MHD_str_equal_caseless_ (content, "chunked"))
504 return MHD_NO;
505 if (0 != (response->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED))
506 return MHD_YES;
507 if (MHD_NO != add_response_entry (response,
509 header,
510 content))
511 {
513 return MHD_YES;
514 }
515 return MHD_NO;
516 }
519 {
520 if (0 != (response->flags_auto & MHD_RAF_HAS_DATE_HDR))
521 {
522 struct MHD_HTTP_Header *hdr;
527 mhd_assert (NULL != hdr);
528 _MHD_remove_header (response, hdr);
529 if (NULL != hdr->value)
530 free (hdr->value);
531 free (hdr->header);
532 free (hdr);
533 }
534 if (MHD_NO != add_response_entry (response,
536 header,
537 content))
538 {
539 response->flags_auto |= MHD_RAF_HAS_DATE_HDR;
540 return MHD_YES;
541 }
542 return MHD_NO;
543 }
545 & response->flags)) &&
548 {
549 /* MHD will set Content-length if allowed and possible,
550 reject attempt by application */
551 return MHD_NO;
552 }
553
554 return add_response_entry (response,
556 header,
557 content);
558}
559
560
570enum MHD_Result
572 const char *footer,
573 const char *content)
574{
575 return add_response_entry (response,
577 footer,
578 content);
579}
580
581
596enum MHD_Result
598 const char *header,
599 const char *content)
600{
601 struct MHD_HTTP_Header *pos;
602 size_t header_len;
603 size_t content_len;
604
605 if ( (NULL == header) ||
606 (NULL == content) )
607 return MHD_NO;
608 header_len = strlen (header);
609
610 if ((0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR)) &&
613 header_len))
614 return del_response_header_connection (response, content);
615
616 content_len = strlen (content);
617 pos = response->first_header;
618 while (NULL != pos)
619 {
620 if ((header_len == pos->header_size) &&
621 (content_len == pos->value_size) &&
622 (0 == memcmp (header,
623 pos->header,
624 header_len)) &&
625 (0 == memcmp (content,
626 pos->value,
627 content_len)))
628 {
629 _MHD_remove_header (response, pos);
630 free (pos->header);
631 free (pos->value);
632 free (pos);
634 header_len) &&
637 header_len) )
638 response->flags_auto &=
641 header_len) &&
644 header_len) )
645 response->flags_auto &=
647 return MHD_YES;
648 }
649 pos = pos->next;
650 }
651 return MHD_NO;
652}
653
654
665int
667 MHD_KeyValueIterator iterator,
668 void *iterator_cls)
669{
670 int numHeaders = 0;
671 struct MHD_HTTP_Header *pos;
672
673 for (pos = response->first_header;
674 NULL != pos;
675 pos = pos->next)
676 {
677 numHeaders++;
678 if ((NULL != iterator) &&
679 (MHD_NO == iterator (iterator_cls,
680 pos->kind,
681 pos->header,
682 pos->value)))
683 break;
684 }
685 return numHeaders;
686}
687
688
697const char *
699 const char *key)
700{
701 struct MHD_HTTP_Header *pos;
702 size_t key_size;
703
704 if (NULL == key)
705 return NULL;
706
707 key_size = strlen (key);
708 for (pos = response->first_header;
709 NULL != pos;
710 pos = pos->next)
711 {
712 if ((pos->header_size == key_size) &&
714 return pos->value;
715 }
716 return NULL;
717}
718
719
731struct MHD_HTTP_Header *
733 enum MHD_ValueKind kind,
734 const char *key,
735 size_t key_len)
736{
737 struct MHD_HTTP_Header *pos;
738
739 mhd_assert (NULL != key);
740 mhd_assert (0 != key[0]);
741 mhd_assert (0 != key_len);
742
743 for (pos = response->first_header;
744 NULL != pos;
745 pos = pos->next)
746 {
747 if ((pos->header_size == key_len) &&
748 (kind == pos->kind) &&
750 return pos;
751 }
752 return NULL;
753}
754
755
772bool
774 const char *key,
775 size_t key_len,
776 const char *token,
777 size_t token_len)
778{
779 struct MHD_HTTP_Header *pos;
780
781 if ( (NULL == key) ||
782 ('\0' == key[0]) ||
783 (NULL == token) ||
784 ('\0' == token[0]) )
785 return false;
786
787 /* Token must not contain binary zero! */
788 mhd_assert (strlen (token) == token_len);
789
790 for (pos = response->first_header;
791 NULL != pos;
792 pos = pos->next)
793 {
794 if ( (pos->kind == MHD_HEADER_KIND) &&
795 (key_len == pos->header_size) &&
797 key,
798 key_len) &&
800 token,
801 token_len) )
802 return true;
803 }
804 return false;
805}
806
807
824struct MHD_Response *
826 size_t block_size,
828 void *crc_cls,
830{
831 struct MHD_Response *response;
832
833 if ((NULL == crc) || (0 == block_size))
834 return NULL;
835 if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response)
836 + block_size)))
837 return NULL;
838 response->fd = -1;
839 response->data = (void *) &response[1];
840 response->data_buffer_size = block_size;
841#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
842 if (! MHD_mutex_init_ (&response->mutex))
843 {
844 free (response);
845 return NULL;
846 }
847#endif
848 response->crc = crc;
849 response->crfc = crfc;
850 response->crc_cls = crc_cls;
851 response->reference_count = 1;
852 response->total_size = size;
853 return response;
854}
855
856
865enum MHD_Result
868 ...)
869{
870 va_list ap;
871 enum MHD_Result ret;
872 enum MHD_ResponseOptions ro;
873
874 ret = MHD_YES;
875 response->flags = flags;
876 va_start (ap, flags);
877 while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
878 {
879 switch (ro)
880 {
881 default:
882 ret = MHD_NO;
883 break;
884 }
885 }
886 va_end (ap);
887 return ret;
888}
889
890
901static ssize_t
902file_reader (void *cls,
903 uint64_t pos,
904 char *buf,
905 size_t max)
906{
907 struct MHD_Response *response = cls;
908#if ! defined(_WIN32) || defined(__CYGWIN__)
909 ssize_t n;
910#else /* _WIN32 && !__CYGWIN__ */
911 const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
912#endif /* _WIN32 && !__CYGWIN__ */
913 const int64_t offset64 = (int64_t) (pos + response->fd_off);
914
915 if (offset64 < 0)
916 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
917
918#if ! defined(_WIN32) || defined(__CYGWIN__)
919 if (max > SSIZE_MAX)
920 max = SSIZE_MAX; /* Clamp to maximum return value. */
921
922#if defined(HAVE_PREAD64)
923 n = pread64 (response->fd, buf, max, offset64);
924#elif defined(HAVE_PREAD)
925 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
926 (offset64 > (uint64_t) INT32_MAX) )
927 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
928
929 n = pread (response->fd, buf, max, (off_t) offset64);
930#else /* ! HAVE_PREAD */
931#if defined(HAVE_LSEEK64)
932 if (lseek64 (response->fd,
933 offset64,
934 SEEK_SET) != offset64)
935 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
936#else /* ! HAVE_LSEEK64 */
937 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
938 (offset64 > (uint64_t) INT32_MAX) )
939 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
940
941 if (lseek (response->fd,
942 (off_t) offset64,
943 SEEK_SET) != (off_t) offset64)
944 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
945#endif /* ! HAVE_LSEEK64 */
946 n = read (response->fd,
947 buf,
948 max);
949
950#endif /* ! HAVE_PREAD */
951 if (0 == n)
953 if (n < 0)
955 return n;
956#else /* _WIN32 && !__CYGWIN__ */
957 if (INVALID_HANDLE_VALUE == fh)
958 return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
959 else
960 {
961 OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
962 ULARGE_INTEGER pos_uli;
963 DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
964 DWORD resRead;
965
966 pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
967 f_ol.Offset = pos_uli.LowPart;
968 f_ol.OffsetHigh = pos_uli.HighPart;
969 if (! ReadFile (fh, (void *) buf, toRead, &resRead, &f_ol))
970 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
971 if (0 == resRead)
973 return (ssize_t) resRead;
974 }
975#endif /* _WIN32 && !__CYGWIN__ */
976}
977
978
989static ssize_t
990pipe_reader (void *cls,
991 uint64_t pos,
992 char *buf,
993 size_t max)
994{
995 struct MHD_Response *response = cls;
996 ssize_t n;
997
998 (void) pos;
999#ifndef _WIN32
1000 if (SSIZE_MAX < max)
1001 max = SSIZE_MAX;
1002#else /* _WIN32 */
1003 if (UINT_MAX < max)
1004 max = UINT_MAX;
1005#endif /* _WIN32 */
1006
1007 n = read (response->fd,
1008 buf,
1009 (MHD_SCKT_SEND_SIZE_) max);
1010 if (0 == n)
1012 if (n < 0)
1014 return n;
1015}
1016
1017
1024static void
1025free_callback (void *cls)
1026{
1027 struct MHD_Response *response = cls;
1028
1029 (void) close (response->fd);
1030 response->fd = -1;
1031}
1032
1033
1034#undef MHD_create_response_from_fd_at_offset
1035
1059struct MHD_Response *
1061 int fd,
1062 off_t offset)
1063{
1065 fd,
1066 offset);
1067}
1068
1069
1095 int fd,
1096 uint64_t offset)
1097{
1098 struct MHD_Response *response;
1099
1100#if ! defined(HAVE___LSEEKI64) && ! defined(HAVE_LSEEK64)
1101 if ( (sizeof(uint64_t) > sizeof(off_t)) &&
1102 ( (size > (uint64_t) INT32_MAX) ||
1103 (offset > (uint64_t) INT32_MAX) ||
1104 ((size + offset) >= (uint64_t) INT32_MAX) ) )
1105 return NULL;
1106#endif
1107 if ( ((int64_t) size < 0) ||
1108 ((int64_t) offset < 0) ||
1109 ((int64_t) (size + offset) < 0) )
1110 return NULL;
1111
1112 response = MHD_create_response_from_callback (size,
1114 &file_reader,
1115 NULL,
1116 &free_callback);
1117 if (NULL == response)
1118 return NULL;
1119 response->fd = fd;
1120 response->is_pipe = false;
1121 response->fd_off = offset;
1122 response->crc_cls = response;
1123 return response;
1124}
1125
1126
1146{
1147 struct MHD_Response *response;
1148
1151 &pipe_reader,
1152 NULL,
1153 &free_callback);
1154 if (NULL == response)
1155 return NULL;
1156 response->fd = fd;
1157 response->is_pipe = true;
1158 response->crc_cls = response;
1159 return response;
1160}
1161
1162
1179struct MHD_Response *
1181 int fd)
1182{
1184 fd,
1185 0);
1186}
1187
1188
1211 int fd)
1212{
1214 fd,
1215 0);
1216}
1217
1218
1240struct MHD_Response *
1242 void *data,
1243 int must_free,
1244 int must_copy)
1245{
1246 struct MHD_Response *response;
1247 void *tmp;
1248
1249 if ((NULL == data) && (size > 0))
1250 return NULL;
1251#if SIZEOF_SIZE_T >= SIZEOF_UINT64_T
1252 if (MHD_SIZE_UNKNOWN == size)
1253 return NULL;
1254#endif /* SIZEOF_SIZE_T >= SIZEOF_UINT64_T */
1255 if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response))))
1256 return NULL;
1257 response->fd = -1;
1258#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1259 if (! MHD_mutex_init_ (&response->mutex))
1260 {
1261 free (response);
1262 return NULL;
1263 }
1264#endif
1265 if ((must_copy) && (size > 0))
1266 {
1267 if (NULL == (tmp = malloc (size)))
1268 {
1269#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1270 MHD_mutex_destroy_chk_ (&response->mutex);
1271#endif
1272 free (response);
1273 return NULL;
1274 }
1275 memcpy (tmp, data, size);
1277 data = tmp;
1278 }
1279 if (must_free)
1280 {
1281 response->crfc = &free;
1282 response->crc_cls = data;
1283 }
1284 response->reference_count = 1;
1285 response->total_size = size;
1286 response->data = data;
1287 response->data_size = size;
1288 if (must_copy)
1289 response->data_buffer_size = size;
1290 return response;
1291}
1292
1293
1311struct MHD_Response *
1313 void *buffer,
1314 enum MHD_ResponseMemoryMode mode)
1315{
1316 return MHD_create_response_from_data (size,
1317 buffer,
1318 mode == MHD_RESPMEM_MUST_FREE,
1319 mode == MHD_RESPMEM_MUST_COPY);
1320}
1321
1322
1342 void *buffer,
1344 crfc)
1345{
1346 struct MHD_Response *r;
1347
1349 buffer,
1350 MHD_YES,
1351 MHD_NO);
1352 if (NULL == r)
1353 return r;
1354 r->crfc = crfc;
1355 return r;
1356}
1357
1358
1381 void *buffer,
1383 crfc,
1384 void *crfc_cls)
1385{
1386 struct MHD_Response *r;
1387
1389 buffer,
1390 crfc);
1391 if (NULL != r)
1392 r->crc_cls = crfc_cls;
1393 return r;
1394}
1395
1396
1418 unsigned int iovcnt,
1420 void *cls)
1421{
1422 struct MHD_Response *response;
1423 unsigned int i;
1424 int i_cp = 0;
1425 uint64_t total_size = 0;
1426 const void *last_valid_buffer = NULL;
1427
1428 if ((NULL == iov) && (0 < iovcnt))
1429 return NULL;
1430
1431 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
1432 if (NULL == response)
1433 return NULL;
1434 if (! MHD_mutex_init_ (&response->mutex))
1435 {
1436 free (response);
1437 return NULL;
1438 }
1439 /* Calculate final size, number of valid elements, and check 'iov' */
1440 for (i = 0; i < iovcnt; ++i)
1441 {
1442 if (0 == iov[i].iov_len)
1443 continue; /* skip zero-sized elements */
1444 if (NULL == iov[i].iov_base)
1445 {
1446 i_cp = -1; /* error */
1447 break;
1448 }
1449 if ( (total_size > (total_size + iov[i].iov_len)) ||
1450 (INT_MAX == i_cp) ||
1451 (SSIZE_MAX < (total_size + iov[i].iov_len)) )
1452 {
1453 i_cp = -1; /* overflow */
1454 break;
1455 }
1456 last_valid_buffer = iov[i].iov_base;
1457 total_size += iov[i].iov_len;
1458#if defined(MHD_POSIX_SOCKETS) || ! defined(_WIN64)
1459 i_cp++;
1460#else /* ! MHD_POSIX_SOCKETS && _WIN64 */
1461 {
1462 int64_t i_add;
1463
1464 i_add = iov[i].iov_len / ULONG_MAX;
1465 if (0 != iov[i].iov_len % ULONG_MAX)
1466 i_add++;
1467 if (INT_MAX < (i_add + i_cp))
1468 {
1469 i_cp = -1; /* overflow */
1470 break;
1471 }
1472 i_cp += (int) i_add;
1473 }
1474#endif /* ! MHD_POSIX_SOCKETS && _WIN64 */
1475 }
1476 if (-1 == i_cp)
1477 {
1478 /* Some error condition */
1479 MHD_mutex_destroy_chk_ (&response->mutex);
1480 free (response);
1481 return NULL;
1482 }
1483 response->fd = -1;
1484 response->reference_count = 1;
1485 response->total_size = total_size;
1486 response->crc_cls = cls;
1487 response->crfc = free_cb;
1488 if (0 == i_cp)
1489 {
1490 mhd_assert (0 == total_size);
1491 return response;
1492 }
1493 if (1 == i_cp)
1494 {
1495 mhd_assert (NULL != last_valid_buffer);
1496 response->data = (void *) last_valid_buffer;
1497 response->data_size = (size_t) total_size;
1498 return response;
1499 }
1500 mhd_assert (1 < i_cp);
1501 {
1502 MHD_iovec_ *iov_copy;
1503 int num_copy_elements = i_cp;
1504
1505 iov_copy = MHD_calloc_ (num_copy_elements,
1506 sizeof(MHD_iovec_));
1507 if (NULL == iov_copy)
1508 {
1509 MHD_mutex_destroy_chk_ (&response->mutex);
1510 free (response);
1511 return NULL;
1512 }
1513 i_cp = 0;
1514 for (i = 0; i < iovcnt; ++i)
1515 {
1516 size_t element_size = iov[i].iov_len;
1517 const uint8_t *buf = (const uint8_t *) iov[i].iov_base;
1518
1519 if (0 == element_size)
1520 continue; /* skip zero-sized elements */
1521#if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64)
1522 while (MHD_IOV_ELMN_MAX_SIZE < element_size)
1523 {
1524 iov_copy[i_cp].iov_base = (char *) buf;
1525 iov_copy[i_cp].iov_len = ULONG_MAX;
1526 buf += ULONG_MAX;
1527 element_size -= ULONG_MAX;
1528 i_cp++;
1529 }
1530#endif /* MHD_WINSOCK_SOCKETS && _WIN64 */
1531 iov_copy[i_cp].iov_base = (void *) buf;
1532 iov_copy[i_cp].iov_len = (MHD_iov_size_) element_size;
1533 i_cp++;
1534 }
1535 mhd_assert (num_copy_elements == i_cp);
1536 response->data_iov = iov_copy;
1537 response->data_iovcnt = i_cp;
1538 return response;
1539 }
1540}
1541
1542
1543#ifdef UPGRADE_SUPPORT
1557MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
1559 ...)
1560{
1561 struct MHD_Connection *connection;
1562 struct MHD_Daemon *daemon;
1563
1564 if (NULL == urh)
1565 return MHD_NO;
1566 connection = urh->connection;
1567
1568 /* Precaution checks on external data. */
1569 if (NULL == connection)
1570 return MHD_NO;
1571 daemon = connection->daemon;
1572 if (NULL == daemon)
1573 return MHD_NO;
1574
1575 switch (action)
1576 {
1578 if (urh->was_closed)
1579 return MHD_NO; /* Already closed. */
1580
1581 /* transition to special 'closed' state for start of cleanup */
1582#ifdef HTTPS_SUPPORT
1583 if (0 != (daemon->options & MHD_USE_TLS) )
1584 {
1585 /* signal that app is done by shutdown() of 'app' socket */
1586 /* Application will not use anyway this socket after this command. */
1587 shutdown (urh->app.socket,
1588 SHUT_RDWR);
1589 }
1590#endif /* HTTPS_SUPPORT */
1591 mhd_assert (MHD_CONNECTION_UPGRADE == connection->state);
1592 /* The next function will mark the connection as closed by application
1593 * by setting 'urh->was_closed'.
1594 * As soon as connection will be marked with BOTH
1595 * 'urh->was_closed' AND 'urh->clean_ready', it will
1596 * be moved to cleanup list by MHD_resume_connection(). */
1597 MHD_upgraded_connection_mark_app_closed_ (connection);
1598 return MHD_YES;
1600 /* Unportable API. TODO: replace with portable action. */
1601 return MHD_connection_set_cork_state_ (connection,
1602 true) ? MHD_YES : MHD_NO;
1604 /* Unportable API. TODO: replace with portable action. */
1605 return MHD_connection_set_cork_state_ (connection,
1606 false) ? MHD_YES : MHD_NO;
1607 default:
1608 /* we don't understand this one */
1609 return MHD_NO;
1610 }
1611}
1612
1613
1627enum MHD_Result
1629 struct MHD_Connection *connection)
1630{
1631 struct MHD_Daemon *daemon = connection->daemon;
1632 struct MHD_UpgradeResponseHandle *urh;
1633 size_t rbo;
1634
1635#ifdef MHD_USE_THREADS
1636 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
1637 MHD_thread_ID_match_current_ (connection->pid) );
1638#endif /* MHD_USE_THREADS */
1639
1640 if (0 == (daemon->options & MHD_ALLOW_UPGRADE))
1641 return MHD_NO;
1642
1643 if (NULL ==
1648 {
1649#ifdef HAVE_MESSAGES
1650 MHD_DLOG (daemon,
1651 _ ("Invalid response for upgrade: " \
1652 "application failed to set the 'Upgrade' header!\n"));
1653#endif
1654 return MHD_NO;
1655 }
1656
1657 urh = MHD_calloc_ (1, sizeof (struct MHD_UpgradeResponseHandle));
1658 if (NULL == urh)
1659 return MHD_NO;
1660 urh->connection = connection;
1661 rbo = connection->read_buffer_offset;
1662 connection->read_buffer_offset = 0;
1663 MHD_connection_set_nodelay_state_ (connection, false);
1664 MHD_connection_set_cork_state_ (connection, false);
1665#ifdef HTTPS_SUPPORT
1666 if (0 != (daemon->options & MHD_USE_TLS) )
1667 {
1668 struct MemoryPool *pool;
1669 size_t avail;
1670 char *buf;
1671 MHD_socket sv[2];
1672#if defined(MHD_socket_nosignal_) || ! defined(MHD_socket_pair_nblk_)
1673 int res1;
1674 int res2;
1675#endif /* MHD_socket_nosignal_ || !MHD_socket_pair_nblk_ */
1676
1677#ifdef MHD_socket_pair_nblk_
1678 if (! MHD_socket_pair_nblk_ (sv))
1679 {
1680 free (urh);
1681 return MHD_NO;
1682 }
1683#else /* !MHD_socket_pair_nblk_ */
1684 if (! MHD_socket_pair_ (sv))
1685 {
1686 free (urh);
1687 return MHD_NO;
1688 }
1689 res1 = MHD_socket_nonblocking_ (sv[0]);
1690 res2 = MHD_socket_nonblocking_ (sv[1]);
1691 if ( (! res1) || (! res2) )
1692 {
1693#ifdef HAVE_MESSAGES
1694 MHD_DLOG (daemon,
1695 _ ("Failed to make loopback sockets non-blocking.\n"));
1696#endif
1697 if (! res2)
1698 {
1699 /* Socketpair cannot be used. */
1700 MHD_socket_close_chk_ (sv[0]);
1701 MHD_socket_close_chk_ (sv[1]);
1702 free (urh);
1703 return MHD_NO;
1704 }
1705 }
1706#endif /* !MHD_socket_pair_nblk_ */
1707#ifdef MHD_socket_nosignal_
1708 res1 = MHD_socket_nosignal_ (sv[0]);
1709 res2 = MHD_socket_nosignal_ (sv[1]);
1710 if ( (! res1) || (! res2) )
1711 {
1712#ifdef HAVE_MESSAGES
1713 MHD_DLOG (daemon,
1714 _ ("Failed to set SO_NOSIGPIPE on loopback sockets.\n"));
1715#endif
1716#ifndef MSG_NOSIGNAL
1717 if (! res2)
1718 {
1719 /* Socketpair cannot be used. */
1720 MHD_socket_close_chk_ (sv[0]);
1721 MHD_socket_close_chk_ (sv[1]);
1722 free (urh);
1723 return MHD_NO;
1724 }
1725#endif /* ! MSG_NOSIGNAL */
1726 }
1727#endif /* MHD_socket_nosignal_ */
1728 if ( (! MHD_SCKT_FD_FITS_FDSET_ (sv[1],
1729 NULL)) &&
1730 (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) )
1731 {
1732#ifdef HAVE_MESSAGES
1733 MHD_DLOG (daemon,
1734 _ ("Socketpair descriptor larger than FD_SETSIZE: %d > %d\n"),
1735 (int) sv[1],
1736 (int) FD_SETSIZE);
1737#endif
1738 MHD_socket_close_chk_ (sv[0]);
1739 MHD_socket_close_chk_ (sv[1]);
1740 free (urh);
1741 return MHD_NO;
1742 }
1743 pool = connection->pool;
1744 if (0 != connection->write_buffer_size)
1745 {
1746 mhd_assert (NULL != connection->write_buffer);
1747 /* All data should be sent already */
1748 mhd_assert (connection->write_buffer_send_offset == \
1749 connection->write_buffer_append_offset);
1750 (void) MHD_pool_reallocate (pool, connection->write_buffer,
1751 connection->write_buffer_size, 0);
1752 connection->write_buffer_append_offset = 0;
1753 connection->write_buffer_send_offset = 0;
1754 connection->write_buffer_size = 0;
1755 }
1756 connection->write_buffer = NULL;
1757 urh->app.socket = sv[0];
1758 urh->app.urh = urh;
1759 urh->app.celi = MHD_EPOLL_STATE_UNREADY;
1760 urh->mhd.socket = sv[1];
1761 urh->mhd.urh = urh;
1762 urh->mhd.celi = MHD_EPOLL_STATE_UNREADY;
1763 avail = MHD_pool_get_free (pool);
1764 if (avail < RESERVE_EBUF_SIZE)
1765 {
1766 /* connection's pool is totally at the limit,
1767 use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
1768 avail = RESERVE_EBUF_SIZE;
1769 buf = urh->e_buf;
1770 }
1771 else
1772 {
1773 /* Normal case: grab all remaining memory from the
1774 connection's pool for the IO buffers; the connection
1775 certainly won't need it anymore as we've upgraded
1776 to another protocol. */
1777 buf = MHD_pool_allocate (pool,
1778 avail,
1779 false);
1780 }
1781 /* use half the buffer for inbound, half for outbound */
1782 urh->in_buffer_size = avail / 2;
1783 urh->out_buffer_size = avail - urh->in_buffer_size;
1784 urh->in_buffer = buf;
1785 urh->out_buffer = &buf[urh->in_buffer_size];
1786#ifdef EPOLL_SUPPORT
1787 /* Launch IO processing by the event loop */
1788 if (0 != (daemon->options & MHD_USE_EPOLL))
1789 {
1790 /* We're running with epoll(), need to add the sockets
1791 to the event set of the daemon's `epoll_upgrade_fd` */
1792 struct epoll_event event;
1793
1794 mhd_assert (-1 != daemon->epoll_upgrade_fd);
1795 /* First, add network socket */
1796 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
1797 event.data.ptr = &urh->app;
1798 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
1799 EPOLL_CTL_ADD,
1800 connection->socket_fd,
1801 &event))
1802 {
1803#ifdef HAVE_MESSAGES
1804 MHD_DLOG (daemon,
1805 _ ("Call to epoll_ctl failed: %s\n"),
1807#endif
1808 MHD_socket_close_chk_ (sv[0]);
1809 MHD_socket_close_chk_ (sv[1]);
1810 free (urh);
1811 return MHD_NO;
1812 }
1813
1814 /* Second, add our end of the UNIX socketpair() */
1815 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
1816 event.data.ptr = &urh->mhd;
1817 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
1818 EPOLL_CTL_ADD,
1819 urh->mhd.socket,
1820 &event))
1821 {
1822 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
1823 event.data.ptr = &urh->app;
1824 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
1825 EPOLL_CTL_DEL,
1826 connection->socket_fd,
1827 &event))
1828 MHD_PANIC (_ ("Error cleaning up while handling epoll error.\n"));
1829#ifdef HAVE_MESSAGES
1830 MHD_DLOG (daemon,
1831 _ ("Call to epoll_ctl failed: %s\n"),
1833#endif
1834 MHD_socket_close_chk_ (sv[0]);
1835 MHD_socket_close_chk_ (sv[1]);
1836 free (urh);
1837 return MHD_NO;
1838 }
1839 EDLL_insert (daemon->eready_urh_head,
1840 daemon->eready_urh_tail,
1841 urh);
1842 urh->in_eready_list = true;
1843 }
1844#endif /* EPOLL_SUPPORT */
1845 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) )
1846 {
1847 /* This takes care of further processing for most event loops:
1848 simply add to DLL for bi-direcitonal processing */
1849 DLL_insert (daemon->urh_head,
1850 daemon->urh_tail,
1851 urh);
1852 }
1853 /* In thread-per-connection mode, thread will switch to forwarding once
1854 * connection.urh is not NULL and connection.state == MHD_CONNECTION_UPGRADE.
1855 */
1856 }
1857 else
1858 {
1859 urh->app.socket = MHD_INVALID_SOCKET;
1860 urh->mhd.socket = MHD_INVALID_SOCKET;
1861 /* Non-TLS connection do not hold any additional resources. */
1862 urh->clean_ready = true;
1863 }
1864#else /* ! HTTPS_SUPPORT */
1865 urh->clean_ready = true;
1866#endif /* ! HTTPS_SUPPORT */
1867 connection->urh = urh;
1868 /* As far as MHD's event loops are concerned, this connection is
1869 suspended; it will be resumed once application is done by the
1870 #MHD_upgrade_action() function */
1871 internal_suspend_connection_ (connection);
1872
1873 /* hand over socket to application */
1874 response->upgrade_handler (response->upgrade_handler_cls,
1875 connection,
1876 connection->client_context,
1877 connection->read_buffer,
1878 rbo,
1879#ifdef HTTPS_SUPPORT
1880 (0 == (daemon->options & MHD_USE_TLS) ) ?
1881 connection->socket_fd : urh->app.socket,
1882#else /* ! HTTPS_SUPPORT */
1883 connection->socket_fd,
1884#endif /* ! HTTPS_SUPPORT */
1885 urh);
1886 return MHD_YES;
1887}
1888
1889
1921 void *upgrade_handler_cls)
1922{
1923 struct MHD_Response *response;
1924
1925 if (NULL == upgrade_handler)
1926 return NULL; /* invalid request */
1927 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
1928 if (NULL == response)
1929 return NULL;
1930#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1931 if (! MHD_mutex_init_ (&response->mutex))
1932 {
1933 free (response);
1934 return NULL;
1935 }
1936#endif
1937 response->upgrade_handler = upgrade_handler;
1938 response->upgrade_handler_cls = upgrade_handler_cls;
1939 response->total_size = MHD_SIZE_UNKNOWN;
1940 response->reference_count = 1;
1941 if (MHD_NO ==
1942 MHD_add_response_header (response,
1944 "Upgrade"))
1945 {
1946 MHD_destroy_response (response);
1947 return NULL;
1948 }
1949 return response;
1950}
1951
1952
1953#endif /* UPGRADE_SUPPORT */
1954
1955
1965void
1967{
1968 struct MHD_HTTP_Header *pos;
1969
1970 if (NULL == response)
1971 return;
1972#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1973 MHD_mutex_lock_chk_ (&response->mutex);
1974#endif
1975 if (0 != --(response->reference_count))
1976 {
1977#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1978 MHD_mutex_unlock_chk_ (&response->mutex);
1979#endif
1980 return;
1981 }
1982#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1983 MHD_mutex_unlock_chk_ (&response->mutex);
1984 MHD_mutex_destroy_chk_ (&response->mutex);
1985#endif
1986 if (NULL != response->crfc)
1987 response->crfc (response->crc_cls);
1988
1989 if (NULL != response->data_iov)
1990 {
1991 free (response->data_iov);
1992 }
1993
1994 while (NULL != response->first_header)
1995 {
1996 pos = response->first_header;
1997 response->first_header = pos->next;
1998 free (pos->header);
1999 free (pos->value);
2000 free (pos);
2001 }
2002 free (response);
2003}
2004
2005
2011void
2013{
2014#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2015 MHD_mutex_lock_chk_ (&response->mutex);
2016#endif
2017 (response->reference_count)++;
2018#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2019 MHD_mutex_unlock_chk_ (&response->mutex);
2020#endif
2021}
2022
2023
2024/* end of response.c */
Methods for managing connections.
void internal_suspend_connection_(struct MHD_Connection *connection)
Definition daemon.c:3110
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition microhttpd.h:612
#define MHD_HTTP_HEADER_CONNECTION
Definition microhttpd.h:606
#define MHD_HTTP_HEADER_DATE
Definition microhttpd.h:620
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition microhttpd.h:674
#define MHD_HTTP_HEADER_UPGRADE
Definition microhttpd.h:676
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
_MHD_EXTERN enum MHD_Result MHD_del_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:597
struct MHD_Response * MHD_create_response_from_data(size_t size, void *data, int must_free, int must_copy)
Definition response.c:1241
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback(size_t size, void *buffer, MHD_ContentReaderFreeCallback crfc)
Definition response.c:1341
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_iovec(const struct MHD_IoVec *iov, unsigned int iovcnt, MHD_ContentReaderFreeCallback free_cb, void *cls)
Definition response.c:1417
_MHD_EXTERN enum MHD_Result MHD_add_response_footer(struct MHD_Response *response, const char *footer, const char *content)
Definition response.c:571
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd(size_t size, int fd)
Definition response.c:1180
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_pipe(int fd)
Definition response.c:1145
struct MHD_HTTP_Header * MHD_get_response_element_n_(struct MHD_Response *response, enum MHD_ValueKind kind, const char *key, size_t key_len)
Definition response.c:732
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition response.c:1312
_MHD_EXTERN int MHD_get_response_headers(struct MHD_Response *response, MHD_KeyValueIterator iterator, void *iterator_cls)
Definition response.c:666
_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:825
MHD_ResponseMemoryMode
void(* MHD_ContentReaderFreeCallback)(void *cls)
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd_at_offset64(uint64_t size, int fd, uint64_t offset)
Definition response.c:1094
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition response.c:1966
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:493
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition response.c:698
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd64(uint64_t size, int fd)
Definition response.c:1210
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback_cls(size_t size, void *buffer, MHD_ContentReaderFreeCallback crfc, void *crfc_cls)
Definition response.c:1380
@ MHD_RESPMEM_MUST_FREE
@ MHD_RESPMEM_MUST_COPY
@ MHD_EPOLL_STATE_UNREADY
Definition internal.h:594
#define DLL_insert(head, tail, element)
Definition internal.h:1743
#define EDLL_insert(head, tail, element)
Definition internal.h:1829
#define MHD_PANIC(msg)
Definition internal.h:69
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition memorypool.c:248
size_t MHD_pool_get_free(struct MemoryPool *pool)
Definition memorypool.c:185
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition memorypool.c:203
#define mhd_assert(CHK)
Definition mhd_assert.h:39
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition mhd_compat.c:98
#define INT32_MAX
Definition mhd_limits.h:65
#define UINT_MAX
Definition mhd_limits.h:45
#define MHD_mutex_unlock_chk_(pmutex)
Definition mhd_locks.h:180
#define MHD_mutex_destroy_chk_(pmutex)
Definition mhd_locks.h:121
#define MHD_mutex_lock_chk_(pmutex)
Definition mhd_locks.h:154
int MHD_socket_nonblocking_(MHD_socket sock)
size_t MHD_SCKT_SEND_SIZE_
#define MHD_socket_last_strerr_()
#define MHD_socket_close_chk_(fd)
#define MHD_SCKT_FD_FITS_FDSET_(fd, pset)
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition mhd_str.c:346
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition mhd_str.c:412
#define MHD_STATICSTR_LEN_(macro)
Definition mhd_str.h:45
#define NULL
static bool add_response_entry(struct MHD_Response *response, enum MHD_ValueKind kind, const char *header, const char *content)
Definition response.c:40
additional automatic macros for MHD_config.h
#define _(String)
Definition mhd_options.h:42
#define _MHD_EXTERN
Definition mhd_options.h:50
bool MHD_connection_set_cork_state_(struct MHD_Connection *connection, bool cork_state)
Definition mhd_send.c:240
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition mhd_send.c:170
Declarations of send() wrappers.
MHD internal shared structures.
size_t MHD_iov_size_
Definition internal.h:403
MHD_ResponseAutoFlags
Definition internal.h:367
@ MHD_RAF_HAS_DATE_HDR
Definition internal.h:372
@ MHD_RAF_HAS_CONNECTION_CLOSE
Definition internal.h:370
@ MHD_RAF_HAS_TRANS_ENC_CHUNKED
Definition internal.h:371
@ MHD_RAF_HAS_CONNECTION_HDR
Definition internal.h:369
#define MHD_IOV_ELMN_MAX_SIZE
Definition internal.h:402
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
macros for mhd_assert()
Header for platform missing functions.
Header for platform-independent inter-thread communication.
limits values definitions
#define SSIZE_MAX
Definition mhd_limits.h:113
#define MHD_mutex_init_(ignore)
Definition mhd_locks.h:191
bool MHD_str_remove_tokens_caseless_(char *str, size_t *str_len, const char *const tokens, const size_t tokens_len)
Definition mhd_str.c:720
bool MHD_str_remove_token_caseless_(const char *str, size_t str_len, const char *const token, const size_t token_len, char *buf, ssize_t *buf_size)
Definition mhd_str.c:553
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition mhd_str.c:445
Header for string manipulating helpers.
static void free_callback(void *cls)
Definition response.c:1025
#define MHD_FILE_READ_BLOCK_SIZE
Definition response.c:70
bool MHD_check_response_header_token_ci(const struct MHD_Response *response, const char *key, size_t key_len, const char *token, size_t token_len)
Definition response.c:773
#define _MHD_insert_header_last(presponse, phdr)
Definition response.c:98
#define _MHD_remove_header(presponse, phdr)
Definition response.c:120
static enum MHD_Result add_response_header_connection(struct MHD_Response *response, const char *value)
Definition response.c:209
#define _MHD_insert_header_first(presponse, phdr)
Definition response.c:77
static ssize_t file_reader(void *cls, uint64_t pos, char *buf, size_t max)
Definition response.c:902
static enum MHD_Result del_response_header_connection(struct MHD_Response *response, const char *value)
Definition response.c:390
enum MHD_Result MHD_set_response_options(struct MHD_Response *response, enum MHD_ResponseFlags flags,...)
Definition response.c:866
static ssize_t pipe_reader(void *cls, uint64_t pos, char *buf, size_t max)
Definition response.c:990
void MHD_increment_response_rc(struct MHD_Response *response)
Definition response.c:2012
int MHD_socket
Definition microhttpd.h:207
void(* MHD_UpgradeHandler)(void *cls, struct MHD_Connection *connection, void *con_cls, const char *extra_in, size_t extra_in_size, MHD_socket sock, struct MHD_UpgradeResponseHandle *urh)
#define MHD_SIZE_UNKNOWN
Definition microhttpd.h:184
MHD_Result
Definition microhttpd.h:158
@ MHD_YES
Definition microhttpd.h:167
@ MHD_NO
Definition microhttpd.h:162
int off_t offset
#define MHD_CONTENT_READER_END_OF_STREAM
Definition microhttpd.h:187
void int int must_copy
#define MHD_create_response_from_fd_at_offset(size, fd, offset)
_MHD_EXTERN struct MHD_Response * MHD_create_response_for_upgrade(MHD_UpgradeHandler upgrade_handler, void *upgrade_handler_cls)
void int must_free
int fd
void * data
#define MHD_INVALID_SOCKET
Definition microhttpd.h:208
ssize_t(* MHD_ContentReaderCallback)(void *cls, uint64_t pos, char *buf, size_t max)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition microhttpd.h:188
MHD_UpgradeAction
@ MHD_UPGRADE_ACTION_CORK_ON
@ MHD_UPGRADE_ACTION_CLOSE
@ MHD_UPGRADE_ACTION_CORK_OFF
MHD_ValueKind
@ MHD_FOOTER_KIND
@ MHD_HEADER_KIND
@ MHD_USE_EPOLL
@ MHD_USE_THREAD_PER_CONNECTION
@ MHD_USE_POLL
@ MHD_USE_TLS
@ MHD_ALLOW_UPGRADE
@ MHD_USE_INTERNAL_POLLING_THREAD
MHD_ResponseOptions
@ MHD_RO_END
MHD_ResponseFlags
@ MHD_RF_INSANITY_HEADER_CONTENT_LENGTH
_MHD_EXTERN enum MHD_Result MHD_upgrade_action(struct MHD_UpgradeResponseHandle *urh, enum MHD_UpgradeAction action,...)
Methods for managing response objects.
enum MHD_Result MHD_response_execute_upgrade_(struct MHD_Response *response, struct MHD_Connection *connection)
MHD_socket socket_fd
Definition internal.h:752
size_t write_buffer_size
Definition internal.h:1091
size_t write_buffer_send_offset
Definition internal.h:1096
size_t write_buffer_append_offset
Definition internal.h:1102
char * write_buffer
Definition internal.h:1042
struct MemoryPool * pool
Definition internal.h:685
size_t read_buffer_offset
Definition internal.h:1086
MHD_thread_handle_ID_ pid
Definition internal.h:723
void * client_context
Definition internal.h:986
enum MHD_CONNECTION_STATE state
Definition internal.h:1263
char * read_buffer
Definition internal.h:1036
struct MHD_Daemon * daemon
Definition internal.h:675
volatile bool shutdown
Definition internal.h:1526
enum MHD_FLAG options
Definition internal.h:1619
size_t value_size
Definition internal.h:352
enum MHD_ValueKind kind
Definition internal.h:358
size_t header_size
Definition internal.h:342
struct MHD_HTTP_Header * next
Definition internal.h:342
const void * iov_base
size_t iov_len
MHD_ContentReaderFreeCallback crfc
Definition internal.h:1606
struct MHD_HTTP_Header * first_header
Definition internal.h:1582
void * crc_cls
Definition internal.h:1594
size_t data_buffer_size
Definition internal.h:1664
MHD_iovec_ * data_iov
Definition internal.h:549
MHD_ContentReaderCallback crc
Definition internal.h:1600
struct MHD_Action action
Definition internal.h:1575
enum MHD_ResponseAutoFlags flags_auto
Definition internal.h:539
unsigned int data_iovcnt
Definition internal.h:554
size_t data_size
Definition internal.h:1659
enum MHD_ResponseFlags flags
Definition internal.h:534
unsigned int reference_count
Definition internal.h:1675
char * data
Definition internal.h:1588
MHD_mutex_ mutex
Definition internal.h:1637
uint64_t total_size
Definition internal.h:1642
uint64_t fd_off
Definition internal.h:1653