diff options
Diffstat (limited to 'src/microhttpd')
-rw-r--r-- | src/microhttpd/connection.c | 39 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 69 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.c | 243 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.h | 22 | ||||
-rw-r--r-- | src/microhttpd/response.c | 153 |
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 | */ | ||
351 | typedef 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 | */ | ||
362 | typedef 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 | */ | ||
369 | typedef struct MHD_IoVec MHD_iovec_; | ||
370 | #define MHD_IOV_ELMN_MAX_SIZE SIZE_MAX | ||
371 | #endif | ||
372 | |||
373 | |||
374 | struct 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 | */ | ||
1272 | static ssize_t | ||
1273 | send_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 | */ | ||
1396 | static ssize_t | ||
1397 | send_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 | |||
1452 | ssize_t | ||
1453 | MHD_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 | */ | ||
144 | ssize_t | ||
145 | MHD_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 * | ||
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; |