diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-12-13 17:24:36 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-12-13 17:24:36 +0300 |
commit | 75e49713c671acc9d0df6167b23bbb0c1273b8df (patch) | |
tree | 96d350877a41a46f9c32b45c9c521163bbc1b6b4 | |
parent | cd8294e59dc3d32062c8a3ddd6e5a203f746958d (diff) | |
download | libmicrohttpd-75e49713c671acc9d0df6167b23bbb0c1273b8df.tar.gz libmicrohttpd-75e49713c671acc9d0df6167b23bbb0c1273b8df.zip |
mhd_send.c: Fixed: body and header pushing logic
-rw-r--r-- | src/microhttpd/connection.c | 13 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.c | 81 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.h | 15 |
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 | |||
811 | MHD_send_hdr_and_body_ (struct MHD_Connection *connection, | 811 | MHD_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 | |||
102 | MHD_send_hdr_and_body_ (struct MHD_Connection *connection, | 109 | MHD_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) |
109 | ssize_t | 118 | ssize_t |