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