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