diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-06-06 18:23:03 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-07-28 11:28:44 +0300 |
commit | bbf0a2969c28a404439af922b7a01420ebc98300 (patch) | |
tree | 770caad7518fb888f052f9833a8584d9203719a2 | |
parent | 28223f6a59f15afbb35c3d8d813f296598a62c3b (diff) | |
download | libmicrohttpd-bbf0a2969c28a404439af922b7a01420ebc98300.tar.gz libmicrohttpd-bbf0a2969c28a404439af922b7a01420ebc98300.zip |
Re-written chunk footer generation function as a separate function
Separated reply footer generation from reply header generation.
-rw-r--r-- | src/microhttpd/connection.c | 188 |
1 files changed, 187 insertions, 1 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 2d3d5671..4ef6c5c3 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -1308,6 +1308,121 @@ try_grow_read_buffer (struct MHD_Connection *connection, | |||
1308 | 1308 | ||
1309 | 1309 | ||
1310 | /** | 1310 | /** |
1311 | * Shrink connection read buffer to the zero of data in the buffer | ||
1312 | * @param connection the connection whose read buffer is being manipulated | ||
1313 | */ | ||
1314 | static void | ||
1315 | connection_shrink_read_buffer (struct MHD_Connection *connection) | ||
1316 | { | ||
1317 | struct MHD_Connection *const c = connection; /**< a short alias */ | ||
1318 | void *new_buf; | ||
1319 | |||
1320 | if (NULL == c->read_buffer) | ||
1321 | { | ||
1322 | mhd_assert (0 == c->read_buffer_size); | ||
1323 | mhd_assert (0 == c->read_buffer_offset); | ||
1324 | c->read_buffer = NULL; | ||
1325 | return; | ||
1326 | } | ||
1327 | |||
1328 | mhd_assert (c->read_buffer_offset <= c->read_buffer_size); | ||
1329 | new_buf = MHD_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size, | ||
1330 | c->read_buffer_offset); | ||
1331 | mhd_assert (c->read_buffer == new_buf); | ||
1332 | c->read_buffer_size = c->read_buffer_offset; | ||
1333 | if (0 == c->read_buffer_size) | ||
1334 | c->read_buffer = NULL; | ||
1335 | } | ||
1336 | |||
1337 | |||
1338 | /** | ||
1339 | * Allocate the maximum available amount of memory from MemoryPool | ||
1340 | * for write buffer. | ||
1341 | * @param connection the connection whose write buffer is being manipulated | ||
1342 | * @return the size of free space in write buffer, may be smaller | ||
1343 | * than requested size. | ||
1344 | */ | ||
1345 | static size_t | ||
1346 | connection_maximize_write_buffer (struct MHD_Connection *connection) | ||
1347 | { | ||
1348 | struct MHD_Connection *const c = connection; /**< a short alias */ | ||
1349 | struct MemoryPool *const pool = connection->pool; | ||
1350 | void *new_buf; | ||
1351 | size_t new_size; | ||
1352 | |||
1353 | mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size)); | ||
1354 | mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset); | ||
1355 | mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); | ||
1356 | |||
1357 | new_size = c->write_buffer_size + MHD_pool_get_free (pool); | ||
1358 | new_buf = MHD_pool_reallocate (pool, | ||
1359 | c->write_buffer, | ||
1360 | c->write_buffer_size, | ||
1361 | new_size); | ||
1362 | /* Buffer position must not be moved. | ||
1363 | * Position could be moved only if buffer was allocated 'from_end', | ||
1364 | * which cannot happen. */ | ||
1365 | mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer)); | ||
1366 | c->write_buffer = new_buf; | ||
1367 | c->write_buffer_size = new_size; | ||
1368 | if (c->write_buffer_send_offset == c->write_buffer_append_offset) | ||
1369 | { | ||
1370 | /* All data have been sent, reset offsets to zero. */ | ||
1371 | c->write_buffer_send_offset = 0; | ||
1372 | c->write_buffer_append_offset = 0; | ||
1373 | } | ||
1374 | |||
1375 | return c->write_buffer_size - c->write_buffer_append_offset; | ||
1376 | } | ||
1377 | |||
1378 | |||
1379 | /** | ||
1380 | * Shrink connection write buffer to the size of unsent data. | ||
1381 | * | ||
1382 | * @note: The number of calls of this function should be limited to avoid extra | ||
1383 | * zeroing of the memory. | ||
1384 | * @param connection the connection whose write buffer is being manipulated | ||
1385 | * @param connection the connection to manipulate write buffer | ||
1386 | */ | ||
1387 | static void | ||
1388 | connection_shrink_write_buffer (struct MHD_Connection *connection) | ||
1389 | { | ||
1390 | struct MHD_Connection *const c = connection; /**< a short alias */ | ||
1391 | struct MemoryPool *const pool = connection->pool; | ||
1392 | void *new_buf; | ||
1393 | |||
1394 | mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size)); | ||
1395 | mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset); | ||
1396 | mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); | ||
1397 | |||
1398 | if (NULL == c->write_buffer) | ||
1399 | return; | ||
1400 | if (c->write_buffer_append_offset == c->write_buffer_size) | ||
1401 | return; | ||
1402 | |||
1403 | new_buf = MHD_pool_reallocate (pool, c->write_buffer, c->write_buffer_size, | ||
1404 | c->write_buffer_append_offset); | ||
1405 | mhd_assert (c->write_buffer == new_buf); | ||
1406 | c->write_buffer_size = c->write_buffer_append_offset; | ||
1407 | } | ||
1408 | |||
1409 | |||
1410 | /** | ||
1411 | * Switch connection from recv mode to send mode. | ||
1412 | * | ||
1413 | * Current request header or body will not be read anymore, | ||
1414 | * response must be assigned to connection. | ||
1415 | * @param connection the connection to prepare for sending. | ||
1416 | */ | ||
1417 | static void | ||
1418 | connection_switch_from_recv_to_send (struct MHD_Connection *connection) | ||
1419 | { | ||
1420 | /* Read buffer is not needed for this request, shrink it.*/ | ||
1421 | connection_shrink_read_buffer (connection); | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | /** | ||
1311 | * Allocate the connection's write buffer and fill it with all of the | 1426 | * Allocate the connection's write buffer and fill it with all of the |
1312 | * headers (or footers, if we have already sent the body) from the | 1427 | * headers (or footers, if we have already sent the body) from the |
1313 | * HTTPd's response. If headers are missing in the response supplied | 1428 | * HTTPd's response. If headers are missing in the response supplied |
@@ -1682,6 +1797,72 @@ build_header_response (struct MHD_Connection *connection) | |||
1682 | 1797 | ||
1683 | 1798 | ||
1684 | /** | 1799 | /** |
1800 | * Allocate the connection's write buffer (if necessary) and fill it | ||
1801 | * with response footers. | ||
1802 | * Works only for chunked responses as other responses do not need | ||
1803 | * and do not support any kind of footers. | ||
1804 | * | ||
1805 | * @param connection the connection | ||
1806 | * @return #MHD_YES on success, #MHD_NO on failure (out of memory) | ||
1807 | */ | ||
1808 | static enum MHD_Result | ||
1809 | build_connection_chunked_response_footer (struct MHD_Connection *connection) | ||
1810 | { | ||
1811 | char *buf; /**< the buffer to write footers to */ | ||
1812 | size_t buf_size; /**< the size of the @a buf */ | ||
1813 | size_t used_size; /**< the used size of the @a buf */ | ||
1814 | struct MHD_Connection *const c = connection; /**< a short alias */ | ||
1815 | struct MHD_HTTP_Header *pos; | ||
1816 | |||
1817 | /* TODO: replace with 'use_chunked_send' */ | ||
1818 | mhd_assert (connection->have_chunked_upload); | ||
1819 | /* TODO: allow combining of the final footer with the last chunk, | ||
1820 | * modify the next assert. */ | ||
1821 | mhd_assert (MHD_CONNECTION_BODY_SENT == connection->state); | ||
1822 | mhd_assert (NULL != c->response); | ||
1823 | |||
1824 | buf_size = connection_maximize_write_buffer (c); | ||
1825 | /* '2' is the minimal size of chunked footer ("\r\n") */ | ||
1826 | if (buf_size < 2) | ||
1827 | return MHD_NO; | ||
1828 | buf = c->write_buffer + c->write_buffer_append_offset; | ||
1829 | used_size = 0; | ||
1830 | |||
1831 | for (pos = c->response->first_header; NULL != pos; pos = pos->next) | ||
1832 | { | ||
1833 | if (MHD_FOOTER_KIND == pos->kind) | ||
1834 | { | ||
1835 | size_t new_used_size; /* resulting size with this header */ | ||
1836 | /* '4' is colon, space, linefeeds */ | ||
1837 | new_used_size = used_size + pos->header_size + pos->value_size + 4; | ||
1838 | if (new_used_size > buf_size) | ||
1839 | return MHD_NO; | ||
1840 | memcpy (buf + used_size, pos->header, pos->header_size); | ||
1841 | used_size += pos->header_size; | ||
1842 | buf[used_size++] = ':'; | ||
1843 | buf[used_size++] = ' '; | ||
1844 | memcpy (buf + used_size, pos->value, pos->value_size); | ||
1845 | used_size += pos->value_size; | ||
1846 | buf[used_size++] = '\r'; | ||
1847 | buf[used_size++] = '\n'; | ||
1848 | mhd_assert (used_size == new_used_size); | ||
1849 | } | ||
1850 | } | ||
1851 | if (used_size + 2 > buf_size) | ||
1852 | return MHD_NO; | ||
1853 | memcpy (buf + used_size, "\r\n", 2); | ||
1854 | used_size += 2; | ||
1855 | |||
1856 | c->write_buffer_append_offset += used_size; | ||
1857 | mhd_assert (c->write_buffer_append_offset <= c->write_buffer_size); | ||
1858 | |||
1859 | /* TODO: remove shrink */ | ||
1860 | connection_shrink_write_buffer (c); | ||
1861 | return MHD_YES; | ||
1862 | } | ||
1863 | |||
1864 | |||
1865 | /** | ||
1685 | * We encountered an error processing the request. | 1866 | * We encountered an error processing the request. |
1686 | * Handle it properly by stopping to read data | 1867 | * Handle it properly by stopping to read data |
1687 | * and sending the indicated response code and message. | 1868 | * and sending the indicated response code and message. |
@@ -3805,6 +3986,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
3805 | continue; | 3986 | continue; |
3806 | if (NULL == connection->response) | 3987 | if (NULL == connection->response) |
3807 | break; /* try again next time */ | 3988 | break; /* try again next time */ |
3989 | |||
3990 | connection_switch_from_recv_to_send (connection); | ||
3808 | if (MHD_NO == build_header_response (connection)) | 3991 | if (MHD_NO == build_header_response (connection)) |
3809 | { | 3992 | { |
3810 | /* oops - close! */ | 3993 | /* oops - close! */ |
@@ -3918,7 +4101,10 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
3918 | /* mutex was already unlocked by try_ready_chunked_body */ | 4101 | /* mutex was already unlocked by try_ready_chunked_body */ |
3919 | break; | 4102 | break; |
3920 | case MHD_CONNECTION_BODY_SENT: | 4103 | case MHD_CONNECTION_BODY_SENT: |
3921 | if (MHD_NO == build_header_response (connection)) | 4104 | /* TODO: replace with 'use_chunked_send' */ |
4105 | mhd_assert (connection->have_chunked_upload); | ||
4106 | |||
4107 | if (MHD_NO == build_connection_chunked_response_footer (connection)) | ||
3922 | { | 4108 | { |
3923 | /* oops - close! */ | 4109 | /* oops - close! */ |
3924 | CONNECTION_CLOSE_ERROR (connection, | 4110 | CONNECTION_CLOSE_ERROR (connection, |