GNU libmicrohttpd 1.0.0
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*/
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
308 header_len = strlen (header);
309 content_len = strlen (content);
310 return add_response_entry_n (response, kind, header,
311 header_len, content,
312 content_len) ? MHD_YES : MHD_NO;
313}
314
315
327static enum MHD_Result
329 const char *value)
330{
331 static const char *key = MHD_HTTP_HEADER_CONNECTION;
333 static const size_t key_len =
335 size_t value_len;
336 size_t old_value_len;
337 size_t buf_size;
338 size_t norm_len;
339 char *buf;
340 struct MHD_HTTP_Res_Header *hdr;
341 bool value_has_close;
342 bool already_has_close;
343 size_t pos = 0;
345 if ( (NULL != strchr (value, '\r')) ||
346 (NULL != strchr (value, '\n')) )
347 return MHD_NO;
348
349 if (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
350 {
352 key, key_len);
353 already_has_close =
354 (0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE));
355 mhd_assert (already_has_close == (0 == memcmp (hdr->value, "close", 5)));
356 mhd_assert (NULL != hdr);
357 }
358 else
359 {
360 hdr = NULL;
361 already_has_close = false;
364 key, key_len));
366 }
367 if (NULL != hdr)
368 old_value_len = hdr->value_size + 2; /* additional size for ", " */
369 else
370 old_value_len = 0;
371
372 value_len = strlen (value);
373 if (value_len >= SSIZE_MAX)
374 return MHD_NO;
375 /* Additional space for normalisation and zero-termination */
376 norm_len = value_len + value_len / 2 + 1;
377 if (norm_len >= SSIZE_MAX)
378 return MHD_NO;
379 buf_size = old_value_len + (size_t) norm_len;
380
381 buf = malloc (buf_size);
382 if (NULL == buf)
383 return MHD_NO;
384 if (1)
385 { /* local scope */
386 ssize_t norm_len_s = (ssize_t) norm_len;
387 /* Remove "close" token (if any), it will be moved to the front */
388 value_has_close = MHD_str_remove_token_caseless_ (value, value_len, "close",
390 "close"),
391 buf + old_value_len,
392 &norm_len_s);
393 mhd_assert (0 <= norm_len_s);
394 if (0 > norm_len_s)
395 {
396 /* Must never happen with realistic sizes */
397 free (buf);
398 return MHD_NO;
399 }
400 else
401 norm_len = (size_t) norm_len_s;
402 }
403#ifdef UPGRADE_SUPPORT
404 if ( (NULL != response->upgrade_handler) && value_has_close)
405 { /* The "close" token cannot be used with connection "upgrade" */
406 free (buf);
407 return MHD_NO;
408 }
409#endif /* UPGRADE_SUPPORT */
410 if (0 != norm_len)
411 MHD_str_remove_tokens_caseless_ (buf + old_value_len, &norm_len,
412 "keep-alive",
413 MHD_STATICSTR_LEN_ ("keep-alive"));
414 if (0 == norm_len)
415 { /* New value is empty after normalisation */
416 if (! value_has_close)
417 { /* The new value had no tokens */
418 free (buf);
419 return MHD_NO;
420 }
421 if (already_has_close)
422 { /* The "close" token is already present, nothing to modify */
423 free (buf);
424 return MHD_YES;
425 }
426 }
427 /* Add "close" token if required */
428 if (value_has_close && ! already_has_close)
429 {
430 /* Need to insert "close" token at the first position */
431 mhd_assert (buf_size >= old_value_len + norm_len \
432 + MHD_STATICSTR_LEN_ ("close, ") + 1);
433 if (0 != norm_len)
434 memmove (buf + MHD_STATICSTR_LEN_ ("close, ") + old_value_len,
435 buf + old_value_len, norm_len + 1);
436 memcpy (buf, "close", MHD_STATICSTR_LEN_ ("close"));
437 pos += MHD_STATICSTR_LEN_ ("close");
438 }
439 /* Add old value tokens (if any) */
440 if (0 != old_value_len)
441 {
442 if (0 != pos)
443 {
444 buf[pos++] = ',';
445 buf[pos++] = ' ';
446 }
447 memcpy (buf + pos, hdr->value,
448 hdr->value_size);
449 pos += hdr->value_size;
450 }
451 /* Add new value token (if any) */
452 if (0 != norm_len)
453 {
454 if (0 != pos)
455 {
456 buf[pos++] = ',';
457 buf[pos++] = ' ';
458 }
459 /* The new value tokens must be already at the correct position */
460 mhd_assert ((value_has_close && ! already_has_close) ? \
461 (MHD_STATICSTR_LEN_ ("close, ") + old_value_len == pos) : \
462 (old_value_len == pos));
463 pos += norm_len;
464 }
465 mhd_assert (buf_size > pos);
466 buf[pos] = 0; /* Null terminate the result */
467
468 if (NULL == hdr)
469 {
470 struct MHD_HTTP_Res_Header *new_hdr;
471 /* Create new response header entry */
472 new_hdr = MHD_calloc_ (1, sizeof (struct MHD_HTTP_Res_Header));
473 if (NULL != new_hdr)
474 {
475 new_hdr->header = malloc (key_len + 1);
476 if (NULL != new_hdr->header)
477 {
478 memcpy (new_hdr->header, key, key_len + 1);
479 new_hdr->header_size = key_len;
480 new_hdr->value = buf;
481 new_hdr->value_size = pos;
482 new_hdr->kind = MHD_HEADER_KIND;
483 if (value_has_close)
486 else
488 _MHD_insert_header_first (response, new_hdr);
489 return MHD_YES;
490 }
491 free (new_hdr);
492 }
493 free (buf);
494 return MHD_NO;
495 }
496
497 /* Update existing header entry */
498 free (hdr->value);
499 hdr->value = buf;
500 hdr->value_size = pos;
501 if (value_has_close && ! already_has_close)
503 return MHD_YES;
504}
505
506
516static enum MHD_Result
518 const char *value)
519{
520 struct MHD_HTTP_Res_Header *hdr;
526 if (NULL == hdr)
527 return MHD_NO;
528
530 strlen (value)))
531 return MHD_NO;
532 if (0 == hdr->value_size)
533 {
534 _MHD_remove_header (response, hdr);
535 free (hdr->value);
536 free (hdr->header);
537 free (hdr);
538 response->flags_auto &=
541 }
542 else
543 {
544 hdr->value[hdr->value_size] = 0; /* Null-terminate the result */
545 if (0 != (response->flags_auto
547 {
548 if (MHD_STATICSTR_LEN_ ("close") == hdr->value_size)
549 {
550 if (0 != memcmp (hdr->value, "close", MHD_STATICSTR_LEN_ ("close")))
551 response->flags_auto &=
553 }
554 else if (MHD_STATICSTR_LEN_ ("close, ") < hdr->value_size)
555 {
556 if (0 != memcmp (hdr->value, "close, ",
557 MHD_STATICSTR_LEN_ ("close, ")))
558 response->flags_auto &=
560 }
561 else
562 response->flags_auto &=
564 }
565 }
566 return MHD_YES;
567}
568
569
621 const char *header,
622 const char *content)
623{
625 return add_response_header_connection (response, content);
626
629 {
630 if (! MHD_str_equal_caseless_ (content, "chunked"))
631 return MHD_NO; /* Only "chunked" encoding is allowed */
632 if (0 != (response->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED))
633 return MHD_YES; /* Already has "chunked" encoding header */
634 if ( (0 != (response->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH)) &&
635 (0 == (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH & response->flags)) )
636 return MHD_NO; /* Has "Content-Length" header and no "Insanity" flag */
637 if (MHD_NO != add_response_entry (response,
639 header,
640 content))
641 {
643 return MHD_YES;
644 }
645 return MHD_NO;
646 }
649 {
650 if (0 != (response->flags_auto & MHD_RAF_HAS_DATE_HDR))
651 {
652 struct MHD_HTTP_Res_Header *hdr;
657 mhd_assert (NULL != hdr);
658 _MHD_remove_header (response, hdr);
659 if (NULL != hdr->value)
660 free (hdr->value);
661 free (hdr->header);
662 free (hdr);
663 }
664 if (MHD_NO != add_response_entry (response,
666 header,
667 content))
668 {
669 response->flags_auto |= MHD_RAF_HAS_DATE_HDR;
670 return MHD_YES;
671 }
672 return MHD_NO;
673 }
674
677 {
678 /* Generally MHD sets automatically correct "Content-Length" always when
679 * needed.
680 * Custom "Content-Length" header is allowed only in special cases. */
681 if ( (0 != (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH & response->flags)) ||
682 ((0 != (MHD_RF_HEAD_ONLY_RESPONSE & response->flags)) &&
683 (0 == (response->flags_auto & (MHD_RAF_HAS_TRANS_ENC_CHUNKED
685 {
686 if (MHD_NO != add_response_entry (response,
688 header,
689 content))
690 {
692 return MHD_YES;
693 }
694 }
695 return MHD_NO;
696 }
697
698 return add_response_entry (response,
700 header,
701 content);
702}
703
704
716 const char *footer,
717 const char *content)
718{
719 return add_response_entry (response,
721 footer,
722 content);
723}
724
725
742 const char *header,
743 const char *content)
744{
745 struct MHD_HTTP_Res_Header *pos;
746 size_t header_len;
747 size_t content_len;
748
749 if ( (NULL == header) ||
750 (NULL == content) )
751 return MHD_NO;
752 header_len = strlen (header);
753
754 if ((0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR)) &&
757 header_len))
758 return del_response_header_connection (response, content);
759
760 content_len = strlen (content);
761 pos = response->first_header;
762 while (NULL != pos)
763 {
764 if ((header_len == pos->header_size) &&
765 (content_len == pos->value_size) &&
766 (0 == memcmp (header,
767 pos->header,
768 header_len)) &&
769 (0 == memcmp (content,
770 pos->value,
771 content_len)))
772 {
773 _MHD_remove_header (response, pos);
774 free (pos->header);
775 free (pos->value);
776 free (pos);
778 header_len) &&
781 header_len) )
782 response->flags_auto &=
785 header_len) &&
788 header_len) )
789 response->flags_auto &=
792 header_len) &&
795 header_len) )
796 {
797 if (NULL == MHD_get_response_element_n_ (response,
800 header_len))
801 response->flags_auto &=
803 }
804 return MHD_YES;
805 }
806 pos = pos->next;
807 }
808 return MHD_NO;
809}
810
811
822_MHD_EXTERN int
824 MHD_KeyValueIterator iterator,
825 void *iterator_cls)
826{
827 int numHeaders = 0;
828 struct MHD_HTTP_Res_Header *pos;
829
830 for (pos = response->first_header;
831 NULL != pos;
832 pos = pos->next)
833 {
834 numHeaders++;
835 if ((NULL != iterator) &&
836 (MHD_NO == iterator (iterator_cls,
837 pos->kind,
838 pos->header,
839 pos->value)))
840 break;
841 }
842 return numHeaders;
843}
844
845
854_MHD_EXTERN const char *
856 const char *key)
857{
858 struct MHD_HTTP_Res_Header *pos;
859 size_t key_size;
860
861 if (NULL == key)
862 return NULL;
863
864 key_size = strlen (key);
865 for (pos = response->first_header;
866 NULL != pos;
867 pos = pos->next)
868 {
869 if ((pos->header_size == key_size) &&
871 return pos->value;
872 }
873 return NULL;
874}
875
876
888struct MHD_HTTP_Res_Header *
890 enum MHD_ValueKind kind,
891 const char *key,
892 size_t key_len)
893{
894 struct MHD_HTTP_Res_Header *pos;
895
896 mhd_assert (NULL != key);
897 mhd_assert (0 != key[0]);
898 mhd_assert (0 != key_len);
899
900 for (pos = response->first_header;
901 NULL != pos;
902 pos = pos->next)
903 {
904 if ((pos->header_size == key_len) &&
905 (kind == pos->kind) &&
907 return pos;
908 }
909 return NULL;
910}
911
912
929bool
931 const char *key,
932 size_t key_len,
933 const char *token,
934 size_t token_len)
935{
936 struct MHD_HTTP_Res_Header *pos;
937
938 if ( (NULL == key) ||
939 ('\0' == key[0]) ||
940 (NULL == token) ||
941 ('\0' == token[0]) )
942 return false;
943
944 /* Token must not contain binary zero! */
945 mhd_assert (strlen (token) == token_len);
946
947 for (pos = response->first_header;
948 NULL != pos;
949 pos = pos->next)
950 {
951 if ( (pos->kind == MHD_HEADER_KIND) &&
952 (key_len == pos->header_size) &&
954 key,
955 key_len) &&
957 token,
958 token_len) )
959 return true;
960 }
961 return false;
962}
963
964
988 size_t block_size,
990 void *crc_cls,
992{
993 struct MHD_Response *response;
994
995 if ((NULL == crc) || (0 == block_size))
996 return NULL;
997 if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response)
998 + block_size)))
999 return NULL;
1000 response->fd = -1;
1001 response->data = (void *) &response[1];
1002 response->data_buffer_size = block_size;
1003#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
1004 if (! MHD_mutex_init_ (&response->mutex))
1005 {
1006 free (response);
1007 return NULL;
1008 }
1009#endif
1010 response->crc = crc;
1011 response->crfc = crfc;
1012 response->crc_cls = crc_cls;
1013 response->reference_count = 1;
1014 response->total_size = size;
1015 return response;
1016}
1017
1018
1030 ...)
1031{
1032 va_list ap;
1033 enum MHD_Result ret;
1034 enum MHD_ResponseOptions ro;
1035
1036 if (0 != (response->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH))
1037 { /* Response has custom "Content-Lengh" header */
1038 if ( (0 != (response->flags & MHD_RF_INSANITY_HEADER_CONTENT_LENGTH)) &&
1040 { /* Request to remove MHD_RF_INSANITY_HEADER_CONTENT_LENGTH flag */
1041 return MHD_NO;
1042 }
1043 if ( (0 != (response->flags & MHD_RF_HEAD_ONLY_RESPONSE)) &&
1045 { /* Request to remove MHD_RF_HEAD_ONLY_RESPONSE flag */
1047 return MHD_NO;
1048 }
1049 }
1050
1051 if ( (0 != (flags & MHD_RF_HEAD_ONLY_RESPONSE)) &&
1052 (0 != response->total_size) )
1053 return MHD_NO;
1054
1055 ret = MHD_YES;
1056 response->flags = flags;
1057
1058 va_start (ap, flags);
1059 while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
1060 {
1061 switch (ro)
1062 {
1063 case MHD_RO_END: /* Not possible */
1064 break;
1065 default:
1066 ret = MHD_NO;
1067 break;
1068 }
1069 }
1070 va_end (ap);
1071 return ret;
1072}
1073
1074
1085static ssize_t
1086file_reader (void *cls,
1087 uint64_t pos,
1088 char *buf,
1089 size_t max)
1090{
1091 struct MHD_Response *response = cls;
1092#if ! defined(_WIN32) || defined(__CYGWIN__)
1093 ssize_t n;
1094#else /* _WIN32 && !__CYGWIN__ */
1095 const HANDLE fh = (HANDLE) (uintptr_t) _get_osfhandle (response->fd);
1096#endif /* _WIN32 && !__CYGWIN__ */
1097 const int64_t offset64 = (int64_t) (pos + response->fd_off);
1098
1099 if (offset64 < 0)
1100 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
1101
1102#if ! defined(_WIN32) || defined(__CYGWIN__)
1103 if (max > SSIZE_MAX)
1104 max = SSIZE_MAX; /* Clamp to maximum return value. */
1105
1106#if defined(HAVE_PREAD64)
1107 n = pread64 (response->fd, buf, max, offset64);
1108#elif defined(HAVE_PREAD)
1109 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
1110 (offset64 > (uint64_t) INT32_MAX) )
1111 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
1112
1113 n = pread (response->fd, buf, max, (off_t) offset64);
1114#else /* ! HAVE_PREAD */
1115#if defined(HAVE_LSEEK64)
1116 if (lseek64 (response->fd,
1117 offset64,
1118 SEEK_SET) != offset64)
1119 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
1120#else /* ! HAVE_LSEEK64 */
1121 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
1122 (offset64 > (uint64_t) INT32_MAX) )
1123 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
1124
1125 if (lseek (response->fd,
1126 (off_t) offset64,
1127 SEEK_SET) != (off_t) offset64)
1128 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
1129#endif /* ! HAVE_LSEEK64 */
1130 n = read (response->fd,
1131 buf,
1132 max);
1133
1134#endif /* ! HAVE_PREAD */
1135 if (0 == n)
1137 if (n < 0)
1139 return n;
1140#else /* _WIN32 && !__CYGWIN__ */
1141 if (INVALID_HANDLE_VALUE == fh)
1142 return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
1143 else
1144 {
1145 OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
1146 ULARGE_INTEGER pos_uli;
1147 DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
1148 DWORD resRead;
1149
1150 pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
1151 f_ol.Offset = pos_uli.LowPart;
1152 f_ol.OffsetHigh = pos_uli.HighPart;
1153 if (! ReadFile (fh, (void *) buf, toRead, &resRead, &f_ol))
1154 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
1155 if (0 == resRead)
1157 return (ssize_t) resRead;
1158 }
1159#endif /* _WIN32 && !__CYGWIN__ */
1160}
1161
1162
1173static ssize_t
1174pipe_reader (void *cls,
1175 uint64_t pos,
1176 char *buf,
1177 size_t max)
1178{
1179 struct MHD_Response *response = cls;
1180 ssize_t n;
1181
1182 (void) pos;
1183
1184#ifndef _WIN32
1185 if (SSIZE_MAX < max)
1186 max = SSIZE_MAX;
1187 n = read (response->fd,
1188 buf,
1189 (MHD_SCKT_SEND_SIZE_) max);
1190#else /* _WIN32 */
1191 if (UINT_MAX < max)
1192 max = INT_MAX;
1193 n = read (response->fd,
1194 buf,
1195 (unsigned int) max);
1196#endif /* _WIN32 */
1197
1198 if (0 == n)
1200 if (n < 0)
1202 return n;
1203}
1204
1205
1212static void
1213free_callback (void *cls)
1214{
1215 struct MHD_Response *response = cls;
1216
1217 (void) close (response->fd);
1218 response->fd = -1;
1219}
1220
1221
1222#undef MHD_create_response_from_fd_at_offset
1223
1249 int fd,
1250 off_t offset)
1251{
1252 if (0 > offset)
1253 return NULL;
1255 fd,
1256 (uint64_t) offset);
1257}
1258
1259
1285 int fd,
1286 uint64_t offset)
1287{
1288 struct MHD_Response *response;
1289
1290#if ! defined(HAVE___LSEEKI64) && ! defined(HAVE_LSEEK64)
1291 if ( (sizeof(uint64_t) > sizeof(off_t)) &&
1292 ( (size > (uint64_t) INT32_MAX) ||
1293 (offset > (uint64_t) INT32_MAX) ||
1294 ((size + offset) >= (uint64_t) INT32_MAX) ) )
1295 return NULL;
1296#endif
1297 if ( ((int64_t) size < 0) ||
1298 ((int64_t) offset < 0) ||
1299 ((int64_t) (size + offset) < 0) )
1300 return NULL;
1301
1302 response = MHD_create_response_from_callback (size,
1304 &file_reader,
1305 NULL,
1306 &free_callback);
1307 if (NULL == response)
1308 return NULL;
1309 response->fd = fd;
1310 response->is_pipe = false;
1311 response->fd_off = offset;
1312 response->crc_cls = response;
1313 return response;
1314}
1315
1316
1336{
1337 struct MHD_Response *response;
1338
1341 &pipe_reader,
1342 NULL,
1343 &free_callback);
1344 if (NULL == response)
1345 return NULL;
1346 response->fd = fd;
1347 response->is_pipe = true;
1348 response->crc_cls = response;
1349 return response;
1350}
1351
1352
1371 int fd)
1372{
1374 fd,
1375 0);
1376}
1377
1378
1401 int fd)
1402{
1404 fd,
1405 0);
1406}
1407
1408
1430 void *data,
1431 int must_free,
1432 int must_copy)
1433{
1434 enum MHD_ResponseMemoryMode mode;
1435
1436 if (0 != must_copy)
1437 mode = MHD_RESPMEM_MUST_COPY;
1438 else if (0 != must_free)
1439 mode = MHD_RESPMEM_MUST_FREE;
1440 else
1442
1443 return MHD_create_response_from_buffer (size, data, mode);
1444}
1445
1446
1466 void *buffer,
1467 enum MHD_ResponseMemoryMode mode)
1468{
1469 if (MHD_RESPMEM_MUST_FREE == mode)
1471 buffer,
1472 &free,
1473 buffer);
1474 if (MHD_RESPMEM_MUST_COPY == mode)
1476 buffer);
1477
1479 buffer,
1480 NULL,
1481 NULL);
1482}
1483
1484
1508 const void *buffer)
1509{
1511 buffer,
1512 NULL,
1513 NULL);
1514}
1515
1516
1541 const void *buffer)
1542{
1543 struct MHD_Response *r;
1544 void *mhd_copy;
1545
1546 if (0 == size)
1548 NULL,
1549 NULL,
1550 NULL);
1551 if (NULL == buffer)
1552 return NULL;
1553
1554 mhd_copy = malloc (size);
1555 if (NULL == mhd_copy)
1556 return NULL;
1557 memcpy (mhd_copy, buffer, size);
1558
1560 mhd_copy,
1561 &free,
1562 mhd_copy);
1563 if (NULL == r)
1564 free (mhd_copy);
1565 else
1566 {
1567 /* TODO: remove the next assignment, the buffer should not be modifiable */
1568 r->data_buffer_size = size;
1569 }
1570
1571 return r;
1572}
1573
1574
1594 void *buffer,
1596 crfc)
1597{
1599 buffer,
1600 crfc,
1601 buffer);
1602}
1603
1604
1628 const void *buffer,
1630 crfc,
1631 void *crfc_cls)
1632{
1633 struct MHD_Response *r;
1634
1635 if ((NULL == buffer) && (size > 0))
1636 return NULL;
1637#if SIZEOF_SIZE_T >= SIZEOF_UINT64_T
1638 if (MHD_SIZE_UNKNOWN == size)
1639 return NULL;
1640#endif /* SIZEOF_SIZE_T >= SIZEOF_UINT64_T */
1641 r = MHD_calloc_ (1, sizeof (struct MHD_Response));
1642 if (NULL == r)
1643 return NULL;
1644#if defined(MHD_USE_THREADS)
1645 if (! MHD_mutex_init_ (&r->mutex))
1646 {
1647 free (r);
1648 return NULL;
1649 }
1650#endif
1651 r->fd = -1;
1652 r->reference_count = 1;
1653 r->total_size = size;
1654 r->data = buffer;
1655 r->data_size = size;
1656 r->crfc = crfc;
1657 r->crc_cls = crfc_cls;
1658 return r;
1659}
1660
1661
1683 unsigned int iovcnt,
1685 void *cls)
1686{
1687 struct MHD_Response *response;
1688 unsigned int i;
1689 int i_cp = 0;
1690 uint64_t total_size = 0;
1691 const void *last_valid_buffer = NULL;
1692
1693 if ((NULL == iov) && (0 < iovcnt))
1694 return NULL;
1695
1696 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
1697 if (NULL == response)
1698 return NULL;
1699 if (! MHD_mutex_init_ (&response->mutex))
1700 {
1701 free (response);
1702 return NULL;
1703 }
1704 /* Calculate final size, number of valid elements, and check 'iov' */
1705 for (i = 0; i < iovcnt; ++i)
1706 {
1707 if (0 == iov[i].iov_len)
1708 continue; /* skip zero-sized elements */
1709 if (NULL == iov[i].iov_base)
1710 {
1711 i_cp = -1; /* error */
1712 break;
1713 }
1714 if ( (total_size > (total_size + iov[i].iov_len)) ||
1715 (INT_MAX == i_cp) ||
1716 (SSIZE_MAX < (total_size + iov[i].iov_len)) )
1717 {
1718 i_cp = -1; /* overflow */
1719 break;
1720 }
1721 last_valid_buffer = iov[i].iov_base;
1722 total_size += iov[i].iov_len;
1723#if defined(MHD_POSIX_SOCKETS) || ! defined(_WIN64)
1724 i_cp++;
1725#else /* ! MHD_POSIX_SOCKETS && _WIN64 */
1726 {
1727 int64_t i_add;
1728
1729 i_add = (int64_t) (iov[i].iov_len / ULONG_MAX);
1730 if (0 != iov[i].iov_len % ULONG_MAX)
1731 i_add++;
1732 if (INT_MAX < (i_add + i_cp))
1733 {
1734 i_cp = -1; /* overflow */
1735 break;
1736 }
1737 i_cp += (int) i_add;
1738 }
1739#endif /* ! MHD_POSIX_SOCKETS && _WIN64 */
1740 }
1741 if (-1 == i_cp)
1742 {
1743 /* Some error condition */
1744 MHD_mutex_destroy_chk_ (&response->mutex);
1745 free (response);
1746 return NULL;
1747 }
1748 response->fd = -1;
1749 response->reference_count = 1;
1750 response->total_size = total_size;
1751 response->crc_cls = cls;
1752 response->crfc = free_cb;
1753 if (0 == i_cp)
1754 {
1755 mhd_assert (0 == total_size);
1756 return response;
1757 }
1758 if (1 == i_cp)
1759 {
1760 mhd_assert (NULL != last_valid_buffer);
1761 response->data = last_valid_buffer;
1762 response->data_size = (size_t) total_size;
1763 return response;
1764 }
1765 mhd_assert (1 < i_cp);
1766 if (1)
1767 { /* for local variables local scope only */
1768 MHD_iovec_ *iov_copy;
1769 int num_copy_elements = i_cp;
1770
1771 iov_copy = MHD_calloc_ ((size_t) num_copy_elements, \
1772 sizeof(MHD_iovec_));
1773 if (NULL == iov_copy)
1774 {
1775 MHD_mutex_destroy_chk_ (&response->mutex);
1776 free (response);
1777 return NULL;
1778 }
1779 i_cp = 0;
1780 for (i = 0; i < iovcnt; ++i)
1781 {
1782 size_t element_size = iov[i].iov_len;
1783 const uint8_t *buf = (const uint8_t *) iov[i].iov_base;
1784
1785 if (0 == element_size)
1786 continue; /* skip zero-sized elements */
1787#if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64)
1788 while (MHD_IOV_ELMN_MAX_SIZE < element_size)
1789 {
1790 iov_copy[i_cp].iov_base = (char *) _MHD_DROP_CONST (buf);
1791 iov_copy[i_cp].iov_len = ULONG_MAX;
1792 buf += ULONG_MAX;
1793 element_size -= ULONG_MAX;
1794 i_cp++;
1795 }
1796#endif /* MHD_WINSOCK_SOCKETS && _WIN64 */
1797 iov_copy[i_cp].iov_base = _MHD_DROP_CONST (buf);
1798 iov_copy[i_cp].iov_len = (MHD_iov_size_) element_size;
1799 i_cp++;
1800 }
1801 mhd_assert (num_copy_elements == i_cp);
1802 mhd_assert (0 <= i_cp);
1803 response->data_iov = iov_copy;
1804 response->data_iovcnt = (unsigned int) i_cp;
1805 }
1806 return response;
1807}
1808
1809
1827{
1828 struct MHD_Response *r;
1829 r = (struct MHD_Response *) MHD_calloc_ (1, sizeof (struct MHD_Response));
1830 if (NULL != r)
1831 {
1832 if (MHD_mutex_init_ (&r->mutex))
1833 {
1834 r->fd = -1;
1835 r->reference_count = 1;
1836 /* If any flags combination will be not allowed, replace the next
1837 * assignment with MHD_set_response_options() call. */
1838 r->flags = flags;
1839
1840 return r; /* Successful result */
1841 }
1842 free (r);
1843 }
1844 return NULL; /* Something failed */
1845}
1846
1847
1848#ifdef UPGRADE_SUPPORT
1862MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
1864 ...)
1865{
1866 struct MHD_Connection *connection;
1867 struct MHD_Daemon *daemon;
1868
1869 if (NULL == urh)
1870 return MHD_NO;
1871 connection = urh->connection;
1872
1873 /* Precaution checks on external data. */
1874 if (NULL == connection)
1875 return MHD_NO;
1876 daemon = connection->daemon;
1877 if (NULL == daemon)
1878 return MHD_NO;
1879
1880 switch (action)
1881 {
1883 if (urh->was_closed)
1884 return MHD_NO; /* Already closed. */
1885
1886 /* transition to special 'closed' state for start of cleanup */
1887#ifdef HTTPS_SUPPORT
1888 if (0 != (daemon->options & MHD_USE_TLS) )
1889 {
1890 /* signal that app is done by shutdown() of 'app' socket */
1891 /* Application will not use anyway this socket after this command. */
1892 shutdown (urh->app.socket,
1893 SHUT_RDWR);
1894 }
1895#endif /* HTTPS_SUPPORT */
1896 mhd_assert (MHD_CONNECTION_UPGRADE == connection->state);
1897 /* The next function will mark the connection as closed by application
1898 * by setting 'urh->was_closed'.
1899 * As soon as connection will be marked with BOTH
1900 * 'urh->was_closed' AND 'urh->clean_ready', it will
1901 * be moved to cleanup list by MHD_resume_connection(). */
1902 MHD_upgraded_connection_mark_app_closed_ (connection);
1903 return MHD_YES;
1905 /* Unportable API. TODO: replace with portable action. */
1906 return MHD_connection_set_cork_state_ (connection,
1907 true) ? MHD_YES : MHD_NO;
1909 /* Unportable API. TODO: replace with portable action. */
1910 return MHD_connection_set_cork_state_ (connection,
1911 false) ? MHD_YES : MHD_NO;
1912 default:
1913 /* we don't understand this one */
1914 return MHD_NO;
1915 }
1916}
1917
1918
1932enum MHD_Result
1934 struct MHD_Connection *connection)
1935{
1936#if defined(HTTPS_SUPPORT) || defined(_DEBUG) || defined(HAVE_MESSAGES)
1937 struct MHD_Daemon *const daemon = connection->daemon;
1938#endif /* HTTPS_SUPPORT || _DEBUG || HAVE_MESSAGES */
1939 struct MHD_UpgradeResponseHandle *urh;
1940 size_t rbo;
1941
1942#ifdef MHD_USE_THREADS
1943 mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
1944 MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
1945#endif /* MHD_USE_THREADS */
1946
1947 /* "Upgrade" responses accepted only if MHD_ALLOW_UPGRADE is enabled */
1948 mhd_assert (0 != (daemon->options & MHD_ALLOW_UPGRADE));
1949 /* The header was checked when response queued */
1950 mhd_assert (NULL != \
1955
1956 if (! connection->sk_nonblck)
1957 {
1958#ifdef HAVE_MESSAGES
1959 MHD_DLOG (daemon,
1960 _ ("Cannot execute \"upgrade\" as the socket is in " \
1961 "the blocking mode.\n"));
1962#endif
1963 return MHD_NO;
1964 }
1965 urh = MHD_calloc_ (1, sizeof (struct MHD_UpgradeResponseHandle));
1966 if (NULL == urh)
1967 return MHD_NO;
1968 urh->connection = connection;
1969 rbo = connection->read_buffer_offset;
1970 connection->read_buffer_offset = 0;
1971 MHD_connection_set_nodelay_state_ (connection, false);
1972 MHD_connection_set_cork_state_ (connection, false);
1973#ifdef HTTPS_SUPPORT
1974 if (0 != (daemon->options & MHD_USE_TLS) )
1975 {
1976 MHD_socket sv[2];
1977#if defined(MHD_socket_nosignal_) || ! defined(MHD_socket_pair_nblk_)
1978 int res1;
1979 int res2;
1980#endif /* MHD_socket_nosignal_ || !MHD_socket_pair_nblk_ */
1981
1982#ifdef MHD_socket_pair_nblk_
1983 if (! MHD_socket_pair_nblk_ (sv))
1984 {
1985 free (urh);
1986 return MHD_NO;
1987 }
1988#else /* !MHD_socket_pair_nblk_ */
1989 if (! MHD_socket_pair_ (sv))
1990 {
1991 free (urh);
1992 return MHD_NO;
1993 }
1994 res1 = MHD_socket_nonblocking_ (sv[0]);
1995 res2 = MHD_socket_nonblocking_ (sv[1]);
1996 if ( (! res1) || (! res2) )
1997 {
1998#ifdef HAVE_MESSAGES
1999 MHD_DLOG (daemon,
2000 _ ("Failed to make loopback sockets non-blocking.\n"));
2001#endif
2002 if (! res2)
2003 {
2004 /* Socketpair cannot be used. */
2005 MHD_socket_close_chk_ (sv[0]);
2006 MHD_socket_close_chk_ (sv[1]);
2007 free (urh);
2008 return MHD_NO;
2009 }
2010 }
2011#endif /* !MHD_socket_pair_nblk_ */
2012#ifdef MHD_socket_nosignal_
2013 res1 = MHD_socket_nosignal_ (sv[0]);
2014 res2 = MHD_socket_nosignal_ (sv[1]);
2015 if ( (! res1) || (! res2) )
2016 {
2017#ifdef HAVE_MESSAGES
2018 MHD_DLOG (daemon,
2019 _ ("Failed to set SO_NOSIGPIPE on loopback sockets.\n"));
2020#endif
2021#ifndef MSG_NOSIGNAL
2022 if (! res2)
2023 {
2024 /* Socketpair cannot be used. */
2025 MHD_socket_close_chk_ (sv[0]);
2026 MHD_socket_close_chk_ (sv[1]);
2027 free (urh);
2028 return MHD_NO;
2029 }
2030#endif /* ! MSG_NOSIGNAL */
2031 }
2032#endif /* MHD_socket_nosignal_ */
2033 if (MHD_D_IS_USING_SELECT_ (daemon) &&
2034 (! MHD_D_DOES_SCKT_FIT_FDSET_ (sv[1], daemon)) )
2035 {
2036#ifdef HAVE_MESSAGES
2037 MHD_DLOG (daemon,
2038 _ ("Socketpair descriptor is not less than FD_SETSIZE: " \
2039 "%d >= %d\n"),
2040 (int) sv[1],
2041 (int) MHD_D_GET_FD_SETSIZE_ (daemon));
2042#endif
2043 MHD_socket_close_chk_ (sv[0]);
2044 MHD_socket_close_chk_ (sv[1]);
2045 free (urh);
2046 return MHD_NO;
2047 }
2048 urh->app.socket = sv[0];
2049 urh->app.urh = urh;
2050 urh->app.celi = MHD_EPOLL_STATE_UNREADY;
2051 urh->mhd.socket = sv[1];
2052 urh->mhd.urh = urh;
2053 urh->mhd.celi = MHD_EPOLL_STATE_UNREADY;
2054#ifdef EPOLL_SUPPORT
2055 /* Launch IO processing by the event loop */
2056 if (MHD_D_IS_USING_EPOLL_ (daemon))
2057 {
2058 /* We're running with epoll(), need to add the sockets
2059 to the event set of the daemon's `epoll_upgrade_fd` */
2060 struct epoll_event event;
2061
2062 mhd_assert (-1 != daemon->epoll_upgrade_fd);
2063 /* First, add network socket */
2064 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2065 event.data.ptr = &urh->app;
2066 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2067 EPOLL_CTL_ADD,
2068 connection->socket_fd,
2069 &event))
2070 {
2071#ifdef HAVE_MESSAGES
2072 MHD_DLOG (daemon,
2073 _ ("Call to epoll_ctl failed: %s\n"),
2075#endif
2076 MHD_socket_close_chk_ (sv[0]);
2077 MHD_socket_close_chk_ (sv[1]);
2078 free (urh);
2079 return MHD_NO;
2080 }
2081
2082 /* Second, add our end of the UNIX socketpair() */
2083 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2084 event.data.ptr = &urh->mhd;
2085 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2086 EPOLL_CTL_ADD,
2087 urh->mhd.socket,
2088 &event))
2089 {
2090 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
2091 event.data.ptr = &urh->app;
2092 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2093 EPOLL_CTL_DEL,
2094 connection->socket_fd,
2095 &event))
2096 MHD_PANIC (_ ("Error cleaning up while handling epoll error.\n"));
2097#ifdef HAVE_MESSAGES
2098 MHD_DLOG (daemon,
2099 _ ("Call to epoll_ctl failed: %s\n"),
2101#endif
2102 MHD_socket_close_chk_ (sv[0]);
2103 MHD_socket_close_chk_ (sv[1]);
2104 free (urh);
2105 return MHD_NO;
2106 }
2107 EDLL_insert (daemon->eready_urh_head,
2108 daemon->eready_urh_tail,
2109 urh);
2110 urh->in_eready_list = true;
2111 }
2112#endif /* EPOLL_SUPPORT */
2113 if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
2114 {
2115 /* This takes care of further processing for most event loops:
2116 simply add to DLL for bi-direcitonal processing */
2117 DLL_insert (daemon->urh_head,
2118 daemon->urh_tail,
2119 urh);
2120 }
2121 /* In thread-per-connection mode, thread will switch to forwarding once
2122 * connection.urh is not NULL and connection.state == MHD_CONNECTION_UPGRADE.
2123 */
2124 }
2125 else
2126 {
2127 urh->app.socket = MHD_INVALID_SOCKET;
2128 urh->mhd.socket = MHD_INVALID_SOCKET;
2129 /* Non-TLS connection do not hold any additional resources. */
2130 urh->clean_ready = true;
2131 }
2132#else /* ! HTTPS_SUPPORT */
2133 urh->clean_ready = true;
2134#endif /* ! HTTPS_SUPPORT */
2135 connection->urh = urh;
2136 /* As far as MHD's event loops are concerned, this connection is
2137 suspended; it will be resumed once application is done by the
2138 #MHD_upgrade_action() function */
2139 internal_suspend_connection_ (connection);
2140
2141 /* hand over socket to application */
2142 response->upgrade_handler (response->upgrade_handler_cls,
2143 connection,
2144 connection->rq.client_context,
2145 connection->read_buffer,
2146 rbo,
2147#ifdef HTTPS_SUPPORT
2148 (0 == (daemon->options & MHD_USE_TLS) ) ?
2149 connection->socket_fd : urh->app.socket,
2150#else /* ! HTTPS_SUPPORT */
2151 connection->socket_fd,
2152#endif /* ! HTTPS_SUPPORT */
2153 urh);
2154
2155#ifdef HTTPS_SUPPORT
2156 if (0 != (daemon->options & MHD_USE_TLS))
2157 {
2158 struct MemoryPool *const pool = connection->pool;
2159 size_t avail;
2160 char *buf;
2161
2162 /* All data should be sent already */
2163 mhd_assert (connection->write_buffer_send_offset == \
2164 connection->write_buffer_append_offset);
2165 MHD_pool_deallocate (pool, connection->write_buffer,
2166 connection->write_buffer_size);
2167 connection->write_buffer_append_offset = 0;
2168 connection->write_buffer_send_offset = 0;
2169 connection->write_buffer_size = 0;
2170 connection->write_buffer = NULL;
2171
2172 /* Extra read data should be processed already by the application */
2173 MHD_pool_deallocate (pool, connection->read_buffer,
2174 connection->read_buffer_size);
2175 connection->read_buffer_offset = 0;
2176 connection->read_buffer_size = 0;
2177 connection->read_buffer = NULL;
2178
2179 avail = MHD_pool_get_free (pool);
2180 if (avail < RESERVE_EBUF_SIZE)
2181 {
2182 /* connection's pool is totally at the limit,
2183 use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
2184 avail = RESERVE_EBUF_SIZE;
2185 buf = urh->e_buf;
2186#ifdef HAVE_MESSAGES
2187 MHD_DLOG (daemon,
2188 _ ("Memory shortage in connection's memory pool. " \
2189 "The \"upgraded\" communication will be inefficient.\n"));
2190#endif
2191 }
2192 else
2193 {
2194 /* Normal case: grab all remaining memory from the
2195 connection's pool for the IO buffers; the connection
2196 certainly won't need it anymore as we've upgraded
2197 to another protocol. */
2198 buf = MHD_pool_allocate (pool,
2199 avail,
2200 false);
2201 }
2202 /* use half the buffer for inbound, half for outbound */
2203 urh->in_buffer_size = avail / 2;
2204 urh->out_buffer_size = avail - urh->in_buffer_size;
2205 urh->in_buffer = buf;
2206 urh->out_buffer = buf + urh->in_buffer_size;
2207 }
2208#endif /* HTTPS_SUPPORT */
2209 return MHD_YES;
2210}
2211
2212
2244 void *upgrade_handler_cls)
2245{
2246 struct MHD_Response *response;
2247
2248 if (NULL == upgrade_handler)
2249 return NULL; /* invalid request */
2250 response = MHD_calloc_ (1, sizeof (struct MHD_Response));
2251 if (NULL == response)
2252 return NULL;
2253#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2254 if (! MHD_mutex_init_ (&response->mutex))
2255 {
2256 free (response);
2257 return NULL;
2258 }
2259#endif
2260 response->upgrade_handler = upgrade_handler;
2261 response->upgrade_handler_cls = upgrade_handler_cls;
2262 response->total_size = 0;
2263 response->reference_count = 1;
2264 if (MHD_NO ==
2265 MHD_add_response_header (response,
2267 "Upgrade"))
2268 {
2269 MHD_destroy_response (response);
2270 return NULL;
2271 }
2272 return response;
2273}
2274
2275
2276#endif /* UPGRADE_SUPPORT */
2277
2278
2288_MHD_EXTERN void
2290{
2291 struct MHD_HTTP_Res_Header *pos;
2292
2293 if (NULL == response)
2294 return;
2295#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2296 MHD_mutex_lock_chk_ (&response->mutex);
2297#endif
2298 if (0 != --(response->reference_count))
2299 {
2300#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2301 MHD_mutex_unlock_chk_ (&response->mutex);
2302#endif
2303 return;
2304 }
2305#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2306 MHD_mutex_unlock_chk_ (&response->mutex);
2307 MHD_mutex_destroy_chk_ (&response->mutex);
2308#endif
2309 if (NULL != response->crfc)
2310 response->crfc (response->crc_cls);
2311
2312 if (NULL != response->data_iov)
2313 {
2314 free (response->data_iov);
2315 }
2316
2317 while (NULL != response->first_header)
2318 {
2319 pos = response->first_header;
2320 response->first_header = pos->next;
2321 free (pos->header);
2322 free (pos->value);
2323 free (pos);
2324 }
2325 free (response);
2326}
2327
2328
2334void
2336{
2337#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2338 MHD_mutex_lock_chk_ (&response->mutex);
2339#endif
2340 (response->reference_count)++;
2341#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2342 MHD_mutex_unlock_chk_ (&response->mutex);
2343#endif
2344}
2345
2346
2347/* 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:590
#define MHD_HTTP_HEADER_CONNECTION
Definition microhttpd.h:584
#define MHD_HTTP_HEADER_DATE
Definition microhttpd.h:598
#define MHD_HTTP_HEADER_TRANSFER_ENCODING
Definition microhttpd.h:648
#define MHD_HTTP_HEADER_UPGRADE
Definition microhttpd.h:650
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:823
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback(size_t size, void *buffer, MHD_ContentReaderFreeCallback crfc)
Definition response.c:1593
_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:1682
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_data(size_t size, void *data, int must_free, int must_copy)
Definition response.c:1429
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_copy(size_t size, const void *buffer)
Definition response.c:1540
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer(size_t size, void *buffer, enum MHD_ResponseMemoryMode mode)
Definition response.c:1465
_MHD_EXTERN enum MHD_Result MHD_del_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:741
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_pipe(int fd)
Definition response.c:1335
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition response.c:2289
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:889
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd(size_t size, int fd)
Definition response.c:1370
_MHD_EXTERN struct MHD_Response * MHD_create_response_empty(enum MHD_ResponseFlags flags)
Definition response.c:1826
MHD_ResponseMemoryMode
_MHD_EXTERN const char * MHD_get_response_header(struct MHD_Response *response, const char *key)
Definition response.c:855
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_static(size_t size, const void *buffer)
Definition response.c:1507
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:1284
_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:1627
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:620
_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:987
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_fd64(uint64_t size, int fd)
Definition response.c:1400
_MHD_EXTERN enum MHD_Result MHD_add_response_footer(struct MHD_Response *response, const char *footer, const char *content)
Definition response.c:715
@ MHD_RESPMEM_MUST_FREE
@ MHD_RESPMEM_PERSISTENT
@ 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
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)
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: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.
MHD internal shared structures.
#define MHD_D_DOES_SCKT_FIT_FDSET_(sckt, d)
Definition internal.h:2601
#define MHD_D_IS_USING_SELECT_(d)
Definition internal.h:2542
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:2595
#define MHD_D_IS_USING_THREAD_PER_CONN_(d)
Definition internal.h:2578
#define MHD_D_IS_USING_THREADS_(d)
Definition internal.h:2574
#define MHD_D_IS_USING_EPOLL_(d)
Definition internal.h:2550
#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
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:121
#define INT_MAX
Definition mhd_limits.h:45
#define MHD_mutex_init_(ignore)
Definition mhd_locks.h:192
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_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_thread_handle_ID_is_current_thread_(hndl_id)
static void free_callback(void *cls)
Definition response.c:1213
#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:930
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:328
#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:1086
static enum MHD_Result del_response_header_connection(struct MHD_Response *response, const char *value)
Definition response.c:517
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:1174
void MHD_increment_response_rc(struct MHD_Response *response)
Definition response.c:2335
_MHD_EXTERN enum MHD_Result MHD_set_response_options(struct MHD_Response *response, enum MHD_ResponseFlags flags,...)
Definition response.c:1028
int MHD_socket
Definition microhttpd.h:201
#define MHD_SIZE_UNKNOWN
Definition microhttpd.h:178
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:181
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:202
ssize_t(* MHD_ContentReaderCallback)(void *cls, uint64_t pos, char *buf, size_t max)
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition microhttpd.h:182
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,...)
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:1441
size_t write_buffer_send_offset
Definition internal.h:1446
size_t write_buffer_append_offset
Definition internal.h:1452
char * write_buffer
Definition internal.h:1409
struct MHD_Request rq
Definition internal.h:1365
struct MemoryPool * pool
Definition internal.h:685
size_t read_buffer_offset
Definition internal.h:1436
enum MHD_CONNECTION_STATE state
Definition internal.h:1565
char * read_buffer
Definition internal.h:1403
struct MHD_Daemon * daemon
Definition internal.h:675
size_t read_buffer_size
Definition internal.h:1430
volatile bool shutdown
Definition internal.h:1526
enum MHD_FLAG options
Definition internal.h:1880
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:401
MHD_ContentReaderFreeCallback crfc
Definition internal.h:1606
void * crc_cls
Definition internal.h:1594
size_t data_buffer_size
Definition internal.h:1664
MHD_iovec_ * data_iov
Definition internal.h:588
MHD_ContentReaderCallback crc
Definition internal.h:1600
struct MHD_Action action
Definition internal.h:1575
enum MHD_ResponseAutoFlags flags_auto
Definition internal.h:578
unsigned int data_iovcnt
Definition internal.h:593
size_t data_size
Definition internal.h:1659
enum MHD_ResponseFlags flags
Definition internal.h:573
char * data
Definition internal.h:1588
unsigned int reference_count
Definition internal.h:1675
MHD_mutex_ mutex
Definition internal.h:1637
uint64_t total_size
Definition internal.h:1642
uint64_t fd_off
Definition internal.h:1653
struct MHD_HTTP_Header * first_header
Definition internal.h:1582