aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd')
-rw-r--r--src/microhttpd/connection.c39
-rw-r--r--src/microhttpd/internal.h69
-rw-r--r--src/microhttpd/mhd_send.c243
-rw-r--r--src/microhttpd/mhd_send.h22
-rw-r--r--src/microhttpd/response.c153
5 files changed, 521 insertions, 5 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 25788414..7f2dcd75 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -794,11 +794,33 @@ try_ready_normal_body (struct MHD_Connection *connection)
794 struct MHD_Response *response; 794 struct MHD_Response *response;
795 795
796 response = connection->response; 796 response = connection->response;
797 if (NULL == response->crc)
798 return MHD_YES;
799 if ( (0 == response->total_size) || 797 if ( (0 == response->total_size) ||
800 (connection->response_write_position == response->total_size) ) 798 (connection->response_write_position == response->total_size) )
801 return MHD_YES; /* 0-byte response is always ready */ 799 return MHD_YES; /* 0-byte response is always ready */
800 if (NULL != response->data_iov)
801 {
802 size_t copy_size;
803 if (NULL != connection->resp_iov.iov)
804 return MHD_YES;
805
806 copy_size = response->data_iovcnt * sizeof(MHD_iovec_);
807 connection->resp_iov.iov = MHD_pool_allocate (connection->pool, copy_size,
808 true);
809 if (NULL == connection->resp_iov.iov)
810 {
811 MHD_mutex_unlock_chk_ (&response->mutex);
812 /* not enough memory */
813 CONNECTION_CLOSE_ERROR (connection,
814 _ ("Closing connection (out of memory).\n"));
815 return MHD_NO;
816 }
817 memcpy (connection->resp_iov.iov, response->data_iov, copy_size);
818 connection->resp_iov.cnt = response->data_iovcnt;
819 connection->resp_iov.sent = 0;
820 return MHD_YES;
821 }
822 if (NULL == response->crc)
823 return MHD_YES;
802 if ( (response->data_start <= 824 if ( (response->data_start <=
803 connection->response_write_position) && 825 connection->response_write_position) &&
804 (response->data_size + response->data_start > 826 (response->data_size + response->data_start >
@@ -2935,6 +2957,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
2935 connection->response_write_position) ); 2957 connection->response_write_position) );
2936 2958
2937 if ( (NULL == resp->crc) && 2959 if ( (NULL == resp->crc) &&
2960 (NULL == resp->data_iov) &&
2938 (0 == connection->response_write_position) ) 2961 (0 == connection->response_write_position) )
2939 { 2962 {
2940 mhd_assert (resp->total_size >= resp->data_size); 2963 mhd_assert (resp->total_size >= resp->data_size);
@@ -3017,12 +3040,16 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3017#if defined(_MHD_HAVE_SENDFILE) 3040#if defined(_MHD_HAVE_SENDFILE)
3018 if (MHD_resp_sender_sendfile == connection->resp_sender) 3041 if (MHD_resp_sender_sendfile == connection->resp_sender)
3019 { 3042 {
3043 mhd_assert (NULL == response->data_iov);
3020 ret = MHD_send_sendfile_ (connection); 3044 ret = MHD_send_sendfile_ (connection);
3021 } 3045 }
3046 else /* combined with the next 'if' */
3047#endif /* _MHD_HAVE_SENDFILE */
3048 if (NULL != response->data_iov)
3049 {
3050 ret = MHD_send_iovec_ (connection, &connection->resp_iov, true);
3051 }
3022 else 3052 else
3023#else /* ! _MHD_HAVE_SENDFILE */
3024 if (1)
3025#endif /* ! _MHD_HAVE_SENDFILE */
3026 { 3053 {
3027 data_write_offset = connection->response_write_position 3054 data_write_offset = connection->response_write_position
3028 - response->data_start; 3055 - response->data_start;
@@ -3674,6 +3701,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
3674 connection->write_buffer_size = 0; 3701 connection->write_buffer_size = 0;
3675 connection->write_buffer_send_offset = 0; 3702 connection->write_buffer_send_offset = 0;
3676 connection->write_buffer_append_offset = 0; 3703 connection->write_buffer_append_offset = 0;
3704 /* iov (if any) was deallocated by MHD_pool_reset */
3705 memset (&connection->resp_iov, 0, sizeof(connection->resp_iov));
3677 continue; 3706 continue;
3678 case MHD_CONNECTION_CLOSED: 3707 case MHD_CONNECTION_CLOSED:
3679 cleanup_connection (connection); 3708 cleanup_connection (connection);
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index f3c4cb1e..ba71d1eb 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -343,6 +343,57 @@ struct MHD_HTTP_Header
343}; 343};
344 344
345 345
346#if defined(MHD_WINSOCK_SOCKETS)
347/**
348 * Internally used I/O vector type for use with winsock.
349 * Binary matches system "WSABUF".
350 */
351typedef struct _MHD_W32_iovec
352{
353 unsigned long iov_len;
354 char *iov_base;
355} MHD_iovec_;
356#define MHD_IOV_ELMN_MAX_SIZE ULONG_MAX
357#elif defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
358/**
359 * Internally used I/O vector type for use when writev or sendmsg
360 * is available. Matches system "struct iovec".
361 */
362typedef struct iovec MHD_iovec_;
363#define MHD_IOV_ELMN_MAX_SIZE SIZE_MAX
364#else
365/**
366 * Internally used I/O vector type for use when writev or sendmsg
367 * is not available.
368 */
369typedef struct MHD_IoVec MHD_iovec_;
370#define MHD_IOV_ELMN_MAX_SIZE SIZE_MAX
371#endif
372
373
374struct MHD_iovec_track_
375{
376 /**
377 * The copy of array of iovec elements.
378 * The copy of elements are updated during sending.
379 * The number of elements is not changed during lifetime.
380 */
381 MHD_iovec_ *iov;
382
383 /**
384 * The number of elements in @iov.
385 * This value is not changed during lifetime.
386 */
387 size_t cnt;
388
389 /**
390 * The number of sent elements.
391 * At the same time, it is the index of the next (or current) element
392 * to send.
393 */
394 size_t sent;
395};
396
346/** 397/**
347 * Representation of a response. 398 * Representation of a response.
348 */ 399 */
@@ -450,6 +501,15 @@ struct MHD_Response
450 */ 501 */
451 bool is_pipe; 502 bool is_pipe;
452 503
504 /**
505 * I/O vector used with MHD_create_response_from_iovec.
506 */
507 MHD_iovec_ *data_iov;
508
509 /**
510 * Number of elements in data_iov.
511 */
512 size_t data_iovcnt;
453}; 513};
454 514
455 515
@@ -873,6 +933,15 @@ struct MHD_Connection
873 */ 933 */
874 uint64_t response_write_position; 934 uint64_t response_write_position;
875 935
936 /**
937 * The copy of iov response.
938 * Valid if iovec response is used.
939 * Updated during send.
940 * Members are allocated in the pool.
941 */
942 struct MHD_iovec_track_ resp_iov;
943
944
876#if defined(_MHD_HAVE_SENDFILE) 945#if defined(_MHD_HAVE_SENDFILE)
877 enum MHD_resp_sender_ 946 enum MHD_resp_sender_
878 { 947 {
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index 0d979c0a..fd67300c 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -51,6 +51,15 @@
51 51
52#include "mhd_limits.h" 52#include "mhd_limits.h"
53 53
54#ifdef MHD_VECT_SEND
55#if (! defined (HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
56 defined (MHD_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
57 defined (MHD_SEND_SPIPE_SUPPRESS_NEEDED)
58#define _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1
59#endif /* (!HAVE_SENDMSG || !MSG_NOSIGNAL) &&
60 MHD_SEND_SPIPE_SUPPRESS_POSSIBLE && MHD_SEND_SPIPE_SUPPRESS_NEEDED */
61#endif /* MHD_VECT_SEND */
62
54/** 63/**
55 * sendfile() chuck size 64 * sendfile() chuck size
56 */ 65 */
@@ -1243,3 +1252,237 @@ MHD_send_sendfile_ (struct MHD_Connection *connection)
1243 1252
1244 1253
1245#endif /* _MHD_HAVE_SENDFILE */ 1254#endif /* _MHD_HAVE_SENDFILE */
1255
1256#if defined(MHD_VECT_SEND)
1257
1258
1259/**
1260 * Function sends iov data by system sendmsg or writev function.
1261 *
1262 * Connection must be in non-TLS (non-HTTPS) mode.
1263 *
1264 * @param connection the MHD connection structure
1265 * @param r_iov the pointer to iov data structure with tracking
1266 * @param push_data set to true to force push the data to the network from
1267 * system buffers (usually set for the last piece of data),
1268 * set to false to prefer holding incomplete network packets
1269 * (more data will be send for the same reply).
1270 * @return actual number of bytes sent
1271 */
1272static ssize_t
1273send_iov_nontls (struct MHD_Connection *connection,
1274 struct MHD_iovec_track_ *const r_iov,
1275 bool push_data)
1276{
1277 ssize_t res;
1278 ssize_t total_sent;
1279 size_t items_to_send;
1280#ifdef HAVE_SENDMSG
1281 struct msghdr msg;
1282#elif defined(MHD_WINSOCK_SOCKETS)
1283 DWORD bytes_sent;
1284 DWORD cnt_w;
1285#endif /* MHD_WINSOCK_SOCKETS */
1286
1287 mhd_assert (0 == (connection->daemon->options & MHD_USE_TLS));
1288
1289 if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
1290 (MHD_CONNECTION_CLOSED == connection->state) )
1291 {
1292 return MHD_ERR_NOTCONN_;
1293 }
1294
1295 pre_send_setopt (connection, false, push_data);
1296
1297 items_to_send = r_iov->cnt - r_iov->sent;
1298#ifdef HAVE_SENDMSG
1299 memset (&msg, 0, sizeof(struct msghdr));
1300 msg.msg_iov = r_iov->iov + r_iov->sent;
1301 msg.msg_iovlen = items_to_send;
1302
1303 res = sendmsg (connection->socket_fd, &msg, MSG_NOSIGNAL_OR_ZERO);
1304#elif defined(HAVE_WRITEV)
1305 res = writev (connection->socket_fd, r_iov->iov + r_iov->sent,
1306 items_to_send);
1307#elif defined(MHD_WINSOCK_SOCKETS)
1308#ifdef _WIN64
1309 cnt_w = (items_to_send > UINT32_MAX) ? UINT32_MAX : (DWORD) items_to_send;
1310#else /* ! _WIN64 */
1311 cnt_w = (DWORD) items_to_send;
1312#endif /* ! _WIN64 */
1313 if (0 == WSASend (connection->socket_fd,
1314 (LPWSABUF) (r_iov->iov + r_iov->sent),
1315 cnt_w,
1316 &bytes_sent, 0, NULL, NULL))
1317 res = (ssize_t) bytes_sent;
1318 else
1319 res = -1;
1320#else /* !HAVE_SENDMSG && !HAVE_WRITEV && !MHD_WINSOCK_SOCKETS */
1321#error No vector-send function available
1322#endif
1323
1324 if (0 > res)
1325 {
1326 const int err = MHD_socket_get_error_ ();
1327
1328 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
1329 {
1330#ifdef EPOLL_SUPPORT
1331 /* EAGAIN --- no longer write-ready */
1332 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
1333#endif /* EPOLL_SUPPORT */
1334 return MHD_ERR_AGAIN_;
1335 }
1336 if (MHD_SCKT_ERR_IS_EINTR_ (err))
1337 return MHD_ERR_AGAIN_;
1338 if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_))
1339 return MHD_ERR_CONNRESET_;
1340 /* Treat any other error as hard error. */
1341 return MHD_ERR_NOTCONN_;
1342 }
1343
1344 /* Some data has been sent */
1345 total_sent = res;
1346 /* Adjust the internal tracking information for the iovec to
1347 * take this last send into account. */
1348 while ((0 != res) && (r_iov->iov[r_iov->sent].iov_len <= (size_t) res))
1349 {
1350 res -= r_iov->iov[r_iov->sent].iov_len;
1351 r_iov->sent++; /* The iov element has been completely sent */
1352 mhd_assert ((r_iov->cnt > r_iov->sent) || (0 == res));
1353 }
1354
1355 if (r_iov->cnt == r_iov->sent)
1356 post_send_setopt (connection, false, push_data);
1357 else
1358 {
1359#ifdef EPOLL_SUPPORT
1360 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
1361#endif /* EPOLL_SUPPORT */
1362 if (0 != res)
1363 {
1364 mhd_assert (r_iov->cnt > r_iov->sent);
1365 /* The last iov element has been partially sent */
1366 r_iov->iov[r_iov->sent].iov_base =
1367 (void*) ((uint8_t*) r_iov->iov[r_iov->sent].iov_base + (size_t) res);
1368 r_iov->iov[r_iov->sent].iov_len -= res;
1369 }
1370 }
1371
1372 return total_sent;
1373}
1374
1375
1376#endif /* MHD_VECT_SEND */
1377
1378#if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1379 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1380
1381
1382/**
1383 * Function sends iov data by sending buffers one-by-one by standard
1384 * data send function.
1385 *
1386 * Connection could be in HTTPS or non-HTTPS mode.
1387 *
1388 * @param connection the MHD connection structure
1389 * @param r_iov the pointer to iov data structure with tracking
1390 * @param push_data set to true to force push the data to the network from
1391 * system buffers (usually set for the last piece of data),
1392 * set to false to prefer holding incomplete network packets
1393 * (more data will be send for the same reply).
1394 * @return actual number of bytes sent
1395 */
1396static ssize_t
1397send_iov_emu (struct MHD_Connection *connection,
1398 struct MHD_iovec_track_ *const r_iov,
1399 bool push_data)
1400{
1401 const bool non_blk = connection->sk_nonblck;
1402 size_t total_sent;
1403 ssize_t res;
1404
1405 mhd_assert (NULL != r_iov->iov);
1406 total_sent = 0;
1407 do
1408 {
1409 if ((size_t) SSIZE_MAX - total_sent < r_iov->iov[r_iov->sent].iov_len)
1410 return total_sent; /* return value would overflow */
1411
1412 res = MHD_send_data_ (connection,
1413 r_iov->iov[r_iov->sent].iov_base,
1414 r_iov->iov[r_iov->sent].iov_len,
1415 push_data && (r_iov->cnt == r_iov->sent + 1));
1416 if (0 > res)
1417 {
1418 /* Result is an error */
1419 if (0 == total_sent)
1420 return res; /* Nothing was sent, return result as is */
1421
1422 if (MHD_ERR_AGAIN_ == res)
1423 return total_sent; /* Some data has been sent, return the amount */
1424
1425 return res; /* Any kind of a hard error */
1426 }
1427
1428 total_sent += (size_t) res;
1429
1430 if (r_iov->iov[r_iov->sent].iov_len != (size_t) res)
1431 {
1432 /* Incomplete buffer has been sent.
1433 * Adjust buffer of the last element. */
1434 r_iov->iov[r_iov->sent].iov_base =
1435 (void*) ((uint8_t*) r_iov->iov[r_iov->sent].iov_base + (size_t) res);
1436 r_iov->iov[r_iov->sent].iov_len -= res;
1437
1438 return total_sent;
1439 }
1440 /* The iov element has been completely sent */
1441 r_iov->sent++;
1442 } while ((r_iov->cnt > r_iov->sent) && (non_blk));
1443
1444 return (ssize_t) total_sent;
1445}
1446
1447
1448#endif /* !MHD_VECT_SEND || HTTPS_SUPPORT
1449 || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1450
1451
1452ssize_t
1453MHD_send_iovec_ (struct MHD_Connection *connection,
1454 struct MHD_iovec_track_ *const r_iov,
1455 bool push_data)
1456{
1457#ifdef MHD_VECT_SEND
1458#if defined(HTTPS_SUPPORT) || \
1459 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1460 bool use_iov_send = true;
1461#endif /* HTTPS_SUPPORT || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1462#endif /* MHD_VECT_SEND */
1463
1464 mhd_assert (NULL != connection->resp_iov.iov);
1465 mhd_assert (NULL != connection->response->data_iov);
1466 mhd_assert (connection->resp_iov.cnt > connection->resp_iov.sent);
1467#ifdef MHD_VECT_SEND
1468#if defined(HTTPS_SUPPORT) || \
1469 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1470#ifdef HTTPS_SUPPORT
1471 use_iov_send = use_iov_send &&
1472 (0 == (connection->daemon->options & MHD_USE_TLS));
1473#endif /* HTTPS_SUPPORT */
1474#ifdef _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
1475 use_iov_send = use_iov_send && (connection->daemon->sigpipe_blocked ||
1476 connection->sk_spipe_suppress);
1477#endif /* _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1478 if (use_iov_send)
1479#endif /* HTTPS_SUPPORT || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1480 return send_iov_nontls (connection, r_iov, push_data);
1481#endif /* MHD_VECT_SEND */
1482
1483#if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1484 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1485 return send_iov_emu (connection, r_iov, push_data);
1486#endif /* !MHD_VECT_SEND || HTTPS_SUPPORT
1487 || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1488}
diff --git a/src/microhttpd/mhd_send.h b/src/microhttpd/mhd_send.h
index 54b5c1fe..d4ee8de7 100644
--- a/src/microhttpd/mhd_send.h
+++ b/src/microhttpd/mhd_send.h
@@ -41,6 +41,11 @@
41#include "connection_https.h" 41#include "connection_https.h"
42#endif 42#endif
43 43
44#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) || \
45 defined(MHD_WINSOCK_SOCKETS)
46#define MHD_VECT_SEND 1
47#endif /* HAVE_SENDMSG || HAVE_WRITEV || MHD_WINSOCK_SOCKETS */
48
44#ifdef HAVE_FREEBSD_SENDFILE 49#ifdef HAVE_FREEBSD_SENDFILE
45/** 50/**
46 * Initialises static variables 51 * Initialises static variables
@@ -125,4 +130,21 @@ MHD_connection_set_nodelay_state_ (struct MHD_Connection *connection,
125 bool nodelay_state); 130 bool nodelay_state);
126 131
127 132
133/**
134 * Function for sending responses backed by a an array of memory buffers.
135 *
136 * @param connection the MHD connection structure
137 * @param r_iov the pointer to iov response structure with tracking
138 * @param push_data set to true to force push the data to the network from
139 * system buffers (usually set for the last piece of data),
140 * set to false to prefer holding incomplete network packets
141 * (more data will be send for the same reply).
142 * @return actual number of bytes sent
143 */
144ssize_t
145MHD_send_iovec_ (struct MHD_Connection *connection,
146 struct MHD_iovec_track_ *r_iov,
147 bool push_data);
148
149
128#endif /* MHD_SEND_H */ 150#endif /* MHD_SEND_H */
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 *
863MHD_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;