Home | History | Annotate | Download | only in lib
      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 
     23 #include "curl_setup.h"
     24 
     25 #include <curl/curl.h>
     26 
     27 #include "urldata.h"
     28 #include "getinfo.h"
     29 
     30 #include "vtls/vtls.h"
     31 #include "connect.h" /* Curl_getconnectinfo() */
     32 #include "progress.h"
     33 
     34 /* The last #include files should be: */
     35 #include "curl_memory.h"
     36 #include "memdebug.h"
     37 
     38 /*
     39  * Initialize statistical and informational data.
     40  *
     41  * This function is called in curl_easy_reset, curl_easy_duphandle and at the
     42  * beginning of a perform session. It must reset the session-info variables,
     43  * in particular all variables in struct PureInfo.
     44  */
     45 CURLcode Curl_initinfo(struct Curl_easy *data)
     46 {
     47   struct Progress *pro = &data->progress;
     48   struct PureInfo *info = &data->info;
     49 
     50   pro->t_nslookup = 0;
     51   pro->t_connect = 0;
     52   pro->t_appconnect = 0;
     53   pro->t_pretransfer = 0;
     54   pro->t_starttransfer = 0;
     55   pro->timespent = 0;
     56   pro->t_redirect = 0;
     57   pro->is_t_startransfer_set = false;
     58 
     59   info->httpcode = 0;
     60   info->httpproxycode = 0;
     61   info->httpversion = 0;
     62   info->filetime = -1; /* -1 is an illegal time and thus means unknown */
     63   info->timecond = FALSE;
     64 
     65   info->header_size = 0;
     66   info->request_size = 0;
     67   info->proxyauthavail = 0;
     68   info->httpauthavail = 0;
     69   info->numconnects = 0;
     70 
     71   free(info->contenttype);
     72   info->contenttype = NULL;
     73 
     74   free(info->wouldredirect);
     75   info->wouldredirect = NULL;
     76 
     77   info->conn_primary_ip[0] = '\0';
     78   info->conn_local_ip[0] = '\0';
     79   info->conn_primary_port = 0;
     80   info->conn_local_port = 0;
     81 
     82   info->conn_scheme = 0;
     83   info->conn_protocol = 0;
     84 
     85 #ifdef USE_SSL
     86   Curl_ssl_free_certinfo(data);
     87 #endif
     88 
     89   return CURLE_OK;
     90 }
     91 
     92 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
     93                              const char **param_charp)
     94 {
     95   switch(info) {
     96   case CURLINFO_EFFECTIVE_URL:
     97     *param_charp = data->change.url?data->change.url:(char *)"";
     98     break;
     99   case CURLINFO_CONTENT_TYPE:
    100     *param_charp = data->info.contenttype;
    101     break;
    102   case CURLINFO_PRIVATE:
    103     *param_charp = (char *) data->set.private_data;
    104     break;
    105   case CURLINFO_FTP_ENTRY_PATH:
    106     /* Return the entrypath string from the most recent connection.
    107        This pointer was copied from the connectdata structure by FTP.
    108        The actual string may be free()ed by subsequent libcurl calls so
    109        it must be copied to a safer area before the next libcurl call.
    110        Callers must never free it themselves. */
    111     *param_charp = data->state.most_recent_ftp_entrypath;
    112     break;
    113   case CURLINFO_REDIRECT_URL:
    114     /* Return the URL this request would have been redirected to if that
    115        option had been enabled! */
    116     *param_charp = data->info.wouldredirect;
    117     break;
    118   case CURLINFO_PRIMARY_IP:
    119     /* Return the ip address of the most recent (primary) connection */
    120     *param_charp = data->info.conn_primary_ip;
    121     break;
    122   case CURLINFO_LOCAL_IP:
    123     /* Return the source/local ip address of the most recent (primary)
    124        connection */
    125     *param_charp = data->info.conn_local_ip;
    126     break;
    127   case CURLINFO_RTSP_SESSION_ID:
    128     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
    129     break;
    130   case CURLINFO_SCHEME:
    131     *param_charp = data->info.conn_scheme;
    132     break;
    133 
    134   default:
    135     return CURLE_UNKNOWN_OPTION;
    136   }
    137 
    138   return CURLE_OK;
    139 }
    140 
    141 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
    142                              long *param_longp)
    143 {
    144   curl_socket_t sockfd;
    145 
    146   union {
    147     unsigned long *to_ulong;
    148     long          *to_long;
    149   } lptr;
    150 
    151   switch(info) {
    152   case CURLINFO_RESPONSE_CODE:
    153     *param_longp = data->info.httpcode;
    154     break;
    155   case CURLINFO_HTTP_CONNECTCODE:
    156     *param_longp = data->info.httpproxycode;
    157     break;
    158   case CURLINFO_FILETIME:
    159     *param_longp = data->info.filetime;
    160     break;
    161   case CURLINFO_HEADER_SIZE:
    162     *param_longp = data->info.header_size;
    163     break;
    164   case CURLINFO_REQUEST_SIZE:
    165     *param_longp = data->info.request_size;
    166     break;
    167   case CURLINFO_SSL_VERIFYRESULT:
    168     *param_longp = data->set.ssl.certverifyresult;
    169     break;
    170   case CURLINFO_PROXY_SSL_VERIFYRESULT:
    171     *param_longp = data->set.proxy_ssl.certverifyresult;
    172     break;
    173   case CURLINFO_REDIRECT_COUNT:
    174     *param_longp = data->set.followlocation;
    175     break;
    176   case CURLINFO_HTTPAUTH_AVAIL:
    177     lptr.to_long = param_longp;
    178     *lptr.to_ulong = data->info.httpauthavail;
    179     break;
    180   case CURLINFO_PROXYAUTH_AVAIL:
    181     lptr.to_long = param_longp;
    182     *lptr.to_ulong = data->info.proxyauthavail;
    183     break;
    184   case CURLINFO_OS_ERRNO:
    185     *param_longp = data->state.os_errno;
    186     break;
    187   case CURLINFO_NUM_CONNECTS:
    188     *param_longp = data->info.numconnects;
    189     break;
    190   case CURLINFO_LASTSOCKET:
    191     sockfd = Curl_getconnectinfo(data, NULL);
    192 
    193     /* note: this is not a good conversion for systems with 64 bit sockets and
    194        32 bit longs */
    195     if(sockfd != CURL_SOCKET_BAD)
    196       *param_longp = (long)sockfd;
    197     else
    198       /* this interface is documented to return -1 in case of badness, which
    199          may not be the same as the CURL_SOCKET_BAD value */
    200       *param_longp = -1;
    201     break;
    202   case CURLINFO_PRIMARY_PORT:
    203     /* Return the (remote) port of the most recent (primary) connection */
    204     *param_longp = data->info.conn_primary_port;
    205     break;
    206   case CURLINFO_LOCAL_PORT:
    207     /* Return the local port of the most recent (primary) connection */
    208     *param_longp = data->info.conn_local_port;
    209     break;
    210   case CURLINFO_CONDITION_UNMET:
    211     /* return if the condition prevented the document to get transferred */
    212     *param_longp = data->info.timecond ? 1L : 0L;
    213     break;
    214   case CURLINFO_RTSP_CLIENT_CSEQ:
    215     *param_longp = data->state.rtsp_next_client_CSeq;
    216     break;
    217   case CURLINFO_RTSP_SERVER_CSEQ:
    218     *param_longp = data->state.rtsp_next_server_CSeq;
    219     break;
    220   case CURLINFO_RTSP_CSEQ_RECV:
    221     *param_longp = data->state.rtsp_CSeq_recv;
    222     break;
    223   case CURLINFO_HTTP_VERSION:
    224     switch(data->info.httpversion) {
    225     case 10:
    226       *param_longp = CURL_HTTP_VERSION_1_0;
    227       break;
    228     case 11:
    229       *param_longp = CURL_HTTP_VERSION_1_1;
    230       break;
    231     case 20:
    232       *param_longp = CURL_HTTP_VERSION_2_0;
    233       break;
    234     default:
    235       *param_longp = CURL_HTTP_VERSION_NONE;
    236       break;
    237     }
    238     break;
    239   case CURLINFO_PROTOCOL:
    240     *param_longp = data->info.conn_protocol;
    241     break;
    242 
    243   default:
    244     return CURLE_UNKNOWN_OPTION;
    245   }
    246 
    247   return CURLE_OK;
    248 }
    249 
    250 #define DOUBLE_SECS(x) (double)(x)/1000000
    251 
    252 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
    253                              curl_off_t *param_offt)
    254 {
    255   switch(info) {
    256   case CURLINFO_SIZE_UPLOAD_T:
    257     *param_offt = data->progress.uploaded;
    258     break;
    259   case CURLINFO_SIZE_DOWNLOAD_T:
    260     *param_offt = data->progress.downloaded;
    261     break;
    262   case CURLINFO_SPEED_DOWNLOAD_T:
    263     *param_offt =  data->progress.dlspeed;
    264     break;
    265   case CURLINFO_SPEED_UPLOAD_T:
    266     *param_offt = data->progress.ulspeed;
    267     break;
    268   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
    269     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
    270       data->progress.size_dl:-1;
    271     break;
    272   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
    273     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
    274       data->progress.size_ul:-1;
    275     break;
    276   default:
    277     return CURLE_UNKNOWN_OPTION;
    278   }
    279 
    280   return CURLE_OK;
    281 }
    282 
    283 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
    284                                double *param_doublep)
    285 {
    286   switch(info) {
    287   case CURLINFO_TOTAL_TIME:
    288     *param_doublep = DOUBLE_SECS(data->progress.timespent);
    289     break;
    290   case CURLINFO_NAMELOOKUP_TIME:
    291     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
    292     break;
    293   case CURLINFO_CONNECT_TIME:
    294     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
    295     break;
    296   case CURLINFO_APPCONNECT_TIME:
    297     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
    298     break;
    299   case CURLINFO_PRETRANSFER_TIME:
    300     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
    301     break;
    302   case CURLINFO_STARTTRANSFER_TIME:
    303     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
    304     break;
    305   case CURLINFO_SIZE_UPLOAD:
    306     *param_doublep =  (double)data->progress.uploaded;
    307     break;
    308   case CURLINFO_SIZE_DOWNLOAD:
    309     *param_doublep = (double)data->progress.downloaded;
    310     break;
    311   case CURLINFO_SPEED_DOWNLOAD:
    312     *param_doublep =  (double)data->progress.dlspeed;
    313     break;
    314   case CURLINFO_SPEED_UPLOAD:
    315     *param_doublep = (double)data->progress.ulspeed;
    316     break;
    317   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
    318     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
    319       (double)data->progress.size_dl:-1;
    320     break;
    321   case CURLINFO_CONTENT_LENGTH_UPLOAD:
    322     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
    323       (double)data->progress.size_ul:-1;
    324     break;
    325   case CURLINFO_REDIRECT_TIME:
    326     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
    327     break;
    328 
    329   default:
    330     return CURLE_UNKNOWN_OPTION;
    331   }
    332 
    333   return CURLE_OK;
    334 }
    335 
    336 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
    337                               struct curl_slist **param_slistp)
    338 {
    339   union {
    340     struct curl_certinfo *to_certinfo;
    341     struct curl_slist    *to_slist;
    342   } ptr;
    343 
    344   switch(info) {
    345   case CURLINFO_SSL_ENGINES:
    346     *param_slistp = Curl_ssl_engines_list(data);
    347     break;
    348   case CURLINFO_COOKIELIST:
    349     *param_slistp = Curl_cookie_list(data);
    350     break;
    351   case CURLINFO_CERTINFO:
    352     /* Return the a pointer to the certinfo struct. Not really an slist
    353        pointer but we can pretend it is here */
    354     ptr.to_certinfo = &data->info.certs;
    355     *param_slistp = ptr.to_slist;
    356     break;
    357   case CURLINFO_TLS_SESSION:
    358   case CURLINFO_TLS_SSL_PTR:
    359     {
    360       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
    361                                           param_slistp;
    362       struct curl_tlssessioninfo *tsi = &data->tsi;
    363 #ifdef USE_SSL
    364       struct connectdata *conn = data->easy_conn;
    365 #endif
    366 
    367       *tsip = tsi;
    368       tsi->backend = Curl_ssl_backend();
    369       tsi->internals = NULL;
    370 
    371 #ifdef USE_SSL
    372       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
    373         unsigned int i;
    374         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
    375           if(conn->ssl[i].use) {
    376             tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
    377             break;
    378           }
    379         }
    380       }
    381 #endif
    382     }
    383     break;
    384   default:
    385     return CURLE_UNKNOWN_OPTION;
    386   }
    387 
    388   return CURLE_OK;
    389 }
    390 
    391 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
    392                                curl_socket_t *param_socketp)
    393 {
    394   switch(info) {
    395   case CURLINFO_ACTIVESOCKET:
    396     *param_socketp = Curl_getconnectinfo(data, NULL);
    397     break;
    398   default:
    399     return CURLE_UNKNOWN_OPTION;
    400   }
    401 
    402   return CURLE_OK;
    403 }
    404 
    405 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
    406 {
    407   va_list arg;
    408   long *param_longp = NULL;
    409   double *param_doublep = NULL;
    410   curl_off_t *param_offt = NULL;
    411   const char **param_charp = NULL;
    412   struct curl_slist **param_slistp = NULL;
    413   curl_socket_t *param_socketp = NULL;
    414   int type;
    415   CURLcode result = CURLE_UNKNOWN_OPTION;
    416 
    417   if(!data)
    418     return result;
    419 
    420   va_start(arg, info);
    421 
    422   type = CURLINFO_TYPEMASK & (int)info;
    423   switch(type) {
    424   case CURLINFO_STRING:
    425     param_charp = va_arg(arg, const char **);
    426     if(param_charp)
    427       result = getinfo_char(data, info, param_charp);
    428     break;
    429   case CURLINFO_LONG:
    430     param_longp = va_arg(arg, long *);
    431     if(param_longp)
    432       result = getinfo_long(data, info, param_longp);
    433     break;
    434   case CURLINFO_DOUBLE:
    435     param_doublep = va_arg(arg, double *);
    436     if(param_doublep)
    437       result = getinfo_double(data, info, param_doublep);
    438     break;
    439   case CURLINFO_OFF_T:
    440     param_offt = va_arg(arg, curl_off_t *);
    441     if(param_offt)
    442       result = getinfo_offt(data, info, param_offt);
    443     break;
    444   case CURLINFO_SLIST:
    445     param_slistp = va_arg(arg, struct curl_slist **);
    446     if(param_slistp)
    447       result = getinfo_slist(data, info, param_slistp);
    448     break;
    449   case CURLINFO_SOCKET:
    450     param_socketp = va_arg(arg, curl_socket_t *);
    451     if(param_socketp)
    452       result = getinfo_socket(data, info, param_socketp);
    453     break;
    454   default:
    455     break;
    456   }
    457 
    458   va_end(arg);
    459 
    460   return result;
    461 }
    462