upload_pausing.c (5635B)
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 /* This is based on the PoC client of issue #11769 25 */ 26 #include "first.h" 27 28 static size_t total_read = 0; 29 30 static size_t read_callback(char *ptr, size_t size, size_t nmemb, 31 void *userdata) 32 { 33 static const size_t PAUSE_READ_AFTER = 1; 34 35 (void)size; 36 (void)nmemb; 37 (void)userdata; 38 if(total_read >= PAUSE_READ_AFTER) { 39 curl_mfprintf(stderr, "read_callback, return PAUSE\n"); 40 return CURL_READFUNC_PAUSE; 41 } 42 else { 43 ptr[0] = '\n'; 44 ++total_read; 45 curl_mfprintf(stderr, "read_callback, return 1 byte\n"); 46 return 1; 47 } 48 } 49 50 static int progress_callback(void *clientp, 51 curl_off_t dltotal, 52 curl_off_t dlnow, 53 curl_off_t ultotal, 54 curl_off_t ulnow) 55 { 56 (void)dltotal; 57 (void)dlnow; 58 (void)ultotal; 59 (void)ulnow; 60 (void)clientp; 61 #if 0 62 /* Used to unpause on progress, but keeping for now. */ 63 { 64 CURL *curl = (CURL *)clientp; 65 curl_easy_pause(curl, CURLPAUSE_CONT); 66 /* curl_easy_pause(curl, CURLPAUSE_RECV_CONT); */ 67 } 68 #endif 69 return 0; 70 } 71 72 static void usage_upload_pausing(const char *msg) 73 { 74 if(msg) 75 curl_mfprintf(stderr, "%s\n", msg); 76 curl_mfprintf(stderr, 77 "usage: [options] url\n" 78 " upload and pause, options:\n" 79 " -V http_version (http/1.1, h2, h3) http version to use\n" 80 ); 81 } 82 83 static int test_upload_pausing(int argc, char *argv[]) 84 { 85 CURL *curl; 86 CURLcode rc = CURLE_OK; 87 CURLU *cu; 88 struct curl_slist *resolve = NULL; 89 char resolve_buf[1024]; 90 char *url, *host = NULL, *port = NULL; 91 long http_version = CURL_HTTP_VERSION_1_1; 92 int ch; 93 94 while((ch = cgetopt(argc, argv, "V:")) != -1) { 95 switch(ch) { 96 case 'V': { 97 if(!strcmp("http/1.1", coptarg)) 98 http_version = CURL_HTTP_VERSION_1_1; 99 else if(!strcmp("h2", coptarg)) 100 http_version = CURL_HTTP_VERSION_2_0; 101 else if(!strcmp("h3", coptarg)) 102 http_version = CURL_HTTP_VERSION_3ONLY; 103 else { 104 usage_upload_pausing("invalid http version"); 105 return 1; 106 } 107 break; 108 } 109 default: 110 usage_upload_pausing("invalid option"); 111 return 1; 112 } 113 } 114 argc -= coptind; 115 argv += coptind; 116 117 if(argc != 1) { 118 usage_upload_pausing("not enough arguments"); 119 return 2; 120 } 121 url = argv[0]; 122 123 curl_global_init(CURL_GLOBAL_DEFAULT); 124 curl_global_trace("ids,time"); 125 126 cu = curl_url(); 127 if(!cu) { 128 curl_mfprintf(stderr, "out of memory\n"); 129 return 1; 130 } 131 if(curl_url_set(cu, CURLUPART_URL, url, 0)) { 132 curl_mfprintf(stderr, "not a URL: '%s'\n", url); 133 return 1; 134 } 135 if(curl_url_get(cu, CURLUPART_HOST, &host, 0)) { 136 curl_mfprintf(stderr, "could not get host of '%s'\n", url); 137 return 1; 138 } 139 if(curl_url_get(cu, CURLUPART_PORT, &port, 0)) { 140 curl_mfprintf(stderr, "could not get port of '%s'\n", url); 141 return 1; 142 } 143 memset(&resolve, 0, sizeof(resolve)); 144 curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1", 145 host, port); 146 resolve = curl_slist_append(resolve, resolve_buf); 147 148 curl = curl_easy_init(); 149 if(!curl) { 150 curl_mfprintf(stderr, "out of memory\n"); 151 return 1; 152 } 153 /* We want to use our own read function. */ 154 curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); 155 156 /* It will help us to continue the read function. */ 157 curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); 158 curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl); 159 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); 160 161 /* It will help us to ensure that keepalive does not help. */ 162 curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); 163 curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L); 164 curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L); 165 curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 1L); 166 167 /* Enable uploading. */ 168 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); 169 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); 170 171 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 172 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 173 174 if(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) != CURLE_OK || 175 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_cb) 176 != CURLE_OK || 177 curl_easy_setopt(curl, CURLOPT_RESOLVE, resolve) != CURLE_OK) 178 ERR(); 179 180 curl_easy_setopt(curl, CURLOPT_URL, url); 181 curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, http_version); 182 183 rc = curl_easy_perform(curl); 184 185 if(curl) { 186 curl_easy_cleanup(curl); 187 } 188 189 curl_slist_free_all(resolve); 190 curl_free(host); 191 curl_free(port); 192 curl_url_cleanup(cu); 193 curl_global_cleanup(); 194 195 return (int)rc; 196 }