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