aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-06-06 18:23:03 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-07-28 11:28:44 +0300
commitbbf0a2969c28a404439af922b7a01420ebc98300 (patch)
tree770caad7518fb888f052f9833a8584d9203719a2
parent28223f6a59f15afbb35c3d8d813f296598a62c3b (diff)
downloadlibmicrohttpd-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.c188
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 */
1314static void
1315connection_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 */
1345static size_t
1346connection_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 */
1387static void
1388connection_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 */
1417static void
1418connection_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 */
1808static enum MHD_Result
1809build_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,