aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2020-12-13 17:24:36 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2020-12-13 17:24:36 +0300
commit75e49713c671acc9d0df6167b23bbb0c1273b8df (patch)
tree96d350877a41a46f9c32b45c9c521163bbc1b6b4
parentcd8294e59dc3d32062c8a3ddd6e5a203f746958d (diff)
downloadlibmicrohttpd-75e49713c671acc9d0df6167b23bbb0c1273b8df.tar.gz
libmicrohttpd-75e49713c671acc9d0df6167b23bbb0c1273b8df.zip
mhd_send.c: Fixed: body and header pushing logic
-rw-r--r--src/microhttpd/connection.c13
-rw-r--r--src/microhttpd/mhd_send.c81
-rw-r--r--src/microhttpd/mhd_send.h15
3 files changed, 91 insertions, 18 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 0ffaffff..51384788 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -2931,26 +2931,33 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
2931 if ( (NULL == resp->crc) && 2931 if ( (NULL == resp->crc) &&
2932 (0 == connection->response_write_position) ) 2932 (0 == connection->response_write_position) )
2933 { 2933 {
2934 mhd_assert (resp->total_size >= resp->data_size);
2934 /* Send response headers alongside the response body, if the body 2935 /* Send response headers alongside the response body, if the body
2935 * data is available. */ 2936 * data is available. */
2936 ret = MHD_send_hdr_and_body_ (connection, 2937 ret = MHD_send_hdr_and_body_ (connection,
2937 &connection->write_buffer 2938 &connection->write_buffer
2938 [connection->write_buffer_send_offset], 2939 [connection->write_buffer_send_offset],
2939 wb_ready, 2940 wb_ready,
2941 false,
2940 resp->data, 2942 resp->data,
2941 resp->data_size); 2943 resp->data_size,
2944 (resp->total_size == resp->data_size));
2942 } 2945 }
2943 else 2946 else
2944 { 2947 {
2945 /* This is response for HEAD request, reply body is not allowed 2948 /* This is response for HEAD request or reply body is not allowed
2946 * for any other reason or reply body is dynamically generated. */ 2949 * for any other reason or reply body is dynamically generated. */
2947 /* Do not send the body data even if it's available. */ 2950 /* Do not send the body data even if it's available. */
2948 ret = MHD_send_hdr_and_body_ (connection, 2951 ret = MHD_send_hdr_and_body_ (connection,
2949 &connection->write_buffer 2952 &connection->write_buffer
2950 [connection->write_buffer_send_offset], 2953 [connection->write_buffer_send_offset],
2951 wb_ready, 2954 wb_ready,
2955 false,
2952 NULL, 2956 NULL,
2953 0); 2957 0,
2958 ((0 == resp->total_size) ||
2959 (resp->total_size ==
2960 connection->response_write_position)));
2954 } 2961 }
2955 2962
2956 if (ret < 0) 2963 if (ret < 0)
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index e54a251c..8abd30d6 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -811,10 +811,14 @@ ssize_t
811MHD_send_hdr_and_body_ (struct MHD_Connection *connection, 811MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
812 const char *header, 812 const char *header,
813 size_t header_size, 813 size_t header_size,
814 bool never_push_hdr,
814 const char *body, 815 const char *body,
815 size_t body_size) 816 size_t body_size,
817 bool complete_response)
816{ 818{
817 ssize_t ret; 819 ssize_t ret;
820 bool push_hdr;
821 bool push_body;
818#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 822#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
819 MHD_socket s = connection->socket_fd; 823 MHD_socket s = connection->socket_fd;
820 struct iovec vector[2]; 824 struct iovec vector[2];
@@ -826,6 +830,32 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
826#endif /* HAVE_SENDMSG || HAVE_WRITEV */ 830#endif /* HAVE_SENDMSG || HAVE_WRITEV */
827 mhd_assert ( (NULL != body) || (0 == body_size) ); 831 mhd_assert ( (NULL != body) || (0 == body_size) );
828 832
833 push_body = complete_response;
834
835 if (! never_push_hdr)
836 {
837 if (! complete_response)
838 push_hdr = true; /* Push the header as the client may react
839 * on header alone while the body data is
840 * being prepared. */
841 else
842 {
843 if (1400 > (header_size + body_size))
844 push_hdr = false; /* Do not push the header as complete
845 * reply is already ready and the whole
846 * reply most probably will fit into
847 * the single IP packet. */
848 else
849 push_hdr = true; /* Push header alone so client may react
850 * on it while reply body is being delivered. */
851 }
852 }
853 else
854 push_hdr = false;
855
856 if (complete_response && (0 == body_size))
857 push_hdr = true; /* The header alone is equal to the whole response. */
858
829 if ( 859 if (
830#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 860#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
831 (no_vec) || 861 (no_vec) ||
@@ -839,7 +869,8 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
839 ret = MHD_send_on_connection_ (connection, 869 ret = MHD_send_on_connection_ (connection,
840 header, 870 header,
841 header_size, 871 header_size,
842 MHD_SSO_HDR_CORK); 872 push_hdr ?
873 MHD_SSO_PUSH_DATA: MHD_SSO_PREFER_BUFF);
843 if ( ((size_t) header_size == ret) && 874 if ( ((size_t) header_size == ret) &&
844 (((size_t) SSIZE_MAX > header_size)) && 875 (((size_t) SSIZE_MAX > header_size)) &&
845 (0 != body_size) ) 876 (0 != body_size) )
@@ -850,12 +881,17 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
850 * the next round. */ 881 * the next round. */
851 /* Make sure that sum of ret + ret2 will not exceed SSIZE_MAX. */ 882 /* Make sure that sum of ret + ret2 will not exceed SSIZE_MAX. */
852 if ( (((size_t) SSIZE_MAX) - ((size_t) ret)) < body_size) 883 if ( (((size_t) SSIZE_MAX) - ((size_t) ret)) < body_size)
884 {
853 body_size = (((size_t) SSIZE_MAX) - ((size_t) ret)); 885 body_size = (((size_t) SSIZE_MAX) - ((size_t) ret));
886 complete_response = false;
887 push_body = complete_response;
888 }
854 889
855 ret2 = MHD_send_on_connection_ (connection, 890 ret2 = MHD_send_on_connection_ (connection,
856 body, 891 body,
857 body_size, 892 body_size,
858 MHD_SSO_PUSH_DATA); 893 push_body ?
894 MHD_SSO_PUSH_DATA: MHD_SSO_PREFER_BUFF);
859 if (0 < ret2) 895 if (0 < ret2)
860 return ret + ret2; /* Total data sent */ 896 return ret + ret2; /* Total data sent */
861 if (MHD_ERR_AGAIN_ == ret2) 897 if (MHD_ERR_AGAIN_ == ret2)
@@ -869,17 +905,19 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
869 905
870 if ( ((size_t) SSIZE_MAX <= body_size) || 906 if ( ((size_t) SSIZE_MAX <= body_size) ||
871 ((size_t) SSIZE_MAX < (header_size + body_size)) ) 907 ((size_t) SSIZE_MAX < (header_size + body_size)) )
908 {
872 body_size = SSIZE_MAX - header_size; 909 body_size = SSIZE_MAX - header_size;
910 complete_response = false;
911 push_body = complete_response;
912 }
873 913
874 /* Since we generally give the fully answer, we do not want
875 corking to happen */
876 pre_send_setopt (connection, 914 pre_send_setopt (connection,
877#if HAVE_SENDMSG 915#if HAVE_SENDMSG
878 true, 916 true,
879#elif HAVE_WRITEV 917#elif HAVE_WRITEV
880 false, 918 false,
881#endif /* HAVE_WRITEV */ 919#endif /* HAVE_WRITEV */
882 true); 920 push_hdr || push_body);
883 921
884 vector[0].iov_base = (void *) header; 922 vector[0].iov_base = (void *) header;
885 vector[0].iov_len = header_size; 923 vector[0].iov_len = header_size;
@@ -913,12 +951,15 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
913 951
914 /* If there is a need to push the data from network buffers 952 /* If there is a need to push the data from network buffers
915 * call post_send_setopt(). */ 953 * call post_send_setopt(). */
916 /* If TLS connection is used then next final send() will be 954 if ( (push_body) &&
917 * without MSG_MORE support. If non-TLS connection is used 955 ((header_size + body_size) == (size_t) ret) )
918 * it's unknown whether sendfile() will be used or not so 956 {
919 * assume that next final send() will be the same, like for 957 /* Complete reply has been sent. */
920 * this response. */ 958 /* If TLS connection is used then next final send() will be
921 if ((header_size + body_size) == (size_t) ret) 959 * without MSG_MORE support. If non-TLS connection is used
960 * it's unknown whether next 'send' will be plain send() / sendmsg() or
961 * sendfile() will be used so assume that next final send() will be
962 * the same, like for this response. */
922 post_send_setopt (connection, 963 post_send_setopt (connection,
923#if HAVE_SENDMSG 964#if HAVE_SENDMSG
924 true, 965 true,
@@ -926,6 +967,22 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
926 false, 967 false,
927#endif /* HAVE_WRITEV */ 968#endif /* HAVE_WRITEV */
928 true); 969 true);
970 }
971 else if ( (push_hdr) &&
972 (header_size <= (size_t) ret))
973 {
974 /* The header has been sent completely and there is a
975 * need to push the header data. */
976 /* Luckily it is know what type of send function will be used
977 * next. */
978 post_send_setopt (connection,
979#if defined(_MHD_HAVE_SENDFILE)
980 MHD_resp_sender_std == connection->resp_sender,
981#else /* ! _MHD_HAVE_SENDFILE */
982 true,
983#endif /* ! _MHD_HAVE_SENDFILE */
984 true);
985 }
929 986
930 return ret; 987 return ret;
931#else /* ! (HAVE_SENDMSG || HAVE_WRITEV) */ 988#else /* ! (HAVE_SENDMSG || HAVE_WRITEV) */
diff --git a/src/microhttpd/mhd_send.h b/src/microhttpd/mhd_send.h
index bc296588..69a06769 100644
--- a/src/microhttpd/mhd_send.h
+++ b/src/microhttpd/mhd_send.h
@@ -92,9 +92,16 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
92 * 92 *
93 * @param connection the MHD_Connection structure 93 * @param connection the MHD_Connection structure
94 * @param header content of header to send 94 * @param header content of header to send
95 * @param header_size the size of the header (in bytes) 95 * @param header_size the size of the @a header (in bytes)
96 * @param never_push_hdr set to true to disable internal algorithm
97 * that can push automatically header data
98 * alone to the network
96 * @param body content of the body to send (optional, may be NULL) 99 * @param body content of the body to send (optional, may be NULL)
97 * @param body_size the size of the body (in bytes) 100 * @param body_size the size of the @a body (in bytes)
101 * @param complete_response set to true if complete response
102 * is provided by @a header and @a body,
103 * set to false if additional body data
104 * will be sent later
98 * @return sum of the number of bytes sent from both buffers or 105 * @return sum of the number of bytes sent from both buffers or
99 * error code (negative) 106 * error code (negative)
100 */ 107 */
@@ -102,8 +109,10 @@ ssize_t
102MHD_send_hdr_and_body_ (struct MHD_Connection *connection, 109MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
103 const char *header, 110 const char *header,
104 size_t header_size, 111 size_t header_size,
112 bool never_push_hdr,
105 const char *body, 113 const char *body,
106 size_t body_size); 114 size_t body_size,
115 bool complete_response);
107 116
108#if defined(_MHD_HAVE_SENDFILE) 117#if defined(_MHD_HAVE_SENDFILE)
109ssize_t 118ssize_t