Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / getinfo.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, 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  */
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
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
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
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_REDIRECT_TIME_T:
413     *param_offt = data->progress.t_redirect;
414     break;
415   case CURLINFO_RETRY_AFTER:
416     *param_offt = data->info.retry_after;
417     break;
418   default:
419     return CURLE_UNKNOWN_OPTION;
420   }
421
422   return CURLE_OK;
423 }
424
425 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
426                                double *param_doublep)
427 {
428 #ifdef DEBUGBUILD
429   char *timestr = getenv("CURL_TIME");
430   if(timestr) {
431     unsigned long val = strtol(timestr, NULL, 10);
432     switch(info) {
433     case CURLINFO_TOTAL_TIME:
434     case CURLINFO_NAMELOOKUP_TIME:
435     case CURLINFO_CONNECT_TIME:
436     case CURLINFO_APPCONNECT_TIME:
437     case CURLINFO_PRETRANSFER_TIME:
438     case CURLINFO_STARTTRANSFER_TIME:
439     case CURLINFO_REDIRECT_TIME:
440     case CURLINFO_SPEED_DOWNLOAD:
441     case CURLINFO_SPEED_UPLOAD:
442       *param_doublep = (double)val;
443       return CURLE_OK;
444     default:
445       break;
446     }
447   }
448 #endif
449   switch(info) {
450   case CURLINFO_TOTAL_TIME:
451     *param_doublep = DOUBLE_SECS(data->progress.timespent);
452     break;
453   case CURLINFO_NAMELOOKUP_TIME:
454     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
455     break;
456   case CURLINFO_CONNECT_TIME:
457     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
458     break;
459   case CURLINFO_APPCONNECT_TIME:
460     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
461     break;
462   case CURLINFO_PRETRANSFER_TIME:
463     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
464     break;
465   case CURLINFO_STARTTRANSFER_TIME:
466     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
467     break;
468   case CURLINFO_SIZE_UPLOAD:
469     *param_doublep = (double)data->progress.uploaded;
470     break;
471   case CURLINFO_SIZE_DOWNLOAD:
472     *param_doublep = (double)data->progress.downloaded;
473     break;
474   case CURLINFO_SPEED_DOWNLOAD:
475     *param_doublep = (double)data->progress.dlspeed;
476     break;
477   case CURLINFO_SPEED_UPLOAD:
478     *param_doublep = (double)data->progress.ulspeed;
479     break;
480   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
481     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
482       (double)data->progress.size_dl:-1;
483     break;
484   case CURLINFO_CONTENT_LENGTH_UPLOAD:
485     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
486       (double)data->progress.size_ul:-1;
487     break;
488   case CURLINFO_REDIRECT_TIME:
489     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
490     break;
491
492   default:
493     return CURLE_UNKNOWN_OPTION;
494   }
495
496   return CURLE_OK;
497 }
498
499 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
500                               struct curl_slist **param_slistp)
501 {
502   union {
503     struct curl_certinfo *to_certinfo;
504     struct curl_slist    *to_slist;
505   } ptr;
506
507   switch(info) {
508   case CURLINFO_SSL_ENGINES:
509     *param_slistp = Curl_ssl_engines_list(data);
510     break;
511   case CURLINFO_COOKIELIST:
512     *param_slistp = Curl_cookie_list(data);
513     break;
514   case CURLINFO_CERTINFO:
515     /* Return the a pointer to the certinfo struct. Not really an slist
516        pointer but we can pretend it is here */
517     ptr.to_certinfo = &data->info.certs;
518     *param_slistp = ptr.to_slist;
519     break;
520   case CURLINFO_TLS_SESSION:
521   case CURLINFO_TLS_SSL_PTR:
522     {
523       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
524                                           param_slistp;
525       struct curl_tlssessioninfo *tsi = &data->tsi;
526 #ifdef USE_SSL
527       struct connectdata *conn = data->conn;
528 #endif
529
530       *tsip = tsi;
531       tsi->backend = Curl_ssl_backend();
532       tsi->internals = NULL;
533
534 #ifdef USE_SSL
535       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
536         unsigned int i;
537         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
538           if(conn->ssl[i].use) {
539             tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
540             break;
541           }
542         }
543       }
544 #endif
545     }
546     break;
547   default:
548     return CURLE_UNKNOWN_OPTION;
549   }
550
551   return CURLE_OK;
552 }
553
554 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
555                                curl_socket_t *param_socketp)
556 {
557   switch(info) {
558   case CURLINFO_ACTIVESOCKET:
559     *param_socketp = Curl_getconnectinfo(data, NULL);
560     break;
561   default:
562     return CURLE_UNKNOWN_OPTION;
563   }
564
565   return CURLE_OK;
566 }
567
568 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
569 {
570   va_list arg;
571   long *param_longp = NULL;
572   double *param_doublep = NULL;
573   curl_off_t *param_offt = NULL;
574   const char **param_charp = NULL;
575   struct curl_slist **param_slistp = NULL;
576   curl_socket_t *param_socketp = NULL;
577   int type;
578   CURLcode result = CURLE_UNKNOWN_OPTION;
579
580   if(!data)
581     return CURLE_BAD_FUNCTION_ARGUMENT;
582
583   va_start(arg, info);
584
585   type = CURLINFO_TYPEMASK & (int)info;
586   switch(type) {
587   case CURLINFO_STRING:
588     param_charp = va_arg(arg, const char **);
589     if(param_charp)
590       result = getinfo_char(data, info, param_charp);
591     break;
592   case CURLINFO_LONG:
593     param_longp = va_arg(arg, long *);
594     if(param_longp)
595       result = getinfo_long(data, info, param_longp);
596     break;
597   case CURLINFO_DOUBLE:
598     param_doublep = va_arg(arg, double *);
599     if(param_doublep)
600       result = getinfo_double(data, info, param_doublep);
601     break;
602   case CURLINFO_OFF_T:
603     param_offt = va_arg(arg, curl_off_t *);
604     if(param_offt)
605       result = getinfo_offt(data, info, param_offt);
606     break;
607   case CURLINFO_SLIST:
608     param_slistp = va_arg(arg, struct curl_slist **);
609     if(param_slistp)
610       result = getinfo_slist(data, info, param_slistp);
611     break;
612   case CURLINFO_SOCKET:
613     param_socketp = va_arg(arg, curl_socket_t *);
614     if(param_socketp)
615       result = getinfo_socket(data, info, param_socketp);
616     break;
617   default:
618     break;
619   }
620
621   va_end(arg);
622
623   return result;
624 }