diff options
Diffstat (limited to 'src/microhttpd/response.c')
-rw-r--r-- | src/microhttpd/response.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 4ae46bf3..3dbcd245 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -846,6 +846,153 @@ MHD_create_response_from_buffer_with_free_callback (size_t size, | |||
846 | } | 846 | } |
847 | 847 | ||
848 | 848 | ||
849 | /** | ||
850 | * Create a response object from an array of memory buffers. | ||
851 | * The response object can be extended with header information and then be used | ||
852 | * any number of times. | ||
853 | * | ||
854 | * @param iov the array for response data buffers, an internal copy of this | ||
855 | * will be made | ||
856 | * @param iovcnt the number of elements in @a iov | ||
857 | * @param free_cb the callback to clean up any data associated with @a iov when | ||
858 | * the response is destroyed. | ||
859 | * @param cls the argument passed to @a free_cb | ||
860 | * @return NULL on error (i.e. invalid arguments, out of memory) | ||
861 | */ | ||
862 | _MHD_EXTERN struct MHD_Response * | ||
863 | MHD_create_response_from_iovec (const struct MHD_IoVec *iov, | ||
864 | int iovcnt, | ||
865 | MHD_ContentReaderFreeCallback free_cb, | ||
866 | void *cls) | ||
867 | { | ||
868 | struct MHD_Response *response; | ||
869 | |||
870 | if ((NULL == iov) && (0 < iovcnt)) | ||
871 | return NULL; | ||
872 | |||
873 | response = MHD_calloc_ (1, sizeof (struct MHD_Response)); | ||
874 | if (NULL != response) | ||
875 | { | ||
876 | if (MHD_mutex_init_ (&response->mutex)) | ||
877 | { | ||
878 | int i; | ||
879 | int i_cp; /**< Index in the copy of iov */ | ||
880 | uint64_t total_size; | ||
881 | void *last_valid_buffer; | ||
882 | |||
883 | i_cp = 0; | ||
884 | total_size = 0; | ||
885 | last_valid_buffer = NULL; | ||
886 | /* Calculate final size, number of valid elements, and check 'iov' */ | ||
887 | for (i = 0; iovcnt > i; ++i) | ||
888 | { | ||
889 | #if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64) | ||
890 | int64_t i_add; | ||
891 | #endif /* ! MHD_WINSOCK_SOCKETS && _WIN64 */ | ||
892 | if (0 == iov[i].iov_len) | ||
893 | continue; /* skip zero-sized elements */ | ||
894 | |||
895 | if (NULL == iov[i].iov_base) | ||
896 | { | ||
897 | i_cp = -1; /* error */ | ||
898 | break; | ||
899 | } | ||
900 | if ( (total_size > (total_size + iov[i].iov_len)) || | ||
901 | (INT_MAX == i_cp) || | ||
902 | (SSIZE_MAX < iov[i].iov_len) ) | ||
903 | { | ||
904 | i_cp = -1; /* overflow */ | ||
905 | break; | ||
906 | } | ||
907 | last_valid_buffer = iov[i].iov_base; | ||
908 | total_size += iov[i].iov_len; | ||
909 | #if defined(MHD_POSIX_SOCKETS) || ! defined(_WIN64) | ||
910 | i_cp++; | ||
911 | #else /* ! MHD_POSIX_SOCKETS && _WIN64 */ | ||
912 | i_add = iov[i].iov_len / ULONG_MAX; | ||
913 | if (0 != iov[i].iov_len % ULONG_MAX) | ||
914 | i_add++; | ||
915 | if (INT_MAX < (i_add + i_cp)) | ||
916 | { | ||
917 | i_cp = -1; /* overflow */ | ||
918 | break; | ||
919 | } | ||
920 | i_cp += (int) i_add; | ||
921 | #endif /* ! MHD_POSIX_SOCKETS && _WIN64 */ | ||
922 | } | ||
923 | if (0 <= i_cp) | ||
924 | { | ||
925 | response->fd = -1; | ||
926 | response->reference_count = 1; | ||
927 | response->total_size = total_size; | ||
928 | response->crc_cls = cls; | ||
929 | response->crfc = free_cb; | ||
930 | if (1 < i_cp) | ||
931 | { | ||
932 | MHD_iovec_ *iov_copy; | ||
933 | int num_copy_elements = i_cp; | ||
934 | |||
935 | iov_copy = MHD_calloc_ (num_copy_elements, sizeof(MHD_iovec_)); | ||
936 | if (NULL != iov_copy) | ||
937 | { | ||
938 | i_cp = 0; | ||
939 | for (i = 0; iovcnt > i; ++i) | ||
940 | { | ||
941 | size_t element_size; | ||
942 | uint8_t *buf; | ||
943 | |||
944 | if (0 == iov[i].iov_len) | ||
945 | continue; /* skip zero-sized elements */ | ||
946 | |||
947 | buf = (uint8_t*) iov[i].iov_base; | ||
948 | element_size = iov[i].iov_len; | ||
949 | #if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64) | ||
950 | while (ULONG_MAX < element_size) | ||
951 | { | ||
952 | iov_copy[i_cp].iov_base = (void*) buf; | ||
953 | iov_copy[i_cp].iov_len = ULONG_MAX; | ||
954 | buf += ULONG_MAX; | ||
955 | element_size -= ULONG_MAX; | ||
956 | i_cp++; | ||
957 | } | ||
958 | #endif /* MHD_WINSOCK_SOCKETS && _WIN64 */ | ||
959 | iov_copy[i_cp].iov_base = (void*) buf; | ||
960 | iov_copy[i_cp].iov_len = element_size; | ||
961 | i_cp++; | ||
962 | } | ||
963 | |||
964 | mhd_assert (num_copy_elements == i_cp); | ||
965 | response->data_iov = iov_copy; | ||
966 | response->data_iovcnt = i_cp; | ||
967 | |||
968 | return response; | ||
969 | } | ||
970 | |||
971 | } | ||
972 | else if (1 == i_cp) | ||
973 | { | ||
974 | mhd_assert (NULL != last_valid_buffer); | ||
975 | response->data = last_valid_buffer; | ||
976 | response->data_size = total_size; | ||
977 | |||
978 | return response; | ||
979 | } | ||
980 | else /* if (0 == i_nz) */ | ||
981 | { | ||
982 | mhd_assert (0 == total_size); | ||
983 | |||
984 | return response; | ||
985 | } | ||
986 | } | ||
987 | /* Some error condition */ | ||
988 | MHD_mutex_destroy_chk_ (&response->mutex); | ||
989 | } | ||
990 | free (response); | ||
991 | } | ||
992 | return NULL; | ||
993 | } | ||
994 | |||
995 | |||
849 | #ifdef UPGRADE_SUPPORT | 996 | #ifdef UPGRADE_SUPPORT |
850 | /** | 997 | /** |
851 | * This connection-specific callback is provided by MHD to | 998 | * This connection-specific callback is provided by MHD to |
@@ -1287,6 +1434,12 @@ MHD_destroy_response (struct MHD_Response *response) | |||
1287 | #endif | 1434 | #endif |
1288 | if (NULL != response->crfc) | 1435 | if (NULL != response->crfc) |
1289 | response->crfc (response->crc_cls); | 1436 | response->crfc (response->crc_cls); |
1437 | |||
1438 | if (NULL != response->data_iov) | ||
1439 | { | ||
1440 | free (response->data_iov); | ||
1441 | } | ||
1442 | |||
1290 | while (NULL != response->first_header) | 1443 | while (NULL != response->first_header) |
1291 | { | 1444 | { |
1292 | pos = response->first_header; | 1445 | pos = response->first_header; |