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