lib1533.c (5469B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 /* 26 * This test sends data with CURLOPT_KEEP_SENDING_ON_ERROR. 27 * The server responds with an early error response. 28 * The test is successful if the connection can be reused for the next request, 29 * because this implies that the data has been sent completely to the server. 30 */ 31 32 #include "first.h" 33 34 #include "memdebug.h" 35 36 struct cb_data { 37 CURL *easy_handle; 38 int response_received; 39 int paused; 40 size_t remaining_bytes; 41 }; 42 43 static void reset_data(struct cb_data *data, CURL *curl) 44 { 45 data->easy_handle = curl; 46 data->response_received = 0; 47 data->paused = 0; 48 data->remaining_bytes = 3; 49 } 50 51 static size_t t1533_read_cb(char *ptr, size_t size, size_t nitems, void *userp) 52 { 53 struct cb_data *data = (struct cb_data *)userp; 54 55 /* wait until the server has sent all response headers */ 56 if(data->response_received) { 57 size_t totalsize = nitems * size; 58 59 size_t bytes_to_send = data->remaining_bytes; 60 if(bytes_to_send > totalsize) { 61 bytes_to_send = totalsize; 62 } 63 64 memset(ptr, 'a', bytes_to_send); 65 data->remaining_bytes -= bytes_to_send; 66 67 return bytes_to_send; 68 } 69 else { 70 data->paused = 1; 71 return CURL_READFUNC_PAUSE; 72 } 73 } 74 75 static size_t t1533_write_cb(char *ptr, size_t size, size_t nmemb, void *userp) 76 { 77 struct cb_data *data = (struct cb_data *)userp; 78 size_t totalsize = nmemb * size; 79 80 /* unused parameter */ 81 (void)ptr; 82 83 /* all response headers have been received */ 84 data->response_received = 1; 85 86 if(data->paused) { 87 /* continue to send request body data */ 88 data->paused = 0; 89 curl_easy_pause(data->easy_handle, CURLPAUSE_CONT); 90 } 91 92 return totalsize; 93 } 94 95 static CURLcode perform_and_check_connections(CURL *curl, 96 const char *description, 97 long expected_connections) 98 { 99 CURLcode res; 100 long connections = 0; 101 102 res = curl_easy_perform(curl); 103 if(res != CURLE_OK) { 104 curl_mfprintf(stderr, "curl_easy_perform() failed with %d\n", res); 105 return TEST_ERR_MAJOR_BAD; 106 } 107 108 res = curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &connections); 109 if(res != CURLE_OK) { 110 curl_mfprintf(stderr, "curl_easy_getinfo() failed\n"); 111 return TEST_ERR_MAJOR_BAD; 112 } 113 114 curl_mfprintf(stderr, 115 "%s: expected: %ld connections; actual: %ld connections\n", 116 description, expected_connections, connections); 117 118 if(connections != expected_connections) { 119 return TEST_ERR_FAILURE; 120 } 121 122 return TEST_ERR_SUCCESS; 123 } 124 125 126 static CURLcode test_lib1533(char *URL) 127 { 128 struct cb_data data; 129 CURL *curl = NULL; 130 CURLcode res = TEST_ERR_FAILURE; 131 CURLcode result; 132 133 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 134 curl_mfprintf(stderr, "curl_global_init() failed\n"); 135 return TEST_ERR_MAJOR_BAD; 136 } 137 138 curl = curl_easy_init(); 139 if(!curl) { 140 curl_mfprintf(stderr, "curl_easy_init() failed\n"); 141 curl_global_cleanup(); 142 return TEST_ERR_MAJOR_BAD; 143 } 144 145 reset_data(&data, curl); 146 147 test_setopt(curl, CURLOPT_URL, URL); 148 test_setopt(curl, CURLOPT_POST, 1L); 149 test_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, 150 (curl_off_t)data.remaining_bytes); 151 test_setopt(curl, CURLOPT_VERBOSE, 1L); 152 test_setopt(curl, CURLOPT_READFUNCTION, t1533_read_cb); 153 test_setopt(curl, CURLOPT_READDATA, &data); 154 test_setopt(curl, CURLOPT_WRITEFUNCTION, t1533_write_cb); 155 test_setopt(curl, CURLOPT_WRITEDATA, &data); 156 157 result = perform_and_check_connections(curl, 158 "First request without CURLOPT_KEEP_SENDING_ON_ERROR", 1); 159 if(result != TEST_ERR_SUCCESS) { 160 res = result; 161 goto test_cleanup; 162 } 163 164 reset_data(&data, curl); 165 166 result = perform_and_check_connections(curl, 167 "Second request without CURLOPT_KEEP_SENDING_ON_ERROR", 1); 168 if(result != TEST_ERR_SUCCESS) { 169 res = result; 170 goto test_cleanup; 171 } 172 173 test_setopt(curl, CURLOPT_KEEP_SENDING_ON_ERROR, 1L); 174 175 reset_data(&data, curl); 176 177 result = perform_and_check_connections(curl, 178 "First request with CURLOPT_KEEP_SENDING_ON_ERROR", 1); 179 if(result != TEST_ERR_SUCCESS) { 180 res = result; 181 goto test_cleanup; 182 } 183 184 reset_data(&data, curl); 185 186 result = perform_and_check_connections(curl, 187 "Second request with CURLOPT_KEEP_SENDING_ON_ERROR", 0); 188 if(result != TEST_ERR_SUCCESS) { 189 res = result; 190 goto test_cleanup; 191 } 192 193 res = TEST_ERR_SUCCESS; 194 195 test_cleanup: 196 197 curl_easy_cleanup(curl); 198 199 curl_global_cleanup(); 200 201 return res; 202 }