summaryrefslogtreecommitdiff
path: root/src/microhttpd/response.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/response.c')
-rw-r--r--src/microhttpd/response.c153
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,
}
+/**
+ * Create a response object from an array of memory buffers.
+ * The response object can be extended with header information and then be used
+ * any number of times.
+ *
+ * @param iov the array for response data buffers, an internal copy of this
+ * will be made
+ * @param iovcnt the number of elements in @a iov
+ * @param free_cb the callback to clean up any data associated with @a iov when
+ * the response is destroyed.
+ * @param cls the argument passed to @a free_cb
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_from_iovec (const struct MHD_IoVec *iov,
+ int iovcnt,
+ MHD_ContentReaderFreeCallback free_cb,
+ void *cls)
+{
+ struct MHD_Response *response;
+
+ if ((NULL == iov) && (0 < iovcnt))
+ return NULL;
+
+ response = MHD_calloc_ (1, sizeof (struct MHD_Response));
+ if (NULL != response)
+ {
+ if (MHD_mutex_init_ (&response->mutex))
+ {
+ int i;
+ int i_cp; /**< Index in the copy of iov */
+ uint64_t total_size;
+ void *last_valid_buffer;
+
+ i_cp = 0;
+ total_size = 0;
+ last_valid_buffer = NULL;
+ /* Calculate final size, number of valid elements, and check 'iov' */
+ for (i = 0; iovcnt > i; ++i)
+ {
+#if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64)
+ int64_t i_add;
+#endif /* ! MHD_WINSOCK_SOCKETS && _WIN64 */
+ if (0 == iov[i].iov_len)
+ continue; /* skip zero-sized elements */
+
+ if (NULL == iov[i].iov_base)
+ {
+ i_cp = -1; /* error */
+ break;
+ }
+ if ( (total_size > (total_size + iov[i].iov_len)) ||
+ (INT_MAX == i_cp) ||
+ (SSIZE_MAX < iov[i].iov_len) )
+ {
+ i_cp = -1; /* overflow */
+ break;
+ }
+ last_valid_buffer = iov[i].iov_base;
+ total_size += iov[i].iov_len;
+#if defined(MHD_POSIX_SOCKETS) || ! defined(_WIN64)
+ i_cp++;
+#else /* ! MHD_POSIX_SOCKETS && _WIN64 */
+ i_add = iov[i].iov_len / ULONG_MAX;
+ if (0 != iov[i].iov_len % ULONG_MAX)
+ i_add++;
+ if (INT_MAX < (i_add + i_cp))
+ {
+ i_cp = -1; /* overflow */
+ break;
+ }
+ i_cp += (int) i_add;
+#endif /* ! MHD_POSIX_SOCKETS && _WIN64 */
+ }
+ if (0 <= i_cp)
+ {
+ response->fd = -1;
+ response->reference_count = 1;
+ response->total_size = total_size;
+ response->crc_cls = cls;
+ response->crfc = free_cb;
+ if (1 < i_cp)
+ {
+ MHD_iovec_ *iov_copy;
+ int num_copy_elements = i_cp;
+
+ iov_copy = MHD_calloc_ (num_copy_elements, sizeof(MHD_iovec_));
+ if (NULL != iov_copy)
+ {
+ i_cp = 0;
+ for (i = 0; iovcnt > i; ++i)
+ {
+ size_t element_size;
+ uint8_t *buf;
+
+ if (0 == iov[i].iov_len)
+ continue; /* skip zero-sized elements */
+
+ buf = (uint8_t*) iov[i].iov_base;
+ element_size = iov[i].iov_len;
+#if defined(MHD_WINSOCK_SOCKETS) && defined(_WIN64)
+ while (ULONG_MAX < element_size)
+ {
+ iov_copy[i_cp].iov_base = (void*) buf;
+ iov_copy[i_cp].iov_len = ULONG_MAX;
+ buf += ULONG_MAX;
+ element_size -= ULONG_MAX;
+ i_cp++;
+ }
+#endif /* MHD_WINSOCK_SOCKETS && _WIN64 */
+ iov_copy[i_cp].iov_base = (void*) buf;
+ iov_copy[i_cp].iov_len = element_size;
+ i_cp++;
+ }
+
+ mhd_assert (num_copy_elements == i_cp);
+ response->data_iov = iov_copy;
+ response->data_iovcnt = i_cp;
+
+ return response;
+ }
+
+ }
+ else if (1 == i_cp)
+ {
+ mhd_assert (NULL != last_valid_buffer);
+ response->data = last_valid_buffer;
+ response->data_size = total_size;
+
+ return response;
+ }
+ else /* if (0 == i_nz) */
+ {
+ mhd_assert (0 == total_size);
+
+ return response;
+ }
+ }
+ /* Some error condition */
+ MHD_mutex_destroy_chk_ (&response->mutex);
+ }
+ free (response);
+ }
+ return NULL;
+}
+
+
#ifdef UPGRADE_SUPPORT
/**
* This connection-specific callback is provided by MHD to
@@ -1287,6 +1434,12 @@ MHD_destroy_response (struct MHD_Response *response)
#endif
if (NULL != response->crfc)
response->crfc (response->crc_cls);
+
+ if (NULL != response->data_iov)
+ {
+ free (response->data_iov);
+ }
+
while (NULL != response->first_header)
{
pos = response->first_header;