• 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     case 30:
239       *param_longp = CURL_HTTP_VERSION_3;
240       break;
241     default:
242       *param_longp = CURL_HTTP_VERSION_NONE;
243       break;
244     }
245     break;
246   case CURLINFO_PROTOCOL:
247     *param_longp = data->info.conn_protocol;
248     break;
249   default:
250     return CURLE_UNKNOWN_OPTION;
251   }
252 
253   return CURLE_OK;
254 }
255 
256 #define DOUBLE_SECS(x) (double)(x)/1000000
257 
getinfo_offt(struct Curl_easy * data,CURLINFO info,curl_off_t * param_offt)258 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
259                              curl_off_t *param_offt)
260 {
261   switch(info) {
262   case CURLINFO_FILETIME_T:
263     *param_offt = (curl_off_t)data->info.filetime;
264     break;
265   case CURLINFO_SIZE_UPLOAD_T:
266     *param_offt = data->progress.uploaded;
267     break;
268   case CURLINFO_SIZE_DOWNLOAD_T:
269     *param_offt = data->progress.downloaded;
270     break;
271   case CURLINFO_SPEED_DOWNLOAD_T:
272     *param_offt =  data->progress.dlspeed;
273     break;
274   case CURLINFO_SPEED_UPLOAD_T:
275     *param_offt = data->progress.ulspeed;
276     break;
277   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
278     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
279       data->progress.size_dl:-1;
280     break;
281   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
282     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
283       data->progress.size_ul:-1;
284     break;
285   case CURLINFO_TOTAL_TIME_T:
286     *param_offt = data->progress.timespent;
287     break;
288   case CURLINFO_NAMELOOKUP_TIME_T:
289     *param_offt = data->progress.t_nslookup;
290     break;
291   case CURLINFO_CONNECT_TIME_T:
292     *param_offt = data->progress.t_connect;
293     break;
294   case CURLINFO_APPCONNECT_TIME_T:
295     *param_offt = data->progress.t_appconnect;
296     break;
297   case CURLINFO_PRETRANSFER_TIME_T:
298     *param_offt = data->progress.t_pretransfer;
299     break;
300   case CURLINFO_STARTTRANSFER_TIME_T:
301     *param_offt = data->progress.t_starttransfer;
302     break;
303   case CURLINFO_REDIRECT_TIME_T:
304     *param_offt = data->progress.t_redirect;
305     break;
306   case CURLINFO_RETRY_AFTER:
307     *param_offt = data->info.retry_after;
308     break;
309   default:
310     return CURLE_UNKNOWN_OPTION;
311   }
312 
313   return CURLE_OK;
314 }
315 
getinfo_double(struct Curl_easy * data,CURLINFO info,double * param_doublep)316 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
317                                double *param_doublep)
318 {
319   switch(info) {
320   case CURLINFO_TOTAL_TIME:
321     *param_doublep = DOUBLE_SECS(data->progress.timespent);
322     break;
323   case CURLINFO_NAMELOOKUP_TIME:
324     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
325     break;
326   case CURLINFO_CONNECT_TIME:
327     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
328     break;
329   case CURLINFO_APPCONNECT_TIME:
330     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
331     break;
332   case CURLINFO_PRETRANSFER_TIME:
333     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
334     break;
335   case CURLINFO_STARTTRANSFER_TIME:
336     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
337     break;
338   case CURLINFO_SIZE_UPLOAD:
339     *param_doublep =  (double)data->progress.uploaded;
340     break;
341   case CURLINFO_SIZE_DOWNLOAD:
342     *param_doublep = (double)data->progress.downloaded;
343     break;
344   case CURLINFO_SPEED_DOWNLOAD:
345     *param_doublep =  (double)data->progress.dlspeed;
346     break;
347   case CURLINFO_SPEED_UPLOAD:
348     *param_doublep = (double)data->progress.ulspeed;
349     break;
350   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
351     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
352       (double)data->progress.size_dl:-1;
353     break;
354   case CURLINFO_CONTENT_LENGTH_UPLOAD:
355     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
356       (double)data->progress.size_ul:-1;
357     break;
358   case CURLINFO_REDIRECT_TIME:
359     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
360     break;
361 
362   default:
363     return CURLE_UNKNOWN_OPTION;
364   }
365 
366   return CURLE_OK;
367 }
368 
getinfo_slist(struct Curl_easy * data,CURLINFO info,struct curl_slist ** param_slistp)369 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
370                               struct curl_slist **param_slistp)
371 {
372   union {
373     struct curl_certinfo *to_certinfo;
374     struct curl_slist    *to_slist;
375   } ptr;
376 
377   switch(info) {
378   case CURLINFO_SSL_ENGINES:
379     *param_slistp = Curl_ssl_engines_list(data);
380     break;
381   case CURLINFO_COOKIELIST:
382     *param_slistp = Curl_cookie_list(data);
383     break;
384   case CURLINFO_CERTINFO:
385     /* Return the a pointer to the certinfo struct. Not really an slist
386        pointer but we can pretend it is here */
387     ptr.to_certinfo = &data->info.certs;
388     *param_slistp = ptr.to_slist;
389     break;
390   case CURLINFO_TLS_SESSION:
391   case CURLINFO_TLS_SSL_PTR:
392     {
393       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
394                                           param_slistp;
395       struct curl_tlssessioninfo *tsi = &data->tsi;
396 #ifdef USE_SSL
397       struct connectdata *conn = data->conn;
398 #endif
399 
400       *tsip = tsi;
401       tsi->backend = Curl_ssl_backend();
402       tsi->internals = NULL;
403 
404 #ifdef USE_SSL
405       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
406         unsigned int i;
407         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
408           if(conn->ssl[i].use) {
409             tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
410             break;
411           }
412         }
413       }
414 #endif
415     }
416     break;
417   default:
418     return CURLE_UNKNOWN_OPTION;
419   }
420 
421   return CURLE_OK;
422 }
423 
getinfo_socket(struct Curl_easy * data,CURLINFO info,curl_socket_t * param_socketp)424 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
425                                curl_socket_t *param_socketp)
426 {
427   switch(info) {
428   case CURLINFO_ACTIVESOCKET:
429     *param_socketp = Curl_getconnectinfo(data, NULL);
430     break;
431   default:
432     return CURLE_UNKNOWN_OPTION;
433   }
434 
435   return CURLE_OK;
436 }
437 
Curl_getinfo(struct Curl_easy * data,CURLINFO info,...)438 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
439 {
440   va_list arg;
441   long *param_longp = NULL;
442   double *param_doublep = NULL;
443   curl_off_t *param_offt = NULL;
444   const char **param_charp = NULL;
445   struct curl_slist **param_slistp = NULL;
446   curl_socket_t *param_socketp = NULL;
447   int type;
448   CURLcode result = CURLE_UNKNOWN_OPTION;
449 
450   if(!data)
451     return result;
452 
453   va_start(arg, info);
454 
455   type = CURLINFO_TYPEMASK & (int)info;
456   switch(type) {
457   case CURLINFO_STRING:
458     param_charp = va_arg(arg, const char **);
459     if(param_charp)
460       result = getinfo_char(data, info, param_charp);
461     break;
462   case CURLINFO_LONG:
463     param_longp = va_arg(arg, long *);
464     if(param_longp)
465       result = getinfo_long(data, info, param_longp);
466     break;
467   case CURLINFO_DOUBLE:
468     param_doublep = va_arg(arg, double *);
469     if(param_doublep)
470       result = getinfo_double(data, info, param_doublep);
471     break;
472   case CURLINFO_OFF_T:
473     param_offt = va_arg(arg, curl_off_t *);
474     if(param_offt)
475       result = getinfo_offt(data, info, param_offt);
476     break;
477   case CURLINFO_SLIST:
478     param_slistp = va_arg(arg, struct curl_slist **);
479     if(param_slistp)
480       result = getinfo_slist(data, info, param_slistp);
481     break;
482   case CURLINFO_SOCKET:
483     param_socketp = va_arg(arg, curl_socket_t *);
484     if(param_socketp)
485       result = getinfo_socket(data, info, param_socketp);
486     break;
487   default:
488     break;
489   }
490 
491   va_end(arg);
492 
493   return result;
494 }
495