diff options
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r-- | src/microhttpd/connection.c | 313 |
1 files changed, 234 insertions, 79 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index d6c4ac1e..4d912ce8 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -57,6 +57,16 @@ | |||
57 | #include "mhd_assert.h" | 57 | #include "mhd_assert.h" |
58 | 58 | ||
59 | /** | 59 | /** |
60 | * The reasonable length of the upload chunk "header" (the size specifier | ||
61 | * with optional chunk extension). | ||
62 | * MHD tries to keep the space in the read buffer large enough to read | ||
63 | * the chunk "header" in one step. | ||
64 | * The real "header" could be much larger, it will be handled correctly | ||
65 | * anyway, however it may require several rounds of buffer grow. | ||
66 | */ | ||
67 | #define MHD_CHUNK_HEADER_REASONABLE_LEN 24 | ||
68 | |||
69 | /** | ||
60 | * Message to transmit when http 1.1 request is received | 70 | * Message to transmit when http 1.1 request is received |
61 | */ | 71 | */ |
62 | #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" | 72 | #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" |
@@ -444,13 +454,13 @@ | |||
444 | * minimal. | 454 | * minimal. |
445 | */ | 455 | */ |
446 | #ifdef HAVE_MESSAGES | 456 | #ifdef HAVE_MESSAGES |
447 | #define INTERNAL_ERROR \ | 457 | #define ERROR_MSG_DATA_NOT_HANDLED_BY_APP \ |
448 | "<html><head><title>Internal server error</title></head>" \ | 458 | "<html><head><title>Internal server error</title></head>" \ |
449 | "<body>Please ask the developer of this Web server to carefully " \ | 459 | "<body>Please ask the developer of this Web server to carefully " \ |
450 | "read the GNU libmicrohttpd documentation about connection "\ | 460 | "read the GNU libmicrohttpd documentation about connection "\ |
451 | "management and blocking.</body></html>" | 461 | "management and blocking.</body></html>" |
452 | #else | 462 | #else |
453 | #define INTERNAL_ERROR "" | 463 | #define ERROR_MSG_DATA_NOT_HANDLED_BY_APP "" |
454 | #endif | 464 | #endif |
455 | 465 | ||
456 | /** | 466 | /** |
@@ -2819,6 +2829,182 @@ transmit_error_response_len (struct MHD_Connection *connection, | |||
2819 | hd_n, hd_n_l, \ | 2829 | hd_n, hd_n_l, \ |
2820 | hd_v, hd_v_l) | 2830 | hd_v, hd_v_l) |
2821 | 2831 | ||
2832 | |||
2833 | /** | ||
2834 | * Check whether the read buffer has any upload body data ready to | ||
2835 | * be processed. | ||
2836 | * Must be called only when connection is in MHD_CONNECTION_BODY_RECEIVING | ||
2837 | * state. | ||
2838 | * | ||
2839 | * @param c the connection to check | ||
2840 | * @return 'true' if upload body data is already in the read buffer, | ||
2841 | * 'false' if no upload data is received and not processed. | ||
2842 | */ | ||
2843 | static bool | ||
2844 | has_unprocessed_upload_body_data_in_buffer (struct MHD_Connection *c) | ||
2845 | { | ||
2846 | mhd_assert (MHD_CONNECTION_BODY_RECEIVING == c->state); | ||
2847 | if (! c->rq.have_chunked_upload) | ||
2848 | return 0 != c->read_buffer_offset; | ||
2849 | |||
2850 | /* Chunked upload */ | ||
2851 | mhd_assert (0 != c->rq.remaining_upload_size); /* Must not be possible in MHD_CONNECTION_BODY_RECEIVING state */ | ||
2852 | if (c->rq.current_chunk_offset == c->rq.current_chunk_size) | ||
2853 | { | ||
2854 | /* 0 == c->rq.current_chunk_size: Waiting the chunk size (chunk header). | ||
2855 | 0 != c->rq.current_chunk_size: Waiting for chunk-closing CRLF. */ | ||
2856 | return false; /* */ | ||
2857 | } | ||
2858 | return 0 != c->read_buffer_offset; /* Chunk payload data in the read buffer */ | ||
2859 | } | ||
2860 | |||
2861 | |||
2862 | /** | ||
2863 | * Check whether enough space is available in the read buffer for the next | ||
2864 | * operation. | ||
2865 | * Handles grow of the buffer if required and error conditions (when buffer | ||
2866 | * grow is required but not possible). | ||
2867 | * Must be called only when processing the event loop states and when | ||
2868 | * reading is required for the next phase. | ||
2869 | * @param c the connection to check | ||
2870 | * @return true if connection handled successfully and enough buffer | ||
2871 | * is available, | ||
2872 | * false if not enough buffer is available and the loop's states | ||
2873 | * must be processed again as connection is in the error state. | ||
2874 | */ | ||
2875 | static bool | ||
2876 | check_and_grow_read_buffer_space (struct MHD_Connection *c) | ||
2877 | { | ||
2878 | /** | ||
2879 | * The increase of read buffer size is desirable. | ||
2880 | */ | ||
2881 | bool rbuff_grow_desired; | ||
2882 | /** | ||
2883 | * The increase of read buffer size is a hard requirement. | ||
2884 | */ | ||
2885 | bool rbuff_grow_required; | ||
2886 | |||
2887 | mhd_assert (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info)); | ||
2888 | mhd_assert (! c->discard_request); | ||
2889 | |||
2890 | rbuff_grow_required = (c->read_buffer_offset == c->read_buffer_size); | ||
2891 | if (rbuff_grow_required) | ||
2892 | rbuff_grow_desired = true; | ||
2893 | else | ||
2894 | { | ||
2895 | rbuff_grow_desired = (c->read_buffer_offset + c->daemon->pool_increment > | ||
2896 | c->read_buffer_size); | ||
2897 | |||
2898 | if ((rbuff_grow_desired) && | ||
2899 | (MHD_CONNECTION_BODY_RECEIVING == c->state)) | ||
2900 | { | ||
2901 | if (! c->rq.have_chunked_upload) | ||
2902 | { | ||
2903 | mhd_assert (MHD_SIZE_UNKNOWN != c->rq.remaining_upload_size); | ||
2904 | /* Do not grow read buffer more than necessary to process the current | ||
2905 | request. */ | ||
2906 | rbuff_grow_desired = | ||
2907 | (c->rq.remaining_upload_size > c->read_buffer_size); | ||
2908 | } | ||
2909 | else | ||
2910 | { | ||
2911 | mhd_assert (MHD_SIZE_UNKNOWN == c->rq.remaining_upload_size); | ||
2912 | if (0 == c->rq.current_chunk_size) | ||
2913 | rbuff_grow_desired = /* Reading value of the next chunk size */ | ||
2914 | (MHD_CHUNK_HEADER_REASONABLE_LEN > | ||
2915 | c->read_buffer_size); | ||
2916 | else | ||
2917 | { | ||
2918 | const size_t cur_chunk_left = | ||
2919 | c->rq.current_chunk_size - c->rq.current_chunk_offset; | ||
2920 | /* Do not grow read buffer more than necessary to process the current | ||
2921 | chunk with terminating CRLF. */ | ||
2922 | mhd_assert (c->rq.current_chunk_offset <= c->rq.current_chunk_size); | ||
2923 | rbuff_grow_desired = ((cur_chunk_left + 2) > c->read_buffer_size); | ||
2924 | } | ||
2925 | } | ||
2926 | } | ||
2927 | } | ||
2928 | |||
2929 | if (! rbuff_grow_desired) | ||
2930 | return true; /* No need to increase the buffer */ | ||
2931 | |||
2932 | if (try_grow_read_buffer (c, rbuff_grow_required)) | ||
2933 | return true; /* Buffer increase succeed */ | ||
2934 | |||
2935 | if (! rbuff_grow_required) | ||
2936 | return true; /* Can continue without buffer increase */ | ||
2937 | |||
2938 | /* Failed to increase the read buffer size, but need to read the data | ||
2939 | from the network. | ||
2940 | No more space in the buffer, no more space to increase the buffer. */ | ||
2941 | |||
2942 | /* 'PROCESS_READ' event state flag must be set only if the last application | ||
2943 | callback has processed some data. If any data is processed then some | ||
2944 | space in the read buffer must be available. */ | ||
2945 | mhd_assert (0 == (MHD_EVENT_LOOP_INFO_PROCESS & c->event_loop_info)); | ||
2946 | |||
2947 | if (MHD_CONNECTION_BODY_RECEIVING != c->state) | ||
2948 | { | ||
2949 | /* Receiving request line, request headers or request footers */ | ||
2950 | /* TODO: Improve detection of the conditions */ | ||
2951 | if (c->rq.url != NULL) | ||
2952 | transmit_error_response_static (c, | ||
2953 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | ||
2954 | REQUEST_TOO_BIG); | ||
2955 | else | ||
2956 | transmit_error_response_static (c, | ||
2957 | MHD_HTTP_URI_TOO_LONG, | ||
2958 | REQUEST_TOO_BIG); | ||
2959 | return false; | ||
2960 | } | ||
2961 | |||
2962 | /* Receiving the request body and no space left in the buffer */ | ||
2963 | |||
2964 | if (! has_unprocessed_upload_body_data_in_buffer (c)) | ||
2965 | { | ||
2966 | /* Full header is received and no space left for reading | ||
2967 | the request body. | ||
2968 | For chunked upload encoding: chunk-extension is too long or | ||
2969 | chunk size is encoded with excessive number of leading zeros. */ | ||
2970 | /* TODO: report proper cause for the error */ | ||
2971 | transmit_error_response_static (c, | ||
2972 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | ||
2973 | REQUEST_TOO_BIG); | ||
2974 | return false; | ||
2975 | } | ||
2976 | |||
2977 | /* No space left in the buffer but some upload body data can be processed | ||
2978 | and some space could be freed. */ | ||
2979 | mhd_assert (! c->rq.some_payload_processed); | ||
2980 | if (0 == (c->daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) | ||
2981 | { | ||
2982 | /* The application is handling processing cycles. | ||
2983 | The data may be processed later. */ | ||
2984 | c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | ||
2985 | return true; | ||
2986 | } | ||
2987 | |||
2988 | /* Using internal thread for sockets polling */ | ||
2989 | |||
2990 | /* failed to grow the read buffer, and the | ||
2991 | client which is supposed to handle the | ||
2992 | received data in a *blocking* fashion | ||
2993 | (in this mode) did not handle the data as | ||
2994 | it was supposed to! | ||
2995 | => we would either have to do busy-waiting | ||
2996 | (on the client, which would likely fail), | ||
2997 | or if we do nothing, we would just timeout | ||
2998 | on the connection (if a timeout is even | ||
2999 | set!). | ||
3000 | Solution: we kill the connection with an error */ | ||
3001 | transmit_error_response_static (c, | ||
3002 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
3003 | ERROR_MSG_DATA_NOT_HANDLED_BY_APP); | ||
3004 | return false; | ||
3005 | } | ||
3006 | |||
3007 | |||
2822 | /** | 3008 | /** |
2823 | * Update the 'event_loop_info' field of this connection based on the state | 3009 | * Update the 'event_loop_info' field of this connection based on the state |
2824 | * that the connection is now in. May also close the connection or | 3010 | * that the connection is now in. May also close the connection or |
@@ -2875,31 +3061,15 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
2875 | { | 3061 | { |
2876 | case MHD_CONNECTION_INIT: | 3062 | case MHD_CONNECTION_INIT: |
2877 | case MHD_CONNECTION_REQ_LINE_RECEIVING: | 3063 | case MHD_CONNECTION_REQ_LINE_RECEIVING: |
3064 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
3065 | break; | ||
2878 | case MHD_CONNECTION_REQ_LINE_RECEIVED: | 3066 | case MHD_CONNECTION_REQ_LINE_RECEIVED: |
3067 | mhd_assert (0); | ||
3068 | break; | ||
2879 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: | 3069 | case MHD_CONNECTION_REQ_HEADERS_RECEIVING: |
2880 | /* while reading headers, we always grow the | 3070 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
2881 | read buffer if needed, no size-check required */ | ||
2882 | if ( (connection->read_buffer_offset == connection->read_buffer_size) && | ||
2883 | (! try_grow_read_buffer (connection, true)) ) | ||
2884 | { | ||
2885 | if (connection->rq.url != NULL) | ||
2886 | transmit_error_response_static (connection, | ||
2887 | MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, | ||
2888 | REQUEST_TOO_BIG); | ||
2889 | else | ||
2890 | transmit_error_response_static (connection, | ||
2891 | MHD_HTTP_URI_TOO_LONG, | ||
2892 | REQUEST_TOO_BIG); | ||
2893 | continue; | ||
2894 | } | ||
2895 | if (! connection->discard_request) | ||
2896 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
2897 | else | ||
2898 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | ||
2899 | break; | 3071 | break; |
2900 | case MHD_CONNECTION_HEADERS_RECEIVED: | 3072 | case MHD_CONNECTION_HEADERS_RECEIVED: |
2901 | mhd_assert (0); | ||
2902 | break; | ||
2903 | case MHD_CONNECTION_HEADERS_PROCESSED: | 3073 | case MHD_CONNECTION_HEADERS_PROCESSED: |
2904 | mhd_assert (0); | 3074 | mhd_assert (0); |
2905 | break; | 3075 | break; |
@@ -2907,54 +3077,37 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
2907 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | 3077 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
2908 | break; | 3078 | break; |
2909 | case MHD_CONNECTION_BODY_RECEIVING: | 3079 | case MHD_CONNECTION_BODY_RECEIVING: |
2910 | if (connection->read_buffer_offset == connection->read_buffer_size) | 3080 | if ((connection->rq.some_payload_processed) && |
3081 | has_unprocessed_upload_body_data_in_buffer (connection)) | ||
2911 | { | 3082 | { |
2912 | const bool internal_poll = (0 != (connection->daemon->options | 3083 | /* Some data was processed, the buffer must have some free space */ |
2913 | & MHD_USE_INTERNAL_POLLING_THREAD)); | 3084 | mhd_assert (connection->read_buffer_offset < \ |
2914 | if ( (! try_grow_read_buffer (connection, true)) && | 3085 | connection->read_buffer_size); |
2915 | internal_poll) | 3086 | if (! connection->rq.have_chunked_upload) |
2916 | { | 3087 | { |
2917 | /* failed to grow the read buffer, and the | 3088 | /* Not a chunked upload. Do not read more than necessary to |
2918 | client which is supposed to handle the | 3089 | process the current request. */ |
2919 | received data in a *blocking* fashion | 3090 | if (connection->rq.remaining_upload_size >= |
2920 | (in this mode) did not handle the data as | 3091 | connection->read_buffer_offset) |
2921 | it was supposed to! | 3092 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; |
2922 | => we would either have to do busy-waiting | 3093 | else |
2923 | (on the client, which would likely fail), | 3094 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ; |
2924 | or if we do nothing, we would just timeout | 3095 | } |
2925 | on the connection (if a timeout is even | 3096 | else |
2926 | set!). | 3097 | { |
2927 | Solution: we kill the connection with an error */ | 3098 | /* Chunked upload. The size of the current request is unknown. |
2928 | transmit_error_response_static (connection, | 3099 | Continue reading as the space in the read buffer is available. */ |
2929 | MHD_HTTP_INTERNAL_SERVER_ERROR, | 3100 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ; |
2930 | INTERNAL_ERROR); | ||
2931 | continue; | ||
2932 | } | 3101 | } |
2933 | } | 3102 | } |
2934 | if (connection->discard_request) | ||
2935 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | ||
2936 | else if (connection->read_buffer_offset == connection->read_buffer_size) | ||
2937 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | ||
2938 | else if (0 == connection->read_buffer_offset) | ||
2939 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | ||
2940 | else if (connection->rq.some_payload_processed) | ||
2941 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ; | ||
2942 | else | 3103 | else |
2943 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | 3104 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
2944 | break; | 3105 | break; |
2945 | case MHD_CONNECTION_BODY_RECEIVED: | 3106 | case MHD_CONNECTION_BODY_RECEIVED: |
3107 | mhd_assert (0); | ||
3108 | break; | ||
2946 | case MHD_CONNECTION_FOOTERS_RECEIVING: | 3109 | case MHD_CONNECTION_FOOTERS_RECEIVING: |
2947 | /* while reading footers, we always grow the | ||
2948 | read buffer if needed, no size-check required */ | ||
2949 | if (connection->read_closed) | ||
2950 | { | ||
2951 | CONNECTION_CLOSE_ERROR (connection, | ||
2952 | NULL); | ||
2953 | continue; | ||
2954 | } | ||
2955 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; | 3110 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; |
2956 | /* transition to FOOTERS_RECEIVED | ||
2957 | happens in read handler */ | ||
2958 | break; | 3111 | break; |
2959 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 3112 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
2960 | mhd_assert (0); | 3113 | mhd_assert (0); |
@@ -2972,18 +3125,18 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
2972 | case MHD_CONNECTION_HEADERS_SENT: | 3125 | case MHD_CONNECTION_HEADERS_SENT: |
2973 | mhd_assert (0); | 3126 | mhd_assert (0); |
2974 | break; | 3127 | break; |
2975 | case MHD_CONNECTION_NORMAL_BODY_READY: | ||
2976 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
2977 | break; | ||
2978 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | 3128 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: |
2979 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | 3129 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; |
2980 | break; | 3130 | break; |
2981 | case MHD_CONNECTION_CHUNKED_BODY_READY: | 3131 | case MHD_CONNECTION_NORMAL_BODY_READY: |
2982 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | 3132 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; |
2983 | break; | 3133 | break; |
2984 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: | 3134 | case MHD_CONNECTION_CHUNKED_BODY_UNREADY: |
2985 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; | 3135 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; |
2986 | break; | 3136 | break; |
3137 | case MHD_CONNECTION_CHUNKED_BODY_READY: | ||
3138 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; | ||
3139 | break; | ||
2987 | case MHD_CONNECTION_CHUNKED_BODY_SENT: | 3140 | case MHD_CONNECTION_CHUNKED_BODY_SENT: |
2988 | mhd_assert (0); | 3141 | mhd_assert (0); |
2989 | break; | 3142 | break; |
@@ -3004,7 +3157,17 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
3004 | default: | 3157 | default: |
3005 | mhd_assert (0); | 3158 | mhd_assert (0); |
3006 | } | 3159 | } |
3007 | break; | 3160 | |
3161 | if (0 != (MHD_EVENT_LOOP_INFO_READ & connection->event_loop_info)) | ||
3162 | { | ||
3163 | /* Check whether the space is available to receive data */ | ||
3164 | if (! check_and_grow_read_buffer_space (connection)) | ||
3165 | { | ||
3166 | mhd_assert (connection->discard_request); | ||
3167 | continue; | ||
3168 | } | ||
3169 | } | ||
3170 | break; /* Everything was processed. */ | ||
3008 | } | 3171 | } |
3009 | } | 3172 | } |
3010 | 3173 | ||
@@ -3555,8 +3718,6 @@ process_request_body (struct MHD_Connection *connection) | |||
3555 | size_t left_unprocessed; | 3718 | size_t left_unprocessed; |
3556 | size_t processed_size; | 3719 | size_t processed_size; |
3557 | 3720 | ||
3558 | connection->rq.some_payload_processed = false; | ||
3559 | |||
3560 | instant_retry = false; | 3721 | instant_retry = false; |
3561 | if (connection->rq.have_chunked_upload) | 3722 | if (connection->rq.have_chunked_upload) |
3562 | { | 3723 | { |
@@ -3756,9 +3917,9 @@ process_request_body (struct MHD_Connection *connection) | |||
3756 | if (left_unprocessed > to_be_processed) | 3917 | if (left_unprocessed > to_be_processed) |
3757 | MHD_PANIC (_ ("libmicrohttpd API violation.\n")); | 3918 | MHD_PANIC (_ ("libmicrohttpd API violation.\n")); |
3758 | 3919 | ||
3759 | if (left_unprocessed != to_be_processed) | 3920 | connection->rq.some_payload_processed = |
3760 | /* Something was processed by the application. */ | 3921 | (left_unprocessed != to_be_processed); |
3761 | connection->rq.some_payload_processed = true; | 3922 | |
3762 | if (0 != left_unprocessed) | 3923 | if (0 != left_unprocessed) |
3763 | { | 3924 | { |
3764 | instant_retry = false; /* client did not process everything */ | 3925 | instant_retry = false; /* client did not process everything */ |
@@ -5461,16 +5622,10 @@ MHD_connection_handle_read (struct MHD_Connection *connection, | |||
5461 | } | 5622 | } |
5462 | #endif /* HTTPS_SUPPORT */ | 5623 | #endif /* HTTPS_SUPPORT */ |
5463 | 5624 | ||
5464 | /* make sure "read" has a reasonable number of bytes | 5625 | mhd_assert (NULL != connection->read_buffer); |
5465 | in buffer to use per system call (if possible) */ | ||
5466 | if (connection->read_buffer_offset + connection->daemon->pool_increment > | ||
5467 | connection->read_buffer_size) | ||
5468 | try_grow_read_buffer (connection, | ||
5469 | (connection->read_buffer_size == | ||
5470 | connection->read_buffer_offset)); | ||
5471 | |||
5472 | if (connection->read_buffer_size == connection->read_buffer_offset) | 5626 | if (connection->read_buffer_size == connection->read_buffer_offset) |
5473 | return; /* No space for receiving data. */ | 5627 | return; /* No space for receiving data. */ |
5628 | |||
5474 | bytes_read = connection->recv_cls (connection, | 5629 | bytes_read = connection->recv_cls (connection, |
5475 | &connection->read_buffer | 5630 | &connection->read_buffer |
5476 | [connection->read_buffer_offset], | 5631 | [connection->read_buffer_offset], |