• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #include <curl/curl.h>
28 
29 #include "urldata.h"
30 #include "getinfo.h"
31 
32 #include "vtls/vtls.h"
33 #include "connect.h" /* Curl_getconnectinfo() */
34 #include "progress.h"
35 
36 /* The last #include files should be: */
37 #include "curl_memory.h"
38 #include "memdebug.h"
39 
40 /*
41  * Initialize statistical and informational data.
42  *
43  * This function is called in curl_easy_reset, curl_easy_duphandle and at the
44  * beginning of a perform session. It must reset the session-info variables,
45  * in particular all variables in struct PureInfo.
46  */
Curl_initinfo(struct Curl_easy * data)47 CURLcode Curl_initinfo(struct Curl_easy *data)
48 {
49   struct Progress *pro = &data->progress;
50   struct PureInfo *info = &data->info;
51 
52   pro->t_nslookup = 0;
53   pro->t_connect = 0;
54   pro->t_appconnect = 0;
55   pro->t_pretransfer = 0;
56   pro->t_posttransfer = 0;
57   pro->t_starttransfer = 0;
58   pro->timespent = 0;
59   pro->t_redirect = 0;
60   pro->is_t_startransfer_set = FALSE;
61 
62   info->httpcode = 0;
63   info->httpproxycode = 0;
64   info->httpversion = 0;
65   info->filetime = -1; /* -1 is an illegal time and thus means unknown */
66   info->timecond = FALSE;
67 
68   info->header_size = 0;
69   info->request_size = 0;
70   info->proxyauthavail = 0;
71   info->httpauthavail = 0;
72   info->proxyauthpicked = 0;
73   info->httpauthpicked = 0;
74   info->numconnects = 0;
75 
76   free(info->contenttype);
77   info->contenttype = NULL;
78 
79   free(info->wouldredirect);
80   info->wouldredirect = NULL;
81 
82   memset(&info->primary, 0, sizeof(info->primary));
83   info->primary.remote_port = -1;
84   info->primary.local_port = -1;
85   info->retry_after = 0;
86 
87   info->conn_scheme = 0;
88   info->conn_protocol = 0;
89 
90 #ifdef USE_SSL
91   Curl_ssl_free_certinfo(data);
92 #endif
93   return CURLE_OK;
94 }
95 
getinfo_char(struct Curl_easy * data,CURLINFO info,const char ** param_charp)96 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
97                              const char **param_charp)
98 {
99   switch(info) {
100   case CURLINFO_EFFECTIVE_URL:
101     *param_charp = data->state.url ? data->state.url : (char *)"";
102     break;
103   case CURLINFO_EFFECTIVE_METHOD: {
104     const char *m = data->set.str[STRING_CUSTOMREQUEST];
105     if(!m) {
106       if(data->set.opt_no_body)
107         m = "HEAD";
108 #ifndef CURL_DISABLE_HTTP
109       else {
110         switch(data->state.httpreq) {
111         case HTTPREQ_POST:
112         case HTTPREQ_POST_FORM:
113         case HTTPREQ_POST_MIME:
114           m = "POST";
115           break;
116         case HTTPREQ_PUT:
117           m = "PUT";
118           break;
119         default: /* this should never happen */
120         case HTTPREQ_GET:
121           m = "GET";
122           break;
123         case HTTPREQ_HEAD:
124           m = "HEAD";
125           break;
126         }
127       }
128 #endif
129     }
130     *param_charp = m;
131   }
132     break;
133   case CURLINFO_CONTENT_TYPE:
134     *param_charp = data->info.contenttype;
135     break;
136   case CURLINFO_PRIVATE:
137     *param_charp = (char *) data->set.private_data;
138     break;
139   case CURLINFO_FTP_ENTRY_PATH:
140     /* Return the entrypath string from the most recent connection.
141        This pointer was copied from the connectdata structure by FTP.
142        The actual string may be free()ed by subsequent libcurl calls so
143        it must be copied to a safer area before the next libcurl call.
144        Callers must never free it themselves. */
145     *param_charp = data->state.most_recent_ftp_entrypath;
146     break;
147   case CURLINFO_REDIRECT_URL:
148     /* Return the URL this request would have been redirected to if that
149        option had been enabled! */
150     *param_charp = data->info.wouldredirect;
151     break;
152   case CURLINFO_REFERER:
153     /* Return the referrer header for this request, or NULL if unset */
154     *param_charp = data->state.referer;
155     break;
156   case CURLINFO_PRIMARY_IP:
157     /* Return the ip address of the most recent (primary) connection */
158     *param_charp = data->info.primary.remote_ip;
159     break;
160   case CURLINFO_LOCAL_IP:
161     /* Return the source/local ip address of the most recent (primary)
162        connection */
163     *param_charp = data->info.primary.local_ip;
164     break;
165   case CURLINFO_RTSP_SESSION_ID:
166 #ifndef CURL_DISABLE_RTSP
167     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
168 #else
169     *param_charp = NULL;
170 #endif
171     break;
172   case CURLINFO_SCHEME:
173     *param_charp = data->info.conn_scheme;
174     break;
175   case CURLINFO_CAPATH:
176 #ifdef CURL_CA_PATH
177     *param_charp = CURL_CA_PATH;
178 #else
179     *param_charp = NULL;
180 #endif
181     break;
182   case CURLINFO_CAINFO:
183 #ifdef CURL_CA_BUNDLE
184     *param_charp = CURL_CA_BUNDLE;
185 #else
186     *param_charp = NULL;
187 #endif
188     break;
189   default:
190     return CURLE_UNKNOWN_OPTION;
191   }
192 
193   return CURLE_OK;
194 }
195 
getinfo_long(struct Curl_easy * data,CURLINFO info,long * param_longp)196 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
197                              long *param_longp)
198 {
199   curl_socket_t sockfd;
200 
201   union {
202     unsigned long *to_ulong;
203     long          *to_long;
204   } lptr;
205 
206 #ifdef DEBUGBUILD
207   char *timestr = getenv("CURL_TIME");
208   if(timestr) {
209     unsigned long val = strtoul(timestr, NULL, 10);
210     switch(info) {
211     case CURLINFO_LOCAL_PORT:
212       *param_longp = (long)val;
213       return CURLE_OK;
214     default:
215       break;
216     }
217   }
218   /* use another variable for this to allow different values */
219   timestr = getenv("CURL_DEBUG_SIZE");
220   if(timestr) {
221     unsigned long val = strtoul(timestr, NULL, 10);
222     switch(info) {
223     case CURLINFO_HEADER_SIZE:
224     case CURLINFO_REQUEST_SIZE:
225       *param_longp = (long)val;
226       return CURLE_OK;
227     default:
228       break;
229     }
230   }
231 #endif
232 
233   switch(info) {
234   case CURLINFO_RESPONSE_CODE:
235     *param_longp = data->info.httpcode;
236     break;
237   case CURLINFO_HTTP_CONNECTCODE:
238     *param_longp = data->info.httpproxycode;
239     break;
240   case CURLINFO_FILETIME:
241     if(data->info.filetime > LONG_MAX)
242       *param_longp = LONG_MAX;
243 #if !defined(MSDOS) && !defined(__AMIGA__)
244     else if(data->info.filetime < LONG_MIN)
245       *param_longp = LONG_MIN;
246 #endif
247     else
248       *param_longp = (long)data->info.filetime;
249     break;
250   case CURLINFO_HEADER_SIZE:
251     *param_longp = (long)data->info.header_size;
252     break;
253   case CURLINFO_REQUEST_SIZE:
254     *param_longp = (long)data->info.request_size;
255     break;
256   case CURLINFO_SSL_VERIFYRESULT:
257     *param_longp = data->set.ssl.certverifyresult;
258     break;
259   case CURLINFO_PROXY_SSL_VERIFYRESULT:
260 #ifndef CURL_DISABLE_PROXY
261     *param_longp = data->set.proxy_ssl.certverifyresult;
262 #else
263     *param_longp = 0;
264 #endif
265     break;
266   case CURLINFO_REDIRECT_COUNT:
267     *param_longp = data->state.followlocation;
268     break;
269   case CURLINFO_HTTPAUTH_AVAIL:
270     lptr.to_long = param_longp;
271     *lptr.to_ulong = data->info.httpauthavail;
272     break;
273   case CURLINFO_PROXYAUTH_AVAIL:
274     lptr.to_long = param_longp;
275     *lptr.to_ulong = data->info.proxyauthavail;
276     break;
277   case CURLINFO_HTTPAUTH_USED:
278     lptr.to_long = param_longp;
279     *lptr.to_ulong = data->info.httpauthpicked;
280     break;
281   case CURLINFO_PROXYAUTH_USED:
282     lptr.to_long = param_longp;
283     *lptr.to_ulong = data->info.proxyauthpicked;
284     break;
285   case CURLINFO_OS_ERRNO:
286     *param_longp = data->state.os_errno;
287     break;
288   case CURLINFO_NUM_CONNECTS:
289     *param_longp = data->info.numconnects;
290     break;
291   case CURLINFO_LASTSOCKET:
292     sockfd = Curl_getconnectinfo(data, NULL);
293 
294     /* note: this is not a good conversion for systems with 64-bit sockets and
295        32-bit longs */
296     if(sockfd != CURL_SOCKET_BAD)
297       *param_longp = (long)sockfd;
298     else
299       /* this interface is documented to return -1 in case of badness, which
300          may not be the same as the CURL_SOCKET_BAD value */
301       *param_longp = -1;
302     break;
303   case CURLINFO_PRIMARY_PORT:
304     /* Return the (remote) port of the most recent (primary) connection */
305     *param_longp = data->info.primary.remote_port;
306     break;
307   case CURLINFO_LOCAL_PORT:
308     /* Return the local port of the most recent (primary) connection */
309     *param_longp = data->info.primary.local_port;
310     break;
311   case CURLINFO_PROXY_ERROR:
312     *param_longp = (long)data->info.pxcode;
313     break;
314   case CURLINFO_CONDITION_UNMET:
315     if(data->info.httpcode == 304)
316       *param_longp = 1L;
317     else
318       /* return if the condition prevented the document to get transferred */
319       *param_longp = data->info.timecond ? 1L : 0L;
320     break;
321 #ifndef CURL_DISABLE_RTSP
322   case CURLINFO_RTSP_CLIENT_CSEQ:
323     *param_longp = data->state.rtsp_next_client_CSeq;
324     break;
325   case CURLINFO_RTSP_SERVER_CSEQ:
326     *param_longp = data->state.rtsp_next_server_CSeq;
327     break;
328   case CURLINFO_RTSP_CSEQ_RECV:
329     *param_longp = data->state.rtsp_CSeq_recv;
330     break;
331 #else
332   case CURLINFO_RTSP_CLIENT_CSEQ:
333   case CURLINFO_RTSP_SERVER_CSEQ:
334   case CURLINFO_RTSP_CSEQ_RECV:
335     *param_longp = 0;
336     break;
337 #endif
338   case CURLINFO_HTTP_VERSION:
339     switch(data->info.httpversion) {
340     case 10:
341       *param_longp = CURL_HTTP_VERSION_1_0;
342       break;
343     case 11:
344       *param_longp = CURL_HTTP_VERSION_1_1;
345       break;
346     case 20:
347       *param_longp = CURL_HTTP_VERSION_2_0;
348       break;
349     case 30:
350       *param_longp = CURL_HTTP_VERSION_3;
351       break;
352     default:
353       *param_longp = CURL_HTTP_VERSION_NONE;
354       break;
355     }
356     break;
357   case CURLINFO_PROTOCOL:
358     *param_longp = (long)data->info.conn_protocol;
359     break;
360   case CURLINFO_USED_PROXY:
361     *param_longp =
362 #ifdef CURL_DISABLE_PROXY
363       0
364 #else
365       data->info.used_proxy
366 #endif
367       ;
368     break;
369   default:
370     return CURLE_UNKNOWN_OPTION;
371   }
372 
373   return CURLE_OK;
374 }
375 
376 #define DOUBLE_SECS(x) (double)(x)/1000000
377 
getinfo_offt(struct Curl_easy * data,CURLINFO info,curl_off_t * param_offt)378 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
379                              curl_off_t *param_offt)
380 {
381 #ifdef DEBUGBUILD
382   char *timestr = getenv("CURL_TIME");
383   if(timestr) {
384     unsigned long val = strtoul(timestr, NULL, 10);
385     switch(info) {
386     case CURLINFO_TOTAL_TIME_T:
387     case CURLINFO_NAMELOOKUP_TIME_T:
388     case CURLINFO_CONNECT_TIME_T:
389     case CURLINFO_APPCONNECT_TIME_T:
390     case CURLINFO_PRETRANSFER_TIME_T:
391     case CURLINFO_POSTTRANSFER_TIME_T:
392     case CURLINFO_QUEUE_TIME_T:
393     case CURLINFO_STARTTRANSFER_TIME_T:
394     case CURLINFO_REDIRECT_TIME_T:
395     case CURLINFO_SPEED_DOWNLOAD_T:
396     case CURLINFO_SPEED_UPLOAD_T:
397       *param_offt = (curl_off_t)val;
398       return CURLE_OK;
399     default:
400       break;
401     }
402   }
403 #endif
404   switch(info) {
405   case CURLINFO_FILETIME_T:
406     *param_offt = (curl_off_t)data->info.filetime;
407     break;
408   case CURLINFO_SIZE_UPLOAD_T:
409     *param_offt = data->progress.ul.cur_size;
410     break;
411   case CURLINFO_SIZE_DOWNLOAD_T:
412     *param_offt = data->progress.dl.cur_size;
413     break;
414   case CURLINFO_SPEED_DOWNLOAD_T:
415     *param_offt = data->progress.dl.speed;
416     break;
417   case CURLINFO_SPEED_UPLOAD_T:
418     *param_offt = data->progress.ul.speed;
419     break;
420   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
421     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN) ?
422       data->progress.dl.total_size : -1;
423     break;
424   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
425     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN) ?
426       data->progress.ul.total_size : -1;
427     break;
428    case CURLINFO_TOTAL_TIME_T:
429     *param_offt = data->progress.timespent;
430     break;
431   case CURLINFO_NAMELOOKUP_TIME_T:
432     *param_offt = data->progress.t_nslookup;
433     break;
434   case CURLINFO_CONNECT_TIME_T:
435     *param_offt = data->progress.t_connect;
436     break;
437   case CURLINFO_APPCONNECT_TIME_T:
438     *param_offt = data->progress.t_appconnect;
439     break;
440   case CURLINFO_PRETRANSFER_TIME_T:
441     *param_offt = data->progress.t_pretransfer;
442     break;
443   case CURLINFO_POSTTRANSFER_TIME_T:
444     *param_offt = data->progress.t_posttransfer;
445     break;
446   case CURLINFO_STARTTRANSFER_TIME_T:
447     *param_offt = data->progress.t_starttransfer;
448     break;
449   case CURLINFO_QUEUE_TIME_T:
450     *param_offt = data->progress.t_postqueue;
451     break;
452   case CURLINFO_REDIRECT_TIME_T:
453     *param_offt = data->progress.t_redirect;
454     break;
455   case CURLINFO_RETRY_AFTER:
456     *param_offt = data->info.retry_after;
457     break;
458   case CURLINFO_XFER_ID:
459     *param_offt = data->id;
460     break;
461   case CURLINFO_CONN_ID:
462     *param_offt = data->conn ?
463       data->conn->connection_id : data->state.recent_conn_id;
464     break;
465   case CURLINFO_EARLYDATA_SENT_T:
466     *param_offt = data->progress.earlydata_sent;
467     break;
468   default:
469     return CURLE_UNKNOWN_OPTION;
470   }
471 
472   return CURLE_OK;
473 }
474 
getinfo_double(struct Curl_easy * data,CURLINFO info,double * param_doublep)475 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
476                                double *param_doublep)
477 {
478 #ifdef DEBUGBUILD
479   char *timestr = getenv("CURL_TIME");
480   if(timestr) {
481     unsigned long val = strtoul(timestr, NULL, 10);
482     switch(info) {
483     case CURLINFO_TOTAL_TIME:
484     case CURLINFO_NAMELOOKUP_TIME:
485     case CURLINFO_CONNECT_TIME:
486     case CURLINFO_APPCONNECT_TIME:
487     case CURLINFO_PRETRANSFER_TIME:
488     case CURLINFO_STARTTRANSFER_TIME:
489     case CURLINFO_REDIRECT_TIME:
490     case CURLINFO_SPEED_DOWNLOAD:
491     case CURLINFO_SPEED_UPLOAD:
492       *param_doublep = (double)val;
493       return CURLE_OK;
494     default:
495       break;
496     }
497   }
498 #endif
499   switch(info) {
500   case CURLINFO_TOTAL_TIME:
501     *param_doublep = DOUBLE_SECS(data->progress.timespent);
502     break;
503   case CURLINFO_NAMELOOKUP_TIME:
504     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
505     break;
506   case CURLINFO_CONNECT_TIME:
507     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
508     break;
509   case CURLINFO_APPCONNECT_TIME:
510     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
511     break;
512   case CURLINFO_PRETRANSFER_TIME:
513     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
514     break;
515   case CURLINFO_STARTTRANSFER_TIME:
516     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
517     break;
518   case CURLINFO_SIZE_UPLOAD:
519     *param_doublep = (double)data->progress.ul.cur_size;
520     break;
521   case CURLINFO_SIZE_DOWNLOAD:
522     *param_doublep = (double)data->progress.dl.cur_size;
523     break;
524   case CURLINFO_SPEED_DOWNLOAD:
525     *param_doublep = (double)data->progress.dl.speed;
526     break;
527   case CURLINFO_SPEED_UPLOAD:
528     *param_doublep = (double)data->progress.ul.speed;
529     break;
530   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
531     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN) ?
532       (double)data->progress.dl.total_size : -1;
533     break;
534   case CURLINFO_CONTENT_LENGTH_UPLOAD:
535     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN) ?
536       (double)data->progress.ul.total_size : -1;
537     break;
538   case CURLINFO_REDIRECT_TIME:
539     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
540     break;
541 
542   default:
543     return CURLE_UNKNOWN_OPTION;
544   }
545 
546   return CURLE_OK;
547 }
548 
getinfo_slist(struct Curl_easy * data,CURLINFO info,struct curl_slist ** param_slistp)549 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
550                               struct curl_slist **param_slistp)
551 {
552   union {
553     struct curl_certinfo *to_certinfo;
554     struct curl_slist    *to_slist;
555   } ptr;
556 
557   switch(info) {
558   case CURLINFO_SSL_ENGINES:
559     *param_slistp = Curl_ssl_engines_list(data);
560     break;
561   case CURLINFO_COOKIELIST:
562     *param_slistp = Curl_cookie_list(data);
563     break;
564   case CURLINFO_CERTINFO:
565     /* Return the a pointer to the certinfo struct. Not really an slist
566        pointer but we can pretend it is here */
567     ptr.to_certinfo = &data->info.certs;
568     *param_slistp = ptr.to_slist;
569     break;
570   case CURLINFO_TLS_SESSION:
571   case CURLINFO_TLS_SSL_PTR:
572     {
573       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
574                                           param_slistp;
575       struct curl_tlssessioninfo *tsi = &data->tsi;
576 #ifdef USE_SSL
577       struct connectdata *conn = data->conn;
578 #endif
579 
580       *tsip = tsi;
581       tsi->backend = Curl_ssl_backend();
582       tsi->internals = NULL;
583 
584 #ifdef USE_SSL
585       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
586         tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
587       }
588 #endif
589     }
590     break;
591   default:
592     return CURLE_UNKNOWN_OPTION;
593   }
594 
595   return CURLE_OK;
596 }
597 
getinfo_socket(struct Curl_easy * data,CURLINFO info,curl_socket_t * param_socketp)598 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
599                                curl_socket_t *param_socketp)
600 {
601   switch(info) {
602   case CURLINFO_ACTIVESOCKET:
603     *param_socketp = Curl_getconnectinfo(data, NULL);
604     break;
605   default:
606     return CURLE_UNKNOWN_OPTION;
607   }
608 
609   return CURLE_OK;
610 }
611 
Curl_getinfo(struct Curl_easy * data,CURLINFO info,...)612 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
613 {
614   va_list arg;
615   long *param_longp = NULL;
616   double *param_doublep = NULL;
617   curl_off_t *param_offt = NULL;
618   const char **param_charp = NULL;
619   struct curl_slist **param_slistp = NULL;
620   curl_socket_t *param_socketp = NULL;
621   int type;
622   CURLcode result = CURLE_UNKNOWN_OPTION;
623 
624   if(!data)
625     return CURLE_BAD_FUNCTION_ARGUMENT;
626 
627   va_start(arg, info);
628 
629   type = CURLINFO_TYPEMASK & (int)info;
630   switch(type) {
631   case CURLINFO_STRING:
632     param_charp = va_arg(arg, const char **);
633     if(param_charp)
634       result = getinfo_char(data, info, param_charp);
635     break;
636   case CURLINFO_LONG:
637     param_longp = va_arg(arg, long *);
638     if(param_longp)
639       result = getinfo_long(data, info, param_longp);
640     break;
641   case CURLINFO_DOUBLE:
642     param_doublep = va_arg(arg, double *);
643     if(param_doublep)
644       result = getinfo_double(data, info, param_doublep);
645     break;
646   case CURLINFO_OFF_T:
647     param_offt = va_arg(arg, curl_off_t *);
648     if(param_offt)
649       result = getinfo_offt(data, info, param_offt);
650     break;
651   case CURLINFO_SLIST:
652     param_slistp = va_arg(arg, struct curl_slist **);
653     if(param_slistp)
654       result = getinfo_slist(data, info, param_slistp);
655     break;
656   case CURLINFO_SOCKET:
657     param_socketp = va_arg(arg, curl_socket_t *);
658     if(param_socketp)
659       result = getinfo_socket(data, info, param_socketp);
660     break;
661   default:
662     break;
663   }
664 
665   va_end(arg);
666 
667   return result;
668 }
669