GNU libmicrohttpd 1.0.6
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-2023 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*/
27
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
166bool
168 enum MHD_ValueKind kind,
169 char *header,
170 size_t header_len,
171 char *content,
172 size_t content_len)
173{
174 struct MHD_HTTP_Res_Header *hdr;
175
176 mhd_assert (0 != header_len);
177 mhd_assert (0 != content_len);
178 if (NULL == (hdr = MHD_calloc_ (1, sizeof (struct MHD_HTTP_Res_Header))))
179 return false;
180
181 hdr->header = header;
182 hdr->header_size = header_len;
183 hdr->value = content;
184 hdr->value_size = content_len;
185 hdr->kind = kind;
186 _MHD_insert_header_last (response, hdr);
187
188 return true; /* Success exit point */
189}
190
191
206bool
208 enum MHD_ValueKind kind,
209 const char *header,
210 size_t header_len,
211 const char *content,
212 size_t content_len)
213{
214 char *header_malloced;
215 char *value_malloced;
216
217 mhd_assert (0 != header_len);
218 mhd_assert (0 != content_len);
219 header_malloced = malloc (header_len + 1);
220 if (NULL == header_malloced)
221 return false;
222
223 memcpy (header_malloced, header, header_len);
224 header_malloced[header_len] = 0;
225
226 value_malloced = malloc (content_len + 1);
227 if (NULL != value_malloced)
228 {
229 memcpy (value_malloced, content, content_len);
230 value_malloced[content_len] = 0;
231
233 header_malloced, header_len,
234 value_malloced, content_len))
235 return true; /* Success exit point */
236
237 free (value_malloced);
238 }
239 free (header_malloced);
240
241 return false; /* Failure exit point */
242}
243
244
255static bool
257 enum MHD_ValueKind kind,
258 const char *header,
259 size_t header_len,
260 const char *content,
261 size_t content_len)
262{
263 if (NULL == response)
264 return false;
265 if (0 == header_len)
266 return false;
267 if (0 == content_len)
268 return false;
269 if (NULL != memchr (header, '\t', header_len))
270 return false;
271 if (NULL != memchr (header, ' ', header_len))
272 return false;
273 if (NULL != memchr (header, '\r', header_len))
274 return false;
275 if (NULL != memchr (header, '\n', header_len))
276 return false;
277 if (NULL != memchr (content, '\r', content_len))
278 return false;
279 if (NULL != memchr (content, '\n', content_len))
280 return false;
281
282 return MHD_add_response_entry_no_check_ (response, kind, header, header_len,
283 content, content_len);
284}
285
286
296static enum MHD_Result
298 enum MHD_ValueKind kind,
299 const char *header,
300 const char *content)
301{
302 size_t header_len;
303 size_t content_len;
304
305 if (NULL == content)
306 return MHD_NO;
307 if (NULL == header)
308 return MHD_NO;
309 header_len = strlen (header);
310 content_len = strlen (content);
311 return add_response_entry_n (response, kind, header,
312 header_len, content,
313 content_len) ? MHD_YES : MHD_NO;
314}
315
316
328static enum MHD_Result
330 const char *value)
331{
332 static const char *key = MHD_HTTP_HEADER_CONNECTION;
334 static const size_t key_len =
336 size_t value_len;
337 size_t old_value_len;
338 size_t buf_size;
339 size_t norm_len;
340 char *buf;
341 struct MHD_HTTP_Res_Header *hdr;
342 bool value_has_close;
343 bool already_has_close;
344 size_t pos = 0;
345
346 if ( (NULL != strchr (value, '\r')) ||
347 (NULL != strchr (value, '\n')) )
348 return MHD_NO;
349
350 if (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
351 {
353 key, key_len);
354 already_has_close =
355 (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE));
356 mhd_assert (NULL != hdr);
357 mhd_assert (already_has_close == (0 == memcmp (hdr->value, "close", 5)));
358 }
359 else
360 {
361 hdr = NULL;
362 already_has_close = false;
365 key, key_len));
367 }
368 if (NULL != hdr)
369 old_value_len = hdr->value_size + 2; /* additional size for ", " */
370 else
371 old_value_len = 0;
372
373 value_len = strlen (value);
374 if (value_len >= SSIZE_MAX)
375 return MHD_NO;
376 /* Additional space for normalisation and zero-termination */
377 norm_len = value_len + value_len / 2 + 1;
378 if (norm_len >= SSIZE_MAX)
379 return MHD_NO;
380 buf_size = old_value_len + (size_t) norm_len;
381
382 buf = malloc (buf_size);
383 if (NULL == buf)
384 return MHD_NO;
385 if (1)
386 { /* local scope */
387 ssize_t norm_len_s = (ssize_t) norm_len;
388 /* Remove "close" token (if any), it will be moved to the front */
389 value_has_close = MHD_str_remove_token_caseless_ (value, value_len, "close",
391 "close"),
392 buf + old_value_len,
393 &norm_len_s);
394 mhd_assert (0 <= norm_len_s);
395 if (0 > norm_len_s)
396 {
397 /* Must never happen with realistic sizes */
398 free (buf);
399 return MHD_NO;
400 }
401 else
402 norm_len = (size_t) norm_len_s;
403 }
404#ifdef UPGRADE_SUPPORT
405 if ( (NULL != response->upgrade_handler) && value_has_close)
406 { /* The "close" token cannot be used with connection "upgrade" */
407 free (buf);
408 return MHD_NO;
409 }
410#endif /* UPGRADE_SUPPORT */
411 if (0 != norm_len)
412 MHD_str_remove_tokens_caseless_ (buf + old_value_len, &norm_len,
413 "keep-alive",
414 MHD_STATICSTR_LEN_ ("keep-alive"));
415 if (0 == norm_len)
416 { /* New value is empty after normalisation */
417 if (! value_has_close)
418 { /* The new value had no tokens */
419 free (buf);
420 return MHD_NO;
421 }
422 if (already_has_close)
423 { /* The "close" token is already present, nothing to modify */
424 free (buf);
425 return MHD_YES;
426 }
427 }
428 /* Add "close" token if required */
429 if (value_has_close && ! already_has_close)
430 {
431 /* Need to insert "close" token at the first position */
432 mhd_assert (buf_size >= old_value_len + norm_len \
433 + MHD_STATICSTR_LEN_ ("close, ") + 1);
434 if (0 != norm_len)
435 memmove (buf + MHD_STATICSTR_LEN_ ("close, ") + old_value_len,
436 buf + old_value_len, norm_len + 1);
437 memcpy (buf, "close", MHD_STATICSTR_LEN_ ("close"));
438 pos += MHD_STATICSTR_LEN_ ("close");
439 }
440 /* Add old value tokens (if any) */
441 if (0 != old_value_len)
442 {
443 if (0 != pos)
444 {
445 buf[pos++] = ',';
446 buf[pos++] = ' ';
447 }
448 memcpy (buf + pos, hdr->value,
449 hdr->value_size);
450 pos += hdr->value_size;
451 }
452 /* Add new value token (if any) */
453 if (0 != norm_len)
454 {
455 if (0 != pos)
456 {
457 buf[pos++] = ',';
458 buf[pos++] = ' ';
459 }
460 /* The new value tokens must be already at the correct position */
461 mhd_assert ((value_has_close && ! already_has_close) ? \
462 (MHD_STATICSTR_LEN_ ("close, ") + old_value_len == pos) : \
463 (old_value_len == pos));
464 pos += norm_len;
465 }
466 mhd_assert (buf_size > pos);
467 buf[pos] = 0; /* Null terminate the result */
468
469 if (NULL == hdr)
470 {
471 struct MHD_HTTP_Res_Header *new_hdr;
472 /* Create new response header entry */
473 new_hdr = MHD_calloc_ (1, sizeof (struct MHD_HTTP_Res_Header));
474 if (NULL != new_hdr)
475 {
476 new_hdr->header = malloc (key_len + 1);
477 if (NULL != new_hdr->header)
478 {
479 memcpy (new_hdr->header, key, key_len + 1);
480 new_hdr->header_size = key_len;
481 new_hdr->value = buf;
482 new_hdr->value_size = pos;
483 new_hdr->kind = MHD_HEADER_KIND;
484 if (value_has_close)
487 else
489 _MHD_insert_header_first (response, new_hdr);
490 return MHD_YES;
491 }
492 free (new_hdr);
493 }
494 free (buf);
495 return MHD_NO;
496 }
497
498 /* Update existing header entry */
499 free (hdr->value);
500 hdr->value = buf;
501 hdr->value_size = pos;
502 if (value_has_close && ! already_has_close)
504 return MHD_YES;
505}
506
507
517static enum MHD_Result
519 const char *value)
520{
521 struct MHD_HTTP_Res_Header *hdr;
522
527 if (NULL == hdr)
528 return MHD_NO;
529
531 &hdr->value_size,
532 value,
533 strlen (value)))
534 return MHD_NO;
535 if (0 == hdr->value_size)
536 {
537 _MHD_remove_header (response, hdr);
538 free (hdr->value);
539 free (hdr->header);
540 free (hdr);
541 response->flags_auto &=
544 }
545 else
546 {
547 hdr->value[hdr->value_size] = 0; /* Null-terminate the result */
548 if (0 != (response->flags_auto
550 {
551 if (MHD_STATICSTR_LEN_ ("close") == hdr->value_size)
552 {
553 if (0 != memcmp (hdr->value,
554 "close",
555 MHD_STATICSTR_LEN_ ("close")))
556 response->flags_auto &=
558 }
559 else if (MHD_STATICSTR_LEN_ ("close, ") < hdr->value_size)
560 {
561 if (0 != memcmp (hdr->value, "close, ",
562 MHD_STATICSTR_LEN_ ("close, ")))
563 response->flags_auto &=
565 }
566 else
567 response->flags_auto &=
569 }
570 }
571 return MHD_YES;
572}
573
574
626 const char *header,
627 const char *content)
628{
630 return add_response_header_connection (response, content);
631
634 {
635 if (! MHD_str_equal_caseless_ (content, "chunked"))
636 return MHD_NO; /* Only "chunked" encoding is allowed */
637 if (0 != (response->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED))
638 return MHD_YES; /* Already has "chunked" encoding header */
639 if ( (0 != (response->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH)) &&
640 (0 == (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH & response->flags)) )
641 return MHD_NO; /* Has "Content-Length" header and no "Insanity" flag */
642 if (MHD_NO != add_response_entry (response,
644 header,
645 content))
646 {
648 return MHD_YES;
649 }
650 return MHD_NO;
651 }
654 {
655 if (0 != (response->flags_auto & MHD_RAF_HAS_DATE_HDR))
656 {
657 struct MHD_HTTP_Res_Header *hdr;
662 mhd_assert (NULL != hdr);
663 _MHD_remove_header (response, hdr);
664 if (NULL != hdr->value)
665 free (hdr->value);
666 free (hdr->header);
667 free (hdr);
668 }
669 if (MHD_NO != add_response_entry (response,
671 header,
672 content))
673 {
674 response->flags_auto |= MHD_RAF_HAS_DATE_HDR;
675 return MHD_YES;
676 }
677 return MHD_NO;
678 }
679
682 {
683 /* Generally MHD sets automatically correct "Content-Length" always when
684 * needed.
685 * Custom "Content-Length" header is allowed only in special cases. */
686 if ( (0 != (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH & response->flags)) ||
687 ((0 != (MHD_RF_HEAD_ONLY_RESPONSE & response->flags)) &&
688 (0 == (response->flags_auto & (MHD_RAF_HAS_TRANS_ENC_CHUNKED
690 {
691 if (MHD_NO != add_response_entry (response,
693 header,
694 content))
695 {
697 return MHD_YES;
698 }
699 }
700 return MHD_NO;
701 }
702
703 return add_response_entry (response,
705 header,
706 content);
707}
708
709
721 const char *footer,
722 const char *content)
723{
724 return add_response_entry (response,
726 footer,
727 content);
728}
729
730
747 const char *header,
748 const char *content)
749{
750 struct MHD_HTTP_Res_Header *pos;
751 size_t header_len;
752 size_t content_len;
753
754 if ( (NULL == header) ||
755 (NULL == content) )
756 return MHD_NO;
757 header_len = strlen (header);
758
759 if ((0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR)) &&
762 header_len))
763 return del_response_header_connection (response, content);
764
765 content_len = strlen (content);
766 pos = response->first_header;
767 while (NULL != pos)
768 {
769 if ((header_len == pos->header_size) &&
770 (content_len == pos->value_size) &&
771 (0 == memcmp (header,
772 pos->header,
773 header_len)) &&
774 (0 == memcmp (content,
775 pos->value,
776 content_len)))
777 {
778 _MHD_remove_header (response, pos);
779 free (pos->header);
780 free (pos->value);
781 free (pos);
783 header_len) &&
786 header_len) )
787 response->flags_auto &=
790 header_len) &&
793 header_len) )
794 response->flags_auto &=
797 header_len) &&
800 header_len) )
801 {
802 if (NULL == MHD_get_response_element_n_ (response,
805 header_len))
806 response->flags_auto &=
808 }
809 return MHD_YES;
810 }
811 pos = pos->next;
812 }
813 return MHD_NO;
814}
815
816
827_MHD_EXTERN int
829 MHD_KeyValueIterator iterator,
830 void *iterator_cls)
831{
832 int numHeaders = 0;
833 struct MHD_HTTP_Res_Header *pos;
834
835 for (pos = response->first_header;
836 NULL != pos;
837 pos = pos->next)
838 {
839 numHeaders++;
840 if ((NULL != iterator) &&
841 (MHD_NO == iterator (iterator_cls,
842 pos->kind,
843 pos->header,
844 pos->value)))
845 break;
846 }
847 return numHeaders;
848}
849
850
859_MHD_EXTERN const char *
861 const char *key)
862{
863 struct MHD_HTTP_Res_Header *pos;
864 size_t key_size;
865
866 if (NULL == key)
867 return NULL;
868
869 key_size = strlen (key);
870 for (pos = response->first_header;
871 NULL != pos;
872 pos = pos->next)
873 {
874 if ((pos->header_size == key_size) &&
876 return pos->value;
877 }
878 return NULL;
879}
880
881
893struct MHD_HTTP_Res_Header *
895 enum MHD_ValueKind kind,
896 const char *key,
897 size_t key_len)
898{
899 struct MHD_HTTP_Res_Header *pos;
900
901 mhd_assert (NULL != key);
902 mhd_assert (0 != key[0]);
903 mhd_assert (0 != key_len);
904
905 for (pos = response->first_header;
906 NULL != pos;
907 pos = pos->next)
908 {
909 if ((pos->header_size == key_len) &&
910 (kind == pos->kind) &&
912 return pos;
913 }
914 return NULL;
915}
916
917
934bool
936 const char *key,
937 size_t key_len,
938 const char *token,
939 size_t token_len)
940{
941 struct MHD_HTTP_Res_Header *pos;
942
943 if ( (NULL == key) ||
944 ('\0' == key[0]) ||
945 (NULL == token) ||
946 ('\0' == token[0]) )
947 return false;
948
949 /* Token must not contain binary zero! */
950 mhd_assert (strlen (token) == token_len);
951
952 for (pos = response->first_header;
953 NULL != pos;
954 pos = pos->next)
955 {
956 if ( (pos->kind == MHD_HEADER_KIND) &&
957 (key_len == pos->header_size) &&
959 key,
960 key_len) &&
962 token,
963 token_len) )
964 return true;
965 }
966 return false;
967}
968
969
993 size_t block_size,
995 void *crc_cls,
997{
998 struct MHD_Response *response;
999
1000 if ((NULL == crc) || (0 == block_size))
1001 return NULL;
1002 if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response)
1003 + block_size)))
1004 return NULL;
1005 response->fd = -1;
1006 response->data = (void *) &response[1];
1007 response->data_buffer_size = block_size;
1008#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1009 if (! MHD_mutex_init_ (&response->mutex))
1010 {
1011 free (response);
1012 return NULL;
1013 }
1014#endif
1015 response->crc = crc;
1016 response->crfc = crfc;
1017 response->crc_cls = crc_cls;
1018 response->reference_count = 1;
1019 response->total_size = size;
1020 return response;
1021}
1022
1023
1035 ...)
1036{
1037 va_list ap;
1038 enum MHD_Result ret;
1039 enum MHD_ResponseOptions ro;
1040
1041 if (0 != (response->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH))
1042 { /* Response has custom "Content-Lengh" header */
1043 if ( (0 != (response->flags & MHD_RF_INSANITY_HEADER_CONTENT_LENGTH)) &&
1045 { /* Request to remove MHD_RF_INSANITY_HEADER_CONTENT_LENGTH flag */
1046 return MHD_NO;
1047 }
1048 if ( (0 != (response->flags & MHD_RF_HEAD_ONLY_RESPONSE)) &&
1050 { /* Request to remove MHD_RF_HEAD_ONLY_RESPONSE flag */
1052 return MHD_NO;
1053 }
1054 }
1055
1056 if ( (0 != (flags & MHD_RF_HEAD_ONLY_RESPONSE)) &&
1057 (0 != response->total_size) )
1058 return MHD_NO;
1059
1060 ret = MHD_YES;
1061 response->flags = flags;
1062
1063 va_start (ap, flags);
1064 while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
1065 {
1066 switch (ro)
1067 {
1068 case MHD_RO_END: /* Not possible */
1069 break;
1070 default:
1071 ret = MHD_NO;
1072 break;
1073 }
1074 }
1075 va_end (ap);
1076 return ret;
1077}
1078
1079
1090static ssize_t
1091file_reader (void *cls,
1092 uint64_t pos,
1093 char *buf,
1094 size_t max)
1095{
1096 struct MHD_Response *response = cls;
1097#if ! defined(_WIN32) || defined(__CYGWIN__)
1098 ssize_t n;
1099#else /* _WIN32 && !__CYGWIN__ */
1100 const HANDLE fh = (HANDLE) (uintptr_t) _get_osfhandle (response->fd);
1101#endif /* _WIN32 && !__CYGWIN__ */
1102 const int64_t offset64 = (int64_t) (pos + response->fd_off);
1103
1104 if (offset64 < 0)
1105 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
1106
1107#if ! defined(_WIN32) || defined(__CYGWIN__)
1108 if (max > SSIZE_MAX)
1109 max = SSIZE_MAX; /* Clamp to maximum return value. */
1110
1111#if defined(HAVE_PREAD64)
1112 n = pread64 (response->fd, buf, max, offset64);
1113#elif defined(HAVE_PREAD)
1114 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
1115 (offset64 > (uint64_t) INT32_MAX) )
1116 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
1117
1118 n = pread (response->fd, buf, max, (off_t) offset64);
1119#else /* ! HAVE_PREAD */
1120#if defined(HAVE_LSEEK64)
1121 if (lseek64 (response->fd,
1122 offset64,
1123 SEEK_SET) != offset64)
1124 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
1125#else /* ! HAVE_LSEEK64 */
1126 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
1127 (offset64 > (uint64_t) INT32_MAX) )
1128 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
1129
1130 if (lseek (response->fd,
1131 (off_t) offset64,
1132 SEEK_SET) != (off_t) offset64)
1133 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
1134#endif /* ! HAVE_LSEEK64 */
1135 n = read (response->fd,
1136 buf,
1137 max);
1138
1139#endif /* ! HAVE_PREAD */
1140 if (0 == n)
1142 if (n < 0)
1144 return n;
1145#else /* _WIN32 && !__CYGWIN__ */
1146 if (INVALID_HANDLE_VALUE == fh)
1147 return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
1148 else
1149 {
1150 OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
1151 ULARGE_INTEGER pos_uli;
1152 DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
1153 DWORD resRead;
1154
1155 pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
1156 f_ol.Offset = pos_uli.LowPart;
1157 f_ol.OffsetHigh = pos_uli.HighPart;
1158 if (! ReadFile (fh, (void *) buf, toRead, &resRead, &f_ol))
1159 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
1160 if (0 == resRead)
1162 return (ssize_t) resRead;
1163 }
1164#endif /* _WIN32 && !__CYGWIN__ */
1165}
1166
1167
1178static ssize_t
1179pipe_reader (void *cls,
1180 uint64_t pos,
1181 char *buf,
1182 size_t max)
1183{
1184 struct MHD_Response *response = cls;
1185 ssize_t n;
1186
1187 (void) pos;
1188
1189#ifndef _WIN32
1190 if (SSIZE_MAX < max)
1191 max = SSIZE_MAX;
1192 n = read (response->fd,
1193 buf,
1194 (MHD_SCKT_SEND_SIZE_) max);
1195#else /* _WIN32 */
1196 if (INT_MAX < max)
1197 max = INT_MAX;
1198 n = read (response->fd,
1199 buf,
1200 (unsigned int) max);
1201#endif /* _WIN32 */
1202
1203 if (0 == n)
1205 if (n < 0)
1207 return n;
1208}
1209
1210
1217static void
1218free_callback (void *cls)
1219{
1220 struct MHD_Response *response = cls;
1221
1222 (void) close (response->fd);
1223 response->fd = -1;
1224}
1225
1226
1227#undef MHD_create_response_from_fd_at_offset
1228
1254 int fd,
1255 off_t offset)
1256{
1257 if (0 > offset)
1258 return NULL;
1260 fd,
1261 (uint64_t) offset);
1262}
1263
1264
1290 int fd,
1291 uint64_t offset)
1292{
1293 struct MHD_Response *response;
1294
1295#if ! defined(HAVE___LSEEKI64) && ! defined(HAVE_LSEEK64)
1296 if ( (sizeof(uint64_t) > sizeof(off_t)) &&
1297 ( (size > (uint64_t) INT32_MAX) ||
1298 (offset > (uint64_t) INT32_MAX) ||
1299 ((size + offset) >= (uint64_t) INT32_MAX) ) )
1300 return NULL;
1301#endif
1302 if ( ((int64_t) size < 0) ||
1303 ((int64_t) offset < 0) ||
1304 ((int64_t) (size + offset) < 0) )
1305 return NULL;
1306
1307 response = MHD_create_response_from_callback (size,
1309 &file_reader,
1310 NULL,
1311 &free_callback);
1312 if (NULL == response)
1313 return NULL;
1314 response->fd = fd;
1315 response->is_pipe = false;
1316 response->fd_off = offset;
1317 response->crc_cls = response;
1318 return response;
1319}
1320
1321
1341{
1342 struct MHD_Response *response;
1343
1346 &pipe_reader,
1347 NULL,
1348 &free_callback);
1349 if (NULL == response)
1350 return NULL;
1351 response->fd = fd;
1352 response->is_pipe = true;
1353 response->crc_cls = response;
1354 return response;
1355}
1356
1357
1376 int fd)
1377{
1379 fd,
1380 0);
1381}
1382
1383
1406 int fd)
1407{
1409 fd,
1410 0);
1411}
1412
1413
1435 void *data,
1436 int must_free,
1437 int must_copy)
1438{
1439 enum MHD_ResponseMemoryMode mode;
1440
1441 if (0 != must_copy)
1442 mode = MHD_RESPMEM_MUST_COPY;
1443 else if (0 != must_free)
1444 mode = MHD_RESPMEM_MUST_FREE;
1445 else
1447
1448 return MHD_create_response_from_buffer (size, data, mode);
1449}
1450
1451
1471 void *buffer,
1472 enum MHD_ResponseMemoryMode mode)
1473{
1474 if (MHD_RESPMEM_MUST_FREE == mode)
1476 buffer,
1477 &free,
1478 buffer);
1479 if (MHD_RESPMEM_MUST_COPY == mode)
1481 buffer);
1482
1484 buffer,
1485 NULL,
1486 NULL);
1487}
1488
1489
1513 const void *buffer)
1514{
1516 buffer,
1517 NULL,
1518 NULL);
1519}
1520
1521
1546 const void *buffer)
1547{
1548 struct MHD_Response *r;
1549 void *mhd_copy;
1550
1551 if (0 == size)
1553 NULL,
1554 NULL,
1555 NULL);
1556 if (NULL == buffer)
1557 return NULL;
1558
1559 mhd_copy = malloc (size);
1560 if (NULL == mhd_copy)
1561 return NULL;
1562 memcpy (mhd_copy, buffer, size);
1563
1565 mhd_copy,
1566 &free,
1567 mhd_copy);
1568 if (NULL == r)
1569 free (mhd_copy);
1570 else
1571 {
1572 /* TODO: remove the next assignment, the buffer should not be modifiable */
1573 r->data_buffer_size = size;
1574 }
1575
1576 return r;
1577}
1578
1579
1599 void *buffer,
1601 crfc)
1602{
1604 buffer,
1605 crfc,
1606 buffer);
1607}
1608
1609
1633 const void *buffer,
1635 crfc,
1636 void *crfc_cls)
1637{
1638 struct MHD_Response *r;
1639
1640 if ((NULL == buffer) && (size > 0))
1641 return NULL;
1642#if SIZEOF_SIZE_T >= SIZEOF_UINT64_T
1643 if (MHD_SIZE_UNKNOWN == size)
1644 return NULL;
1645#endif /* SIZEOF_SIZE_T >= SIZEOF_UINT64_T */
1646 r = MHD_calloc_ (1, sizeof (struct MHD_Response));
1647 if (NULL == r)
1648 return NULL;
1649#if defined(MHD_USE_THREADS)
1650 if (! MHD_mutex_init_ (&r->mutex))
1651 {
1652 free (r);
1653 return NULL;
1654 }
1655#endif
1656 r->fd = -1;
1657 r->reference_count = 1;
1658 r->total_size = size;
1659 r->data = buffer;
1660 r->data_size = size;
1661 r->crfc = crfc;
1662 r->crc_cls = crfc_cls;
1663 return r;
1664}
1665
1666
1688 unsigned int iovcnt,
1690 void *cls)
1691{
1692 struct MHD_Response *response;
1693 unsigned int i;
1694 int i_cp = 0;
1695 uint64_t total_size = 0;
1696 const void *last_valid_buffer = NULL;
1697
1698 if ((NULL == iov) && (0 < iovcnt))
1699 return NULL;
1700
1701 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
1702 if (NULL == response)
1703 return NULL;
1704 if (! MHD_mutex_init_ (&response->mutex))
1705 {
1706 free (response);
1707 return NULL;
1708 }
1709 /* Calculate final size, number of valid elements, and check 'iov' */
1710 for (i = 0; i < iovcnt; ++i)
1711 {
1712 if (0 == iov[i].iov_len)
1713 continue; /* skip zero-sized elements */
1714 if (NULL == iov[i].iov_base)
1715 {
1716 i_cp = -1; /* error */
1717 break;
1718 }
1719 if ( (total_size > (total_size + iov[i].iov_len)) ||
1720 (INT_MAX == i_cp) ||
1721 (SSIZE_MAX < (total_size + iov[i].iov_len)) )
1722 {
1723 i_cp = -1; /* overflow */
1724 break;
1725 }
1726 last_valid_buffer = iov[i].iov_base;
1727 total_size += iov[i].iov_len;
1728#if defined(MHD_POSIX_SOCKETS) || ! defined(_WIN64)
1729 i_cp++;
1730#else /* ! MHD_POSIX_SOCKETS && _WIN64 */
1731 {
1732 int64_t i_add;
1733
1734 i_add = (int64_t) (iov[i].iov_len / ULONG_MAX);
1735 if (0 != iov[i].iov_len % ULONG_MAX)
1736 i_add++;
1737 if (INT_MAX < (i_add + i_cp))
1738 {
1739 i_cp = -1; /* overflow */
1740 break;
1741 }
1742 i_cp += (int) i_add;
1743 }
1744#endif /* ! MHD_POSIX_SOCKETS && _WIN64 */
1745 }
1746 if (-1 == i_cp)
1747 {
1748 /* Some error condition */
1749 MHD_mutex_destroy_chk_ (&response->mutex);
1750 free (response);
1751 return NULL;
1752 }
1753 response->fd = -1;
1754 response->reference_count = 1;
1755 response->total_size = total_size;
1756 response->crc_cls = cls;
1757 response->crfc = free_cb;
1758 if (0 == i_cp)
1759 {
1760 mhd_assert (0 == total_size);
1761 return response;
1762 }
1763 if (1 == i_cp)
1764 {
1765 mhd_assert (NULL != last_valid_buffer);
1766 response->data = last_valid_buffer;
1767 response->data_size = (size_t) total_size;
1768 return response;
1769 }
1770 mhd_assert (1 < i_cp);
1771 if (1)
1772 { /* for local variables local scope only */
1773 MHD_iovec_ *iov_copy;
1774 int num_copy_elements = i_cp;
1775
1776 iov_copy = MHD_calloc_ ((size_t) num_copy_elements, \
1777 sizeof(MHD_iovec_));
1778 if (NULL == iov_copy)
1779 {
1780 MHD_mutex_destroy_chk_ (&response->mutex);
1781 free (response);
1782 return NULL;
1783 }
1784 i_cp = 0;
1785 for (i = 0; i < iovcnt; ++i)
1786 {
1787 size_t element_size = iov[i].iov_len;
1788 const uint8_t *buf = (const uint8_t *) iov[i].iov_base;
1789
1790 if (0 == element_size)
1791 continue; /* skip zero-sized elements */
1792#if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64)
1793 while (MHD_IOV_ELMN_MAX_SIZE < element_size)
1794 {
1795 iov_copy[i_cp].iov_base = (char *) _MHD_DROP_CONST (buf);
1796 iov_copy[i_cp].iov_len = ULONG_MAX;
1797 buf += ULONG_MAX;
1798 element_size -= ULONG_MAX;
1799 i_cp++;
1800 }
1801#endif /* MHD_WINSOCK_SOCKETS && _WIN64 */
1802 iov_copy[i_cp].iov_base = _MHD_DROP_CONST (buf);
1803 iov_copy[i_cp].iov_len = (MHD_iov_size_) element_size;
1804 i_cp++;
1805 }
1806 mhd_assert (num_copy_elements == i_cp);
1807 mhd_assert (0 <= i_cp);
1808 response->data_iov = iov_copy;
1809 response->data_iovcnt = (unsigned int) i_cp;
1810 }
1811 return response;
1812}
1813
1814
1832{
1833 struct MHD_Response *r;
1834 r = (struct MHD_Response *) MHD_calloc_ (1, sizeof (struct MHD_Response));
1835 if (NULL != r)
1836 {
1837 if (MHD_mutex_init_ (&r->mutex))
1838 {
1839 r->fd = -1;
1840 r->reference_count = 1;
1841 /* If any flags combination will be not allowed, replace the next
1842 * assignment with MHD_set_response_options() call. */
1843 r->flags = flags;
1844
1845 return r; /* Successful result */
1846 }
1847 free (r);
1848 }
1849 return NULL; /* Something failed */
1850}
1851
1852
1853#ifdef UPGRADE_SUPPORT
1867MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
1868 enum MHD_UpgradeAction action,
1869 ...)
1870{
1871 struct MHD_Connection *connection;
1872 struct MHD_Daemon *daemon;
1873
1874 if (NULL == urh)
1875 return MHD_NO;
1876 connection = urh->connection;
1877
1878 /* Precaution checks on external data. */
1879 if (NULL == connection)
1880 return MHD_NO;
1881 daemon = connection->daemon;
1882 if (NULL == daemon)
1883 return MHD_NO;
1884
1885 switch (action)
1886 {
1888 if (urh->was_closed)
1889 return MHD_NO; /* Already closed. */
1890
1891 /* transition to special 'closed' state for start of cleanup */
1892#ifdef HTTPS_SUPPORT
1893 if (0 != (daemon->options & MHD_USE_TLS) )
1894 {
1895 /* signal that app is done by shutdown() of 'app' socket */
1896 /* Application will not use anyway this socket after this command. */
1897 shutdown (urh->app.socket,
1898 SHUT_RDWR);
1899 }
1900#endif /* HTTPS_SUPPORT */
1901 mhd_assert (MHD_CONNECTION_UPGRADE == connection->state);
1902 /* The next function will mark the connection as closed by application
1903 * by setting 'urh->was_closed'.
1904 * As soon as connection will be marked with BOTH
1905 * 'urh->was_closed' AND 'urh->clean_ready', it will
1906 * be moved to cleanup list by MHD_resume_connection(). */
1907 MHD_upgraded_connection_mark_app_closed_ (connection);
1908 return MHD_YES;
1910 /* Unportable API. TODO: replace with portable action. */
1911 return MHD_connection_set_cork_state_ (connection,
1912 true) ? MHD_YES : MHD_NO;
1914 /* Unportable API. TODO: replace with portable action. */
1915 return MHD_connection_set_cork_state_ (connection,
1916 false) ? MHD_YES : MHD_NO;
1917 default:
1918 /* we don't understand this one */
1919 return MHD_NO;
1920 }
1921}
1922
1923
1937enum MHD_Result
1939 struct MHD_Connection *connection)
1940{
1941#if defined(HTTPS_SUPPORT) || defined(_DEBUG) || defined(HAVE_MESSAGES)
1942 struct MHD_Daemon *const daemon = connection->daemon;
1943#endif /* HTTPS_SUPPORT || _DEBUG || HAVE_MESSAGES */
1944 struct MHD_UpgradeResponseHandle *urh;
1945 size_t rbo;
1946
1947#ifdef MHD_USE_THREADS
1948 mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
1949 MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
1950#endif /* MHD_USE_THREADS */
1951
1952 /* "Upgrade" responses accepted only if MHD_ALLOW_UPGRADE is enabled */
1953 mhd_assert (0 != (daemon->options & MHD_ALLOW_UPGRADE));
1954 /* The header was checked when response queued */
1955 mhd_assert (NULL != \
1960
1961 if (! connection->sk_nonblck)
1962 {
1963#ifdef HAVE_MESSAGES
1964 MHD_DLOG (daemon,
1965 _ ("Cannot execute \"upgrade\" as the socket is in " \
1966 "the blocking mode.\n"));
1967#endif
1968 return MHD_NO;
1969 }
1970 urh = MHD_calloc_ (1, sizeof (struct MHD_UpgradeResponseHandle));
1971 if (NULL == urh)
1972 return MHD_NO;
1973 urh->connection = connection;
1974 rbo = connection->read_buffer_offset;
1975 connection->read_buffer_offset = 0;
1976 MHD_connection_set_nodelay_state_ (connection, false);
1977 MHD_connection_set_cork_state_ (connection, false);
1978#ifdef HTTPS_SUPPORT
1979 if (0 != (daemon->options & MHD_USE_TLS) )
1980 {
1981 MHD_socket sv[2];
1982#if defined(MHD_socket_nosignal_) || ! defined(MHD_socket_pair_nblk_)
1983 int res1;
1984 int res2;
1985#endif /* MHD_socket_nosignal_ || !MHD_socket_pair_nblk_ */
1986
1987#ifdef MHD_socket_pair_nblk_
1988 if (! MHD_socket_pair_nblk_ (sv))
1989 {
1990 free (urh);
1991 return MHD_NO;
1992 }
1993#else /* !MHD_socket_pair_nblk_ */
1994 if (! MHD_socket_pair_ (sv))
1995 {
1996 free (urh);
1997 return MHD_NO;
1998 }
1999 res1 = MHD_socket_nonblocking_ (sv[0]);
2000 res2 = MHD_socket_nonblocking_ (sv[1]);
2001 if ( (! res1) || (! res2) )
2002 {
2003#ifdef HAVE_MESSAGES
2004 MHD_DLOG (daemon,
2005 _ ("Failed to make loopback sockets non-blocking.\n"));
2006#endif
2007 if (! res2)
2008 {
2009 /* Socketpair cannot be used. */
2010 MHD_socket_close_chk_ (sv[0]);
2011 MHD_socket_close_chk_ (sv[1]);
2012 free (urh);
2013 return MHD_NO;
2014 }
2015 }
2016#endif /* !MHD_socket_pair_nblk_ */
2017#ifdef MHD_socket_nosignal_
2018 res1 = MHD_socket_nosignal_ (sv[0]);
2019 res2 = MHD_socket_nosignal_ (sv[1]);
2020 if ( (! res1) || (! res2) )
2021 {
2022#ifdef HAVE_MESSAGES
2023 MHD_DLOG (daemon,
2024 _ ("Failed to set SO_NOSIGPIPE on loopback sockets.\n"));
2025#endif
2026#ifndef MSG_NOSIGNAL
2027 if (! res2)
2028 {
2029 /* Socketpair cannot be used. */
2030 MHD_socket_close_chk_ (sv[0]);
2031 MHD_socket_close_chk_ (sv[1]);
2032 free (urh);
2033 return MHD_NO;
2034 }
2035#endif /* ! MSG_NOSIGNAL */
2036 }
2037#endif /* MHD_socket_nosignal_ */
2038 if (MHD_D_IS_USING_SELECT_ (daemon) &&
2039 (! MHD_D_DOES_SCKT_FIT_FDSET_ (sv[1], daemon)) )
2040 {
2041#ifdef HAVE_MESSAGES
2042 MHD_DLOG (daemon,
2043 _ ("Socketpair descriptor is not less than FD_SETSIZE: " \
2044 "%d >= %d\n"),
2045 (int) sv[1],
2046 (int) MHD_D_GET_FD_SETSIZE_ (daemon));
2047#endif
2048 MHD_socket_close_chk_ (sv[0]);
2049 MHD_socket_close_chk_ (sv[1]);
2050 free (urh);
2051 return MHD_NO;
2052 }
2053 urh->app.socket = sv[0];
2054 urh->app.urh = urh;
2055 urh->app.celi = MHD_EPOLL_STATE_UNREADY;
2056 urh->mhd.socket = sv[1];
2057 urh->mhd.urh = urh;
2058 urh->mhd.celi = MHD_EPOLL_STATE_UNREADY;
2059#ifdef EPOLL_SUPPORT
2060 /* Launch IO processing by the event loop */
2061 if (MHD_D_IS_USING_EPOLL_ (daemon))
2062 {
2063 /* We're running with epoll(), need to add the sockets
2064 to the event set of the daemon's `epoll_upgrade_fd` */
2065 struct epoll_event event;
2066
2067 mhd_assert (-1 != daemon->epoll_upgrade_fd);
2068 /* First, add network socket */
2069 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2070 event.data.ptr = &urh->app;
2071 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2072 EPOLL_CTL_ADD,
2073 connection->socket_fd,
2074 &event))
2075 {
2076#ifdef HAVE_MESSAGES
2077 MHD_DLOG (daemon,
2078 _ ("Call to epoll_ctl failed: %s\n"),
2080#endif
2081 MHD_socket_close_chk_ (sv[0]);
2082 MHD_socket_close_chk_ (sv[1]);
2083 free (urh);
2084 return MHD_NO;
2085 }
2086
2087 /* Second, add our end of the UNIX socketpair() */
2088 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2089 event.data.ptr = &urh->mhd;
2090 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2091 EPOLL_CTL_ADD,
2092 urh->mhd.socket,
2093 &event))
2094 {
2095 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
2096 event.data.ptr = &urh->app;
2097 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2098 EPOLL_CTL_DEL,
2099 connection->socket_fd,
2100 &event))
2101 MHD_PANIC (_ ("Error cleaning up while handling epoll error.\n"));
2102#ifdef HAVE_MESSAGES
2103 MHD_DLOG (daemon,
2104 _ ("Call to epoll_ctl failed: %s\n"),
2106#endif
2107 MHD_socket_close_chk_ (sv[0]);
2108 MHD_socket_close_chk_ (sv[1]);
2109 free (urh);
2110 return MHD_NO;
2111 }
2112 EDLL_insert (daemon->eready_urh_head,
2113 daemon->eready_urh_tail,
2114 urh);
2115 urh->in_eready_list = true;
2116 }
2117#endif /* EPOLL_SUPPORT */
2118 if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
2119 {
2120 /* This takes care of further processing for most event loops:
2121 simply add to DLL for bi-direcitonal processing */
2122 DLL_insert (daemon->urh_head,
2123 daemon->urh_tail,
2124 urh);
2125 }
2126 /* In thread-per-connection mode, thread will switch to forwarding once
2127 * connection.urh is not NULL and connection.state == MHD_CONNECTION_UPGRADE.
2128 */
2129 }
2130 else
2131 {
2132 urh->app.socket = MHD_INVALID_SOCKET;
2133 urh->mhd.socket = MHD_INVALID_SOCKET;
2134 /* Non-TLS connection do not hold any additional resources. */
2135 urh->clean_ready = true;
2136 }
2137#else /* ! HTTPS_SUPPORT */
2138 urh->clean_ready = true;
2139#endif /* ! HTTPS_SUPPORT */
2140 connection->urh = urh;
2141 /* As far as MHD's event loops are concerned, this connection is
2142 suspended; it will be resumed once application is done by the
2143 #MHD_upgrade_action() function */
2144 internal_suspend_connection_ (connection);
2145
2146 /* hand over socket to application */
2147 response->upgrade_handler (response->upgrade_handler_cls,
2148 connection,
2149 connection->rq.client_context,
2150 connection->read_buffer,
2151 rbo,
2152#ifdef HTTPS_SUPPORT
2153 (0 == (daemon->options & MHD_USE_TLS) ) ?
2154 connection->socket_fd : urh->app.socket,
2155#else /* ! HTTPS_SUPPORT */
2156 connection->socket_fd,
2157#endif /* ! HTTPS_SUPPORT */
2158 urh);
2159
2160#ifdef HTTPS_SUPPORT
2161 if (0 != (daemon->options & MHD_USE_TLS))
2162 {
2163 struct MemoryPool *const pool = connection->pool;
2164 size_t avail;
2165 char *buf;
2166
2167 /* All data should be sent already */
2168 mhd_assert (connection->write_buffer_send_offset == \
2169 connection->write_buffer_append_offset);
2170 MHD_pool_deallocate (pool, connection->write_buffer,
2171 connection->write_buffer_size);
2172 connection->write_buffer_append_offset = 0;
2173 connection->write_buffer_send_offset = 0;
2174 connection->write_buffer_size = 0;
2175 connection->write_buffer = NULL;
2176
2177 /* Extra read data should be processed already by the application */
2178 MHD_pool_deallocate (pool, connection->read_buffer,
2179 connection->read_buffer_size);
2180 connection->read_buffer_offset = 0;
2181 connection->read_buffer_size = 0;
2182 connection->read_buffer = NULL;
2183
2184 avail = MHD_pool_get_free (pool);
2185 if (avail < RESERVE_EBUF_SIZE)
2186 {
2187 /* connection's pool is totally at the limit,
2188 use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
2189 avail = RESERVE_EBUF_SIZE;
2190 buf = urh->e_buf;
2191#ifdef HAVE_MESSAGES
2192 MHD_DLOG (daemon,
2193 _ ("Memory shortage in connection's memory pool. " \
2194 "The \"upgraded\" communication will be inefficient.\n"));
2195#endif
2196 }
2197 else
2198 {
2199 /* Normal case: grab all remaining memory from the
2200 connection's pool for the IO buffers; the connection
2201 certainly won't need it anymore as we've upgraded
2202 to another protocol. */
2203 buf = MHD_pool_allocate (pool,
2204 avail,
2205 false);
2206 }
2207 /* use half the buffer for inbound, half for outbound */
2208 urh->in_buffer_size = avail / 2;
2209 urh->out_buffer_size = avail - urh->in_buffer_size;
2210 urh->in_buffer = buf;
2211 urh->out_buffer = buf + urh->in_buffer_size;
2212 }
2213#endif /* HTTPS_SUPPORT */
2214 return MHD_YES;
2215}
2216
2217
2249 void *upgrade_handler_cls)
2250{
2251 struct MHD_Response *response;
2252
2253 if (NULL == upgrade_handler)
2254 return NULL; /* invalid request */
2255 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
2256 if (NULL == response)
2257 return NULL;
2258#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2259 if (! MHD_mutex_init_ (&response->mutex))
2260 {
2261 free (response);
2262 return NULL;
2263 }
2264#endif
2265 response->upgrade_handler = upgrade_handler;
2266 response->upgrade_handler_cls = upgrade_handler_cls;
2267 response->total_size = 0;
2268 response->reference_count = 1;
2269 if (MHD_NO ==
2270 MHD_add_response_header (response,
2272 "Upgrade"))
2273 {
2274 MHD_destroy_response (response);
2275 return NULL;
2276 }
2277 return response;
2278}
2279
2280
2281#endif /* UPGRADE_SUPPORT */
2282
2283
2293_MHD_EXTERN void
2295{
2296 struct MHD_HTTP_Res_Header *pos;
2297
2298 if (NULL == response)
2299 return;
2300#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2301 MHD_mutex_lock_chk_ (&response->mutex);
2302#endif
2303 if (0 != --(response->reference_count))
2304 {
2305#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2306 MHD_mutex_unlock_chk_ (&response->mutex);
2307#endif
2308 return;
2309 }
2310#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2311 MHD_mutex_unlock_chk_ (&response->mutex);
2312 MHD_mutex_destroy_chk_ (&response->mutex);
2313#endif
2314 if (NULL != response->crfc)
2315 response->crfc (response->crc_cls);
2316
2317 if (NULL != response->data_iov)
2318 {
2319 free (response->data_iov);
2320 }
2321
2322 while (NULL != response->first_header)
2323 {
2324 pos = response->first_header;
2325 response->first_header = pos->next;
2326 free (pos->header);
2327 free (pos->value);
2328 free (pos);
2329 }
2330 free (response);
2331}
2332
2333
2339void
2341{
2342#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2343 MHD_mutex_lock_chk_ (&response->mutex);
2344#endif
2345 (response->reference_count)++;
2346#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2347 MHD_mutex_unlock_chk_ (&response->mutex);
2348#endif
2349}
2350
2351
2352/* end of response.c */
Methods for managing connections.
void internal_suspend_connection_(struct MHD_Connection *connection)
Definition daemon.c:3224
#define MHD_HTTP_HEADER_CONTENT_LENGTH
Definition microhttpd.h:596
#define MHD_HTTP_HEADER_CONNECTION
Definition microhttpd.h:590
#define MHD_HTTP_HEADER_DATE
Definition microhttpd.h:604
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition microhttpd.h:654
#define MHD_HTTP_HEADER_UPGRADE
Definition microhttpd.h:656
enum MHD_Result(* MHD_KeyValueIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
_MHD_EXTERN int MHD_get_response_headers(struct MHD_Response *response, MHD_KeyValueIterator iterator, void *iterator_cls)
Definition response.c:828
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback(size_t size, void *buffer, MHD_ContentReaderFreeCallback crfc)
Definition response.c:1598
_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:1687
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_data(size_t size, void *data, int must_free, int must_copy)
Definition response.c:1434
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_copy(size_t size, const void *buffer)
Definition response.c:1545
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition response.c:1470
_MHD_EXTERN enum MHD_Result MHD_del_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:746
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_pipe(int fd)
Definition response.c:1340
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition response.c:2294
struct MHD_HTTP_Res_Header * MHD_get_response_element_n_(struct MHD_Response *response, enum MHD_ValueKind kind, const char *key, size_t key_len)
Definition response.c:894
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd(size_t size, int fd)
Definition response.c:1375
_MHD_EXTERN struct MHD_Response * MHD_create_response_empty(enum MHD_ResponseFlags flags)
Definition response.c:1831
MHD_ResponseMemoryMode
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition response.c:860
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_static(size_t size, const void *buffer)
Definition response.c:1512
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:1289
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback_cls(size_t size, const void *buffer, MHD_ContentReaderFreeCallback crfc, void *crfc_cls)
Definition response.c:1632
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:625
_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:992
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd64(uint64_t size, int fd)
Definition response.c:1405
_MHD_EXTERN enum MHD_Result MHD_add_response_footer(struct MHD_Response *response, const char *footer, const char *content)
Definition response.c:720
@ MHD_RESPMEM_MUST_FREE
@ MHD_RESPMEM_PERSISTENT
@ MHD_RESPMEM_MUST_COPY
MHD internal shared structures.
@ MHD_EPOLL_STATE_UNREADY
Definition internal.h:175
#define DLL_insert(head, tail, element)
Definition internal.h:2671
#define MHD_D_DOES_SCKT_FIT_FDSET_(sckt, d)
Definition internal.h:2614
#define MHD_D_IS_USING_SELECT_(d)
Definition internal.h:2555
#define EDLL_insert(head, tail, element)
Definition internal.h:2765
struct MHD_IoVec MHD_iovec_
Definition internal.h:440
size_t MHD_iov_size_
Definition internal.h:442
MHD_ResponseAutoFlags
Definition internal.h:405
@ MHD_RAF_HAS_DATE_HDR
Definition internal.h:411
@ MHD_RAF_HAS_CONTENT_LENGTH
Definition internal.h:410
@ MHD_RAF_HAS_CONNECTION_CLOSE
Definition internal.h:408
@ MHD_RAF_HAS_TRANS_ENC_CHUNKED
Definition internal.h:409
@ MHD_RAF_HAS_CONNECTION_HDR
Definition internal.h:407
#define _MHD_DROP_CONST(ptr)
Definition internal.h:77
#define MHD_D_GET_FD_SETSIZE_(d)
Definition internal.h:2608
#define MHD_D_IS_USING_THREAD_PER_CONN_(d)
Definition internal.h:2591
#define MHD_D_IS_USING_THREADS_(d)
Definition internal.h:2587
#define MHD_D_IS_USING_EPOLL_(d)
Definition internal.h:2563
#define MHD_IOV_ELMN_MAX_SIZE
Definition internal.h:441
void MHD_pool_deallocate(struct MemoryPool *pool, void *block, size_t block_size)
Definition memorypool.c:625
size_t MHD_pool_get_free(struct MemoryPool *pool)
Definition memorypool.c:374
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, bool from_end)
Definition memorypool.c:399
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
macros for mhd_assert()
#define mhd_assert(ignore)
Definition mhd_assert.h:45
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition mhd_compat.c:98
Header for platform missing functions.
Header for platform-independent inter-thread communication.
#define MHD_PANIC(msg)
Definition mhd_itc.h:45
limits values definitions
#define INT32_MAX
Definition mhd_limits.h:77
#define SSIZE_MAX
Definition mhd_limits.h:121
#define INT_MAX
Definition mhd_limits.h:45
#define MHD_mutex_unlock_chk_(ignore)
Definition mhd_locks.h:198
#define MHD_mutex_init_(ignore)
Definition mhd_locks.h:192
#define MHD_mutex_lock_chk_(ignore)
Definition mhd_locks.h:196
#define MHD_mutex_destroy_chk_(ignore)
Definition mhd_locks.h:194
#define NULL
additional automatic macros for MHD_config.h
#define _(String)
Definition mhd_options.h:42
#define _MHD_EXTERN
Definition mhd_options.h:53
bool MHD_connection_set_cork_state_(struct MHD_Connection *connection, bool cork_state)
Definition mhd_send.c:244
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition mhd_send.c:174
Declarations of send() wrappers.
int MHD_socket_nonblocking_(MHD_socket sock)
size_t MHD_SCKT_SEND_SIZE_
#define MHD_socket_last_strerr_()
#define MHD_socket_close_chk_(fd)
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition mhd_str.c:683
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:1033
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition mhd_str.c:782
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:857
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition mhd_str.c:749
Header for string manipulating helpers.
#define MHD_STATICSTR_LEN_(macro)
#define MHD_thread_handle_ID_is_current_thread_(hndl_id)
int MHD_socket
Definition microhttpd.h:206
#define MHD_SIZE_UNKNOWN
Definition microhttpd.h:183
MHD_Result
Definition microhttpd.h:163
@ MHD_YES
Definition microhttpd.h:172
@ MHD_NO
Definition microhttpd.h:167
int off_t offset
#define MHD_CONTENT_READER_END_OF_STREAM
Definition microhttpd.h:186
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:207
ssize_t(* MHD_ContentReaderCallback)(void *cls, uint64_t pos, char *buf, size_t max)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition microhttpd.h:187
MHD_UpgradeAction
@ MHD_UPGRADE_ACTION_CORK_ON
@ MHD_UPGRADE_ACTION_CLOSE
@ MHD_UPGRADE_ACTION_CORK_OFF
MHD_ValueKind
@ MHD_FOOTER_KIND
@ MHD_HEADER_KIND
void(* MHD_UpgradeHandler)(void *cls, struct MHD_Connection *connection, void *req_cls, const char *extra_in, size_t extra_in_size, MHD_socket sock, struct MHD_UpgradeResponseHandle *urh)
@ MHD_USE_TLS
@ MHD_ALLOW_UPGRADE
MHD_ResponseOptions
@ MHD_RO_END
MHD_ResponseFlags
@ MHD_RF_HEAD_ONLY_RESPONSE
@ MHD_RF_INSANITY_HEADER_CONTENT_LENGTH
_MHD_EXTERN enum MHD_Result MHD_upgrade_action(struct MHD_UpgradeResponseHandle *urh, enum MHD_UpgradeAction action,...)
static void free_callback(void *cls)
Definition response.c:1218
#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:935
bool MHD_add_response_entry_no_check_(struct MHD_Response *response, enum MHD_ValueKind kind, const char *header, size_t header_len, const char *content, size_t content_len)
Definition response.c:207
#define _MHD_insert_header_last(presponse, phdr)
Definition response.c:98
static bool add_response_entry_n(struct MHD_Response *response, enum MHD_ValueKind kind, const char *header, size_t header_len, const char *content, size_t content_len)
Definition response.c:256
#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:329
#define _MHD_insert_header_first(presponse, phdr)
Definition response.c:77
static enum MHD_Result add_response_entry(struct MHD_Response *response, enum MHD_ValueKind kind, const char *header, const char *content)
Definition response.c:297
static ssize_t file_reader(void *cls, uint64_t pos, char *buf, size_t max)
Definition response.c:1091
static enum MHD_Result del_response_header_connection(struct MHD_Response *response, const char *value)
Definition response.c:518
bool MHD_add_response_entry_no_alloc_(struct MHD_Response *response, enum MHD_ValueKind kind, char *header, size_t header_len, char *content, size_t content_len)
Definition response.c:167
static ssize_t pipe_reader(void *cls, uint64_t pos, char *buf, size_t max)
Definition response.c:1179
void MHD_increment_response_rc(struct MHD_Response *response)
Definition response.c:2340
_MHD_EXTERN enum MHD_Result MHD_set_response_options(struct MHD_Response *response, enum MHD_ResponseFlags flags,...)
Definition response.c:1033
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:1489
size_t write_buffer_size
Definition internal.h:1447
size_t write_buffer_send_offset
Definition internal.h:1452
size_t write_buffer_append_offset
Definition internal.h:1458
char * write_buffer
Definition internal.h:1415
struct MHD_Request rq
Definition internal.h:1371
size_t read_buffer_offset
Definition internal.h:1442
struct MemoryPool * pool
Definition internal.h:1386
enum MHD_CONNECTION_STATE state
Definition internal.h:1571
char * read_buffer
Definition internal.h:1409
struct MHD_Daemon * daemon
Definition internal.h:1366
size_t read_buffer_size
Definition internal.h:1436
volatile bool shutdown
Definition internal.h:2209
enum MHD_FLAG options
Definition internal.h:1886
struct MHD_HTTP_Res_Header * next
Definition internal.h:323
enum MHD_ValueKind kind
Definition internal.h:353
const void * iov_base
size_t iov_len
void * client_context
Definition internal.h:1198
MHD_ContentReaderFreeCallback crfc
Definition internal.h:507
size_t data_buffer_size
Definition internal.h:557
MHD_iovec_ * data_iov
Definition internal.h:588
const char * data
Definition internal.h:489
MHD_ContentReaderCallback crc
Definition internal.h:501
enum MHD_ResponseAutoFlags flags_auto
Definition internal.h:578
unsigned int data_iovcnt
Definition internal.h:593
size_t data_size
Definition internal.h:552
enum MHD_ResponseFlags flags
Definition internal.h:573
void * crc_cls
Definition internal.h:495
unsigned int reference_count
Definition internal.h:563
struct MHD_HTTP_Res_Header * first_header
Definition internal.h:478
uint64_t total_size
Definition internal.h:535
uint64_t fd_off
Definition internal.h:546