1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
27 #include <curl/curl.h>
32 #include "vtls/vtls.h"
33 #include "connect.h" /* Curl_getconnectinfo() */
36 /* The last #include files should be: */
37 #include "curl_memory.h"
41 * Initialize statistical and informational data.
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.
47 CURLcode Curl_initinfo(struct Curl_easy *data)
49 struct Progress *pro = &data->progress;
50 struct PureInfo *info = &data->info;
54 pro->t_appconnect = 0;
55 pro->t_pretransfer = 0;
56 pro->t_starttransfer = 0;
59 pro->is_t_startransfer_set = false;
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;
67 info->header_size = 0;
68 info->request_size = 0;
69 info->proxyauthavail = 0;
70 info->httpauthavail = 0;
71 info->numconnects = 0;
73 free(info->contenttype);
74 info->contenttype = NULL;
76 free(info->wouldredirect);
77 info->wouldredirect = NULL;
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;
85 info->conn_scheme = 0;
86 info->conn_protocol = 0;
89 Curl_ssl_free_certinfo(data);
94 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
95 const char **param_charp)
98 case CURLINFO_EFFECTIVE_URL:
99 *param_charp = data->state.url?data->state.url:(char *)"";
101 case CURLINFO_EFFECTIVE_METHOD: {
102 const char *m = data->set.str[STRING_CUSTOMREQUEST];
104 if(data->set.opt_no_body)
106 #ifndef CURL_DISABLE_HTTP
108 switch(data->state.httpreq) {
110 case HTTPREQ_POST_FORM:
111 case HTTPREQ_POST_MIME:
117 default: /* this should never happen */
131 case CURLINFO_CONTENT_TYPE:
132 *param_charp = data->info.contenttype;
134 case CURLINFO_PRIVATE:
135 *param_charp = (char *) data->set.private_data;
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;
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;
150 case CURLINFO_REFERER:
151 /* Return the referrer header for this request, or NULL if unset */
152 *param_charp = data->state.referer;
154 case CURLINFO_PRIMARY_IP:
155 /* Return the ip address of the most recent (primary) connection */
156 *param_charp = data->info.conn_primary_ip;
158 case CURLINFO_LOCAL_IP:
159 /* Return the source/local ip address of the most recent (primary)
161 *param_charp = data->info.conn_local_ip;
163 case CURLINFO_RTSP_SESSION_ID:
164 *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
166 case CURLINFO_SCHEME:
167 *param_charp = data->info.conn_scheme;
169 case CURLINFO_CAPATH:
171 *param_charp = CURL_CA_PATH;
176 case CURLINFO_CAINFO:
177 #ifdef CURL_CA_BUNDLE
178 *param_charp = CURL_CA_BUNDLE;
185 return CURLE_UNKNOWN_OPTION;
191 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
194 curl_socket_t sockfd;
197 unsigned long *to_ulong;
202 char *timestr = getenv("CURL_TIME");
204 unsigned long val = strtol(timestr, NULL, 10);
206 case CURLINFO_LOCAL_PORT:
207 *param_longp = (long)val;
213 /* use another variable for this to allow different values */
214 timestr = getenv("CURL_DEBUG_SIZE");
216 unsigned long val = strtol(timestr, NULL, 10);
218 case CURLINFO_HEADER_SIZE:
219 case CURLINFO_REQUEST_SIZE:
220 *param_longp = (long)val;
229 case CURLINFO_RESPONSE_CODE:
230 *param_longp = data->info.httpcode;
232 case CURLINFO_HTTP_CONNECTCODE:
233 *param_longp = data->info.httpproxycode;
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;
241 *param_longp = (long)data->info.filetime;
243 case CURLINFO_HEADER_SIZE:
244 *param_longp = (long)data->info.header_size;
246 case CURLINFO_REQUEST_SIZE:
247 *param_longp = (long)data->info.request_size;
249 case CURLINFO_SSL_VERIFYRESULT:
250 *param_longp = data->set.ssl.certverifyresult;
252 #ifndef CURL_DISABLE_PROXY
253 case CURLINFO_PROXY_SSL_VERIFYRESULT:
254 *param_longp = data->set.proxy_ssl.certverifyresult;
257 case CURLINFO_REDIRECT_COUNT:
258 *param_longp = data->state.followlocation;
260 case CURLINFO_HTTPAUTH_AVAIL:
261 lptr.to_long = param_longp;
262 *lptr.to_ulong = data->info.httpauthavail;
264 case CURLINFO_PROXYAUTH_AVAIL:
265 lptr.to_long = param_longp;
266 *lptr.to_ulong = data->info.proxyauthavail;
268 case CURLINFO_OS_ERRNO:
269 *param_longp = data->state.os_errno;
271 case CURLINFO_NUM_CONNECTS:
272 *param_longp = data->info.numconnects;
274 case CURLINFO_LASTSOCKET:
275 sockfd = Curl_getconnectinfo(data, NULL);
277 /* note: this is not a good conversion for systems with 64 bit sockets and
279 if(sockfd != CURL_SOCKET_BAD)
280 *param_longp = (long)sockfd;
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 */
286 case CURLINFO_PRIMARY_PORT:
287 /* Return the (remote) port of the most recent (primary) connection */
288 *param_longp = data->info.conn_primary_port;
290 case CURLINFO_LOCAL_PORT:
291 /* Return the local port of the most recent (primary) connection */
292 *param_longp = data->info.conn_local_port;
294 case CURLINFO_PROXY_ERROR:
295 *param_longp = (long)data->info.pxcode;
297 case CURLINFO_CONDITION_UNMET:
298 if(data->info.httpcode == 304)
301 /* return if the condition prevented the document to get transferred */
302 *param_longp = data->info.timecond ? 1L : 0L;
304 #ifndef CURL_DISABLE_RTSP
305 case CURLINFO_RTSP_CLIENT_CSEQ:
306 *param_longp = data->state.rtsp_next_client_CSeq;
308 case CURLINFO_RTSP_SERVER_CSEQ:
309 *param_longp = data->state.rtsp_next_server_CSeq;
311 case CURLINFO_RTSP_CSEQ_RECV:
312 *param_longp = data->state.rtsp_CSeq_recv;
315 case CURLINFO_HTTP_VERSION:
316 switch(data->info.httpversion) {
318 *param_longp = CURL_HTTP_VERSION_1_0;
321 *param_longp = CURL_HTTP_VERSION_1_1;
324 *param_longp = CURL_HTTP_VERSION_2_0;
327 *param_longp = CURL_HTTP_VERSION_3;
330 *param_longp = CURL_HTTP_VERSION_NONE;
334 case CURLINFO_PROTOCOL:
335 *param_longp = data->info.conn_protocol;
338 return CURLE_UNKNOWN_OPTION;
344 #define DOUBLE_SECS(x) (double)(x)/1000000
346 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
347 curl_off_t *param_offt)
350 char *timestr = getenv("CURL_TIME");
352 unsigned long val = strtol(timestr, NULL, 10);
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;
371 case CURLINFO_FILETIME_T:
372 *param_offt = (curl_off_t)data->info.filetime;
374 case CURLINFO_SIZE_UPLOAD_T:
375 *param_offt = data->progress.uploaded;
377 case CURLINFO_SIZE_DOWNLOAD_T:
378 *param_offt = data->progress.downloaded;
380 case CURLINFO_SPEED_DOWNLOAD_T:
381 *param_offt = data->progress.dlspeed;
383 case CURLINFO_SPEED_UPLOAD_T:
384 *param_offt = data->progress.ulspeed;
386 case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
387 *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
388 data->progress.size_dl:-1;
390 case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
391 *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
392 data->progress.size_ul:-1;
394 case CURLINFO_TOTAL_TIME_T:
395 *param_offt = data->progress.timespent;
397 case CURLINFO_NAMELOOKUP_TIME_T:
398 *param_offt = data->progress.t_nslookup;
400 case CURLINFO_CONNECT_TIME_T:
401 *param_offt = data->progress.t_connect;
403 case CURLINFO_APPCONNECT_TIME_T:
404 *param_offt = data->progress.t_appconnect;
406 case CURLINFO_PRETRANSFER_TIME_T:
407 *param_offt = data->progress.t_pretransfer;
409 case CURLINFO_STARTTRANSFER_TIME_T:
410 *param_offt = data->progress.t_starttransfer;
412 case CURLINFO_REDIRECT_TIME_T:
413 *param_offt = data->progress.t_redirect;
415 case CURLINFO_RETRY_AFTER:
416 *param_offt = data->info.retry_after;
419 return CURLE_UNKNOWN_OPTION;
425 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
426 double *param_doublep)
429 char *timestr = getenv("CURL_TIME");
431 unsigned long val = strtol(timestr, NULL, 10);
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;
450 case CURLINFO_TOTAL_TIME:
451 *param_doublep = DOUBLE_SECS(data->progress.timespent);
453 case CURLINFO_NAMELOOKUP_TIME:
454 *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
456 case CURLINFO_CONNECT_TIME:
457 *param_doublep = DOUBLE_SECS(data->progress.t_connect);
459 case CURLINFO_APPCONNECT_TIME:
460 *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
462 case CURLINFO_PRETRANSFER_TIME:
463 *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
465 case CURLINFO_STARTTRANSFER_TIME:
466 *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
468 case CURLINFO_SIZE_UPLOAD:
469 *param_doublep = (double)data->progress.uploaded;
471 case CURLINFO_SIZE_DOWNLOAD:
472 *param_doublep = (double)data->progress.downloaded;
474 case CURLINFO_SPEED_DOWNLOAD:
475 *param_doublep = (double)data->progress.dlspeed;
477 case CURLINFO_SPEED_UPLOAD:
478 *param_doublep = (double)data->progress.ulspeed;
480 case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
481 *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
482 (double)data->progress.size_dl:-1;
484 case CURLINFO_CONTENT_LENGTH_UPLOAD:
485 *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
486 (double)data->progress.size_ul:-1;
488 case CURLINFO_REDIRECT_TIME:
489 *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
493 return CURLE_UNKNOWN_OPTION;
499 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
500 struct curl_slist **param_slistp)
503 struct curl_certinfo *to_certinfo;
504 struct curl_slist *to_slist;
508 case CURLINFO_SSL_ENGINES:
509 *param_slistp = Curl_ssl_engines_list(data);
511 case CURLINFO_COOKIELIST:
512 *param_slistp = Curl_cookie_list(data);
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;
520 case CURLINFO_TLS_SESSION:
521 case CURLINFO_TLS_SSL_PTR:
523 struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
525 struct curl_tlssessioninfo *tsi = &data->tsi;
527 struct connectdata *conn = data->conn;
531 tsi->backend = Curl_ssl_backend();
532 tsi->internals = NULL;
535 if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
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);
548 return CURLE_UNKNOWN_OPTION;
554 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
555 curl_socket_t *param_socketp)
558 case CURLINFO_ACTIVESOCKET:
559 *param_socketp = Curl_getconnectinfo(data, NULL);
562 return CURLE_UNKNOWN_OPTION;
568 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
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;
578 CURLcode result = CURLE_UNKNOWN_OPTION;
581 return CURLE_BAD_FUNCTION_ARGUMENT;
585 type = CURLINFO_TYPEMASK & (int)info;
587 case CURLINFO_STRING:
588 param_charp = va_arg(arg, const char **);
590 result = getinfo_char(data, info, param_charp);
593 param_longp = va_arg(arg, long *);
595 result = getinfo_long(data, info, param_longp);
597 case CURLINFO_DOUBLE:
598 param_doublep = va_arg(arg, double *);
600 result = getinfo_double(data, info, param_doublep);
603 param_offt = va_arg(arg, curl_off_t *);
605 result = getinfo_offt(data, info, param_offt);
608 param_slistp = va_arg(arg, struct curl_slist **);
610 result = getinfo_slist(data, info, param_slistp);
612 case CURLINFO_SOCKET:
613 param_socketp = va_arg(arg, curl_socket_t *);
615 result = getinfo_socket(data, info, param_socketp);