1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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.haxx.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 ***************************************************************************/ 22 #include "tool_setup.h" 23 #define ENABLE_CURLX_PRINTF 24 /* use our own printf() functions */ 25 #include "curlx.h" 26 #include "tool_cfgable.h" 27 #include "tool_writeout.h" 28 29 #include "memdebug.h" /* keep this as LAST include */ 30 31 typedef enum { 32 VAR_NONE, /* must be the first */ 33 VAR_TOTAL_TIME, 34 VAR_NAMELOOKUP_TIME, 35 VAR_CONNECT_TIME, 36 VAR_APPCONNECT_TIME, 37 VAR_PRETRANSFER_TIME, 38 VAR_STARTTRANSFER_TIME, 39 VAR_SIZE_DOWNLOAD, 40 VAR_SIZE_UPLOAD, 41 VAR_SPEED_DOWNLOAD, 42 VAR_SPEED_UPLOAD, 43 VAR_HTTP_CODE, 44 VAR_HTTP_CODE_PROXY, 45 VAR_HEADER_SIZE, 46 VAR_REQUEST_SIZE, 47 VAR_EFFECTIVE_URL, 48 VAR_CONTENT_TYPE, 49 VAR_NUM_CONNECTS, 50 VAR_REDIRECT_TIME, 51 VAR_REDIRECT_COUNT, 52 VAR_FTP_ENTRY_PATH, 53 VAR_REDIRECT_URL, 54 VAR_SSL_VERIFY_RESULT, 55 VAR_PROXY_SSL_VERIFY_RESULT, 56 VAR_EFFECTIVE_FILENAME, 57 VAR_PRIMARY_IP, 58 VAR_PRIMARY_PORT, 59 VAR_LOCAL_IP, 60 VAR_LOCAL_PORT, 61 VAR_HTTP_VERSION, 62 VAR_SCHEME, 63 VAR_NUM_OF_VARS /* must be the last */ 64 } replaceid; 65 66 struct variable { 67 const char *name; 68 replaceid id; 69 }; 70 71 72 static const struct variable replacements[]={ 73 {"url_effective", VAR_EFFECTIVE_URL}, 74 {"http_code", VAR_HTTP_CODE}, 75 {"response_code", VAR_HTTP_CODE}, 76 {"http_connect", VAR_HTTP_CODE_PROXY}, 77 {"time_total", VAR_TOTAL_TIME}, 78 {"time_namelookup", VAR_NAMELOOKUP_TIME}, 79 {"time_connect", VAR_CONNECT_TIME}, 80 {"time_appconnect", VAR_APPCONNECT_TIME}, 81 {"time_pretransfer", VAR_PRETRANSFER_TIME}, 82 {"time_starttransfer", VAR_STARTTRANSFER_TIME}, 83 {"size_header", VAR_HEADER_SIZE}, 84 {"size_request", VAR_REQUEST_SIZE}, 85 {"size_download", VAR_SIZE_DOWNLOAD}, 86 {"size_upload", VAR_SIZE_UPLOAD}, 87 {"speed_download", VAR_SPEED_DOWNLOAD}, 88 {"speed_upload", VAR_SPEED_UPLOAD}, 89 {"content_type", VAR_CONTENT_TYPE}, 90 {"num_connects", VAR_NUM_CONNECTS}, 91 {"time_redirect", VAR_REDIRECT_TIME}, 92 {"num_redirects", VAR_REDIRECT_COUNT}, 93 {"ftp_entry_path", VAR_FTP_ENTRY_PATH}, 94 {"redirect_url", VAR_REDIRECT_URL}, 95 {"ssl_verify_result", VAR_SSL_VERIFY_RESULT}, 96 {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT}, 97 {"filename_effective", VAR_EFFECTIVE_FILENAME}, 98 {"remote_ip", VAR_PRIMARY_IP}, 99 {"remote_port", VAR_PRIMARY_PORT}, 100 {"local_ip", VAR_LOCAL_IP}, 101 {"local_port", VAR_LOCAL_PORT}, 102 {"http_version", VAR_HTTP_VERSION}, 103 {"scheme", VAR_SCHEME}, 104 {NULL, VAR_NONE} 105 }; 106 107 void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo) 108 { 109 FILE *stream = stdout; 110 const char *ptr = writeinfo; 111 char *stringp = NULL; 112 long longinfo; 113 double doubleinfo; 114 115 while(ptr && *ptr) { 116 if('%' == *ptr && ptr[1]) { 117 if('%' == ptr[1]) { 118 /* an escaped %-letter */ 119 fputc('%', stream); 120 ptr += 2; 121 } 122 else { 123 /* this is meant as a variable to output */ 124 char *end; 125 char keepit; 126 int i; 127 if('{' == ptr[1]) { 128 bool match = FALSE; 129 end = strchr(ptr, '}'); 130 ptr += 2; /* pass the % and the { */ 131 if(!end) { 132 fputs("%{", stream); 133 continue; 134 } 135 keepit = *end; 136 *end = 0; /* zero terminate */ 137 for(i = 0; replacements[i].name; i++) { 138 if(curl_strequal(ptr, replacements[i].name)) { 139 match = TRUE; 140 switch(replacements[i].id) { 141 case VAR_EFFECTIVE_URL: 142 if((CURLE_OK == 143 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp)) 144 && stringp) 145 fputs(stringp, stream); 146 break; 147 case VAR_HTTP_CODE: 148 if(CURLE_OK == 149 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo)) 150 fprintf(stream, "%03ld", longinfo); 151 break; 152 case VAR_HTTP_CODE_PROXY: 153 if(CURLE_OK == 154 curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, 155 &longinfo)) 156 fprintf(stream, "%03ld", longinfo); 157 break; 158 case VAR_HEADER_SIZE: 159 if(CURLE_OK == 160 curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo)) 161 fprintf(stream, "%ld", longinfo); 162 break; 163 case VAR_REQUEST_SIZE: 164 if(CURLE_OK == 165 curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo)) 166 fprintf(stream, "%ld", longinfo); 167 break; 168 case VAR_NUM_CONNECTS: 169 if(CURLE_OK == 170 curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo)) 171 fprintf(stream, "%ld", longinfo); 172 break; 173 case VAR_REDIRECT_COUNT: 174 if(CURLE_OK == 175 curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo)) 176 fprintf(stream, "%ld", longinfo); 177 break; 178 case VAR_REDIRECT_TIME: 179 if(CURLE_OK == 180 curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, 181 &doubleinfo)) 182 fprintf(stream, "%.6f", doubleinfo); 183 break; 184 case VAR_TOTAL_TIME: 185 if(CURLE_OK == 186 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo)) 187 fprintf(stream, "%.6f", doubleinfo); 188 break; 189 case VAR_NAMELOOKUP_TIME: 190 if(CURLE_OK == 191 curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, 192 &doubleinfo)) 193 fprintf(stream, "%.6f", doubleinfo); 194 break; 195 case VAR_CONNECT_TIME: 196 if(CURLE_OK == 197 curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo)) 198 fprintf(stream, "%.6f", doubleinfo); 199 break; 200 case VAR_APPCONNECT_TIME: 201 if(CURLE_OK == 202 curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, 203 &doubleinfo)) 204 fprintf(stream, "%.6f", doubleinfo); 205 break; 206 case VAR_PRETRANSFER_TIME: 207 if(CURLE_OK == 208 curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, 209 &doubleinfo)) 210 fprintf(stream, "%.6f", doubleinfo); 211 break; 212 case VAR_STARTTRANSFER_TIME: 213 if(CURLE_OK == 214 curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, 215 &doubleinfo)) 216 fprintf(stream, "%.6f", doubleinfo); 217 break; 218 case VAR_SIZE_UPLOAD: 219 if(CURLE_OK == 220 curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo)) 221 fprintf(stream, "%.0f", doubleinfo); 222 break; 223 case VAR_SIZE_DOWNLOAD: 224 if(CURLE_OK == 225 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, 226 &doubleinfo)) 227 fprintf(stream, "%.0f", doubleinfo); 228 break; 229 case VAR_SPEED_DOWNLOAD: 230 if(CURLE_OK == 231 curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, 232 &doubleinfo)) 233 fprintf(stream, "%.3f", doubleinfo); 234 break; 235 case VAR_SPEED_UPLOAD: 236 if(CURLE_OK == 237 curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo)) 238 fprintf(stream, "%.3f", doubleinfo); 239 break; 240 case VAR_CONTENT_TYPE: 241 if((CURLE_OK == 242 curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp)) 243 && stringp) 244 fputs(stringp, stream); 245 break; 246 case VAR_FTP_ENTRY_PATH: 247 if((CURLE_OK == 248 curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp)) 249 && stringp) 250 fputs(stringp, stream); 251 break; 252 case VAR_REDIRECT_URL: 253 if((CURLE_OK == 254 curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp)) 255 && stringp) 256 fputs(stringp, stream); 257 break; 258 case VAR_SSL_VERIFY_RESULT: 259 if(CURLE_OK == 260 curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, 261 &longinfo)) 262 fprintf(stream, "%ld", longinfo); 263 break; 264 case VAR_PROXY_SSL_VERIFY_RESULT: 265 if(CURLE_OK == 266 curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, 267 &longinfo)) 268 fprintf(stream, "%ld", longinfo); 269 break; 270 case VAR_EFFECTIVE_FILENAME: 271 if(outs->filename) 272 fprintf(stream, "%s", outs->filename); 273 break; 274 case VAR_PRIMARY_IP: 275 if(CURLE_OK == 276 curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, 277 &stringp)) 278 fprintf(stream, "%s", stringp); 279 break; 280 case VAR_PRIMARY_PORT: 281 if(CURLE_OK == 282 curl_easy_getinfo(curl, CURLINFO_PRIMARY_PORT, 283 &longinfo)) 284 fprintf(stream, "%ld", longinfo); 285 break; 286 case VAR_LOCAL_IP: 287 if(CURLE_OK == 288 curl_easy_getinfo(curl, CURLINFO_LOCAL_IP, 289 &stringp)) 290 fprintf(stream, "%s", stringp); 291 break; 292 case VAR_LOCAL_PORT: 293 if(CURLE_OK == 294 curl_easy_getinfo(curl, CURLINFO_LOCAL_PORT, 295 &longinfo)) 296 fprintf(stream, "%ld", longinfo); 297 break; 298 case VAR_HTTP_VERSION: 299 if(CURLE_OK == 300 curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, 301 &longinfo)) { 302 const char *version = "0"; 303 switch(longinfo) { 304 case CURL_HTTP_VERSION_1_0: 305 version = "1.0"; 306 break; 307 case CURL_HTTP_VERSION_1_1: 308 version = "1.1"; 309 break; 310 case CURL_HTTP_VERSION_2_0: 311 version = "2"; 312 break; 313 } 314 315 fprintf(stream, version); 316 } 317 break; 318 case VAR_SCHEME: 319 if(CURLE_OK == 320 curl_easy_getinfo(curl, CURLINFO_SCHEME, 321 &stringp)) 322 fprintf(stream, "%s", stringp); 323 break; 324 default: 325 break; 326 } 327 break; 328 } 329 } 330 if(!match) { 331 fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr); 332 } 333 ptr = end + 1; /* pass the end */ 334 *end = keepit; 335 } 336 else { 337 /* illegal syntax, then just output the characters that are used */ 338 fputc('%', stream); 339 fputc(ptr[1], stream); 340 ptr += 2; 341 } 342 } 343 } 344 else if('\\' == *ptr && ptr[1]) { 345 switch(ptr[1]) { 346 case 'r': 347 fputc('\r', stream); 348 break; 349 case 'n': 350 fputc('\n', stream); 351 break; 352 case 't': 353 fputc('\t', stream); 354 break; 355 default: 356 /* unknown, just output this */ 357 fputc(*ptr, stream); 358 fputc(ptr[1], stream); 359 break; 360 } 361 ptr += 2; 362 } 363 else { 364 fputc(*ptr, stream); 365 ptr++; 366 } 367 } 368 369 } 370