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