1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 http://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 "setup.h" 23 24#include <curl/curl.h> 25 26#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */ 27#include <curl/mprintf.h> 28 29#include "tool_writeout.h" 30 31#include "memdebug.h" /* keep this as LAST include */ 32 33typedef enum { 34 VAR_NONE, /* must be the first */ 35 VAR_TOTAL_TIME, 36 VAR_NAMELOOKUP_TIME, 37 VAR_CONNECT_TIME, 38 VAR_APPCONNECT_TIME, 39 VAR_PRETRANSFER_TIME, 40 VAR_STARTTRANSFER_TIME, 41 VAR_SIZE_DOWNLOAD, 42 VAR_SIZE_UPLOAD, 43 VAR_SPEED_DOWNLOAD, 44 VAR_SPEED_UPLOAD, 45 VAR_HTTP_CODE, 46 VAR_HTTP_CODE_PROXY, 47 VAR_HEADER_SIZE, 48 VAR_REQUEST_SIZE, 49 VAR_EFFECTIVE_URL, 50 VAR_CONTENT_TYPE, 51 VAR_NUM_CONNECTS, 52 VAR_REDIRECT_TIME, 53 VAR_REDIRECT_COUNT, 54 VAR_FTP_ENTRY_PATH, 55 VAR_REDIRECT_URL, 56 VAR_SSL_VERIFY_RESULT, 57 VAR_NUM_OF_VARS /* must be the last */ 58} replaceid; 59 60struct variable { 61 const char *name; 62 replaceid id; 63}; 64 65 66static const struct variable replacements[]={ 67 {"url_effective", VAR_EFFECTIVE_URL}, 68 {"http_code", VAR_HTTP_CODE}, 69 {"response_code", VAR_HTTP_CODE}, 70 {"http_connect", VAR_HTTP_CODE_PROXY}, 71 {"time_total", VAR_TOTAL_TIME}, 72 {"time_namelookup", VAR_NAMELOOKUP_TIME}, 73 {"time_connect", VAR_CONNECT_TIME}, 74 {"time_appconnect", VAR_APPCONNECT_TIME}, 75 {"time_pretransfer", VAR_PRETRANSFER_TIME}, 76 {"time_starttransfer", VAR_STARTTRANSFER_TIME}, 77 {"size_header", VAR_HEADER_SIZE}, 78 {"size_request", VAR_REQUEST_SIZE}, 79 {"size_download", VAR_SIZE_DOWNLOAD}, 80 {"size_upload", VAR_SIZE_UPLOAD}, 81 {"speed_download", VAR_SPEED_DOWNLOAD}, 82 {"speed_upload", VAR_SPEED_UPLOAD}, 83 {"content_type", VAR_CONTENT_TYPE}, 84 {"num_connects", VAR_NUM_CONNECTS}, 85 {"time_redirect", VAR_REDIRECT_TIME}, 86 {"num_redirects", VAR_REDIRECT_COUNT}, 87 {"ftp_entry_path", VAR_FTP_ENTRY_PATH}, 88 {"redirect_url", VAR_REDIRECT_URL}, 89 {"ssl_verify_result", VAR_SSL_VERIFY_RESULT}, 90 {NULL, VAR_NONE} 91}; 92 93void ourWriteOut(CURL *curl, const char *writeinfo) 94{ 95 FILE *stream = stdout; 96 const char *ptr = writeinfo; 97 char *stringp; 98 long longinfo; 99 double doubleinfo; 100 101 while(ptr && *ptr) { 102 if('%' == *ptr) { 103 if('%' == ptr[1]) { 104 /* an escaped %-letter */ 105 fputc('%', stream); 106 ptr += 2; 107 } 108 else { 109 /* this is meant as a variable to output */ 110 char *end; 111 char keepit; 112 int i; 113 if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) { 114 bool match = FALSE; 115 ptr += 2; /* pass the % and the { */ 116 keepit = *end; 117 *end = 0; /* zero terminate */ 118 for(i = 0; replacements[i].name; i++) { 119 if(curl_strequal(ptr, replacements[i].name)) { 120 match = TRUE; 121 switch(replacements[i].id) { 122 case VAR_EFFECTIVE_URL: 123 if((CURLE_OK == 124 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp)) 125 && stringp) 126 fputs(stringp, stream); 127 break; 128 case VAR_HTTP_CODE: 129 if(CURLE_OK == 130 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo)) 131 fprintf(stream, "%03ld", longinfo); 132 break; 133 case VAR_HTTP_CODE_PROXY: 134 if(CURLE_OK == 135 curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, 136 &longinfo)) 137 fprintf(stream, "%03ld", longinfo); 138 break; 139 case VAR_HEADER_SIZE: 140 if(CURLE_OK == 141 curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo)) 142 fprintf(stream, "%ld", longinfo); 143 break; 144 case VAR_REQUEST_SIZE: 145 if(CURLE_OK == 146 curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo)) 147 fprintf(stream, "%ld", longinfo); 148 break; 149 case VAR_NUM_CONNECTS: 150 if(CURLE_OK == 151 curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo)) 152 fprintf(stream, "%ld", longinfo); 153 break; 154 case VAR_REDIRECT_COUNT: 155 if(CURLE_OK == 156 curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo)) 157 fprintf(stream, "%ld", longinfo); 158 break; 159 case VAR_REDIRECT_TIME: 160 if(CURLE_OK == 161 curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, 162 &doubleinfo)) 163 fprintf(stream, "%.3f", doubleinfo); 164 break; 165 case VAR_TOTAL_TIME: 166 if(CURLE_OK == 167 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo)) 168 fprintf(stream, "%.3f", doubleinfo); 169 break; 170 case VAR_NAMELOOKUP_TIME: 171 if(CURLE_OK == 172 curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, 173 &doubleinfo)) 174 fprintf(stream, "%.3f", doubleinfo); 175 break; 176 case VAR_CONNECT_TIME: 177 if(CURLE_OK == 178 curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo)) 179 fprintf(stream, "%.3f", doubleinfo); 180 break; 181 case VAR_APPCONNECT_TIME: 182 if(CURLE_OK == 183 curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, 184 &doubleinfo)) 185 fprintf(stream, "%.3f", doubleinfo); 186 break; 187 case VAR_PRETRANSFER_TIME: 188 if(CURLE_OK == 189 curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, 190 &doubleinfo)) 191 fprintf(stream, "%.3f", doubleinfo); 192 break; 193 case VAR_STARTTRANSFER_TIME: 194 if(CURLE_OK == 195 curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, 196 &doubleinfo)) 197 fprintf(stream, "%.3f", doubleinfo); 198 break; 199 case VAR_SIZE_UPLOAD: 200 if(CURLE_OK == 201 curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo)) 202 fprintf(stream, "%.0f", doubleinfo); 203 break; 204 case VAR_SIZE_DOWNLOAD: 205 if(CURLE_OK == 206 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, 207 &doubleinfo)) 208 fprintf(stream, "%.0f", doubleinfo); 209 break; 210 case VAR_SPEED_DOWNLOAD: 211 if(CURLE_OK == 212 curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, 213 &doubleinfo)) 214 fprintf(stream, "%.3f", doubleinfo); 215 break; 216 case VAR_SPEED_UPLOAD: 217 if(CURLE_OK == 218 curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo)) 219 fprintf(stream, "%.3f", doubleinfo); 220 break; 221 case VAR_CONTENT_TYPE: 222 if((CURLE_OK == 223 curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp)) 224 && stringp) 225 fputs(stringp, stream); 226 break; 227 case VAR_FTP_ENTRY_PATH: 228 if((CURLE_OK == 229 curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp)) 230 && stringp) 231 fputs(stringp, stream); 232 break; 233 case VAR_REDIRECT_URL: 234 if((CURLE_OK == 235 curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp)) 236 && stringp) 237 fputs(stringp, stream); 238 break; 239 case VAR_SSL_VERIFY_RESULT: 240 if(CURLE_OK == 241 curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, 242 &longinfo)) 243 fprintf(stream, "%ld", longinfo); 244 break; 245 default: 246 break; 247 } 248 break; 249 } 250 } 251 if(!match) { 252 fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr); 253 } 254 ptr = end + 1; /* pass the end */ 255 *end = keepit; 256 } 257 else { 258 /* illegal syntax, then just output the characters that are used */ 259 fputc('%', stream); 260 fputc(ptr[1], stream); 261 ptr += 2; 262 } 263 } 264 } 265 else if('\\' == *ptr) { 266 switch(ptr[1]) { 267 case 'r': 268 fputc('\r', stream); 269 break; 270 case 'n': 271 fputc('\n', stream); 272 break; 273 case 't': 274 fputc('\t', stream); 275 break; 276 default: 277 /* unknown, just output this */ 278 fputc(*ptr, stream); 279 fputc(ptr[1], stream); 280 break; 281 } 282 ptr += 2; 283 } 284 else { 285 fputc(*ptr, stream); 286 ptr++; 287 } 288 } 289 290} 291