Home | History | Annotate | Download | only in src
      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