1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2021, 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 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
30 #include "vtls/vtls.h"
31 #include "connect.h" /* Curl_getconnectinfo() */
34 /* The last #include files should be: */
35 #include "curl_memory.h"
39 * Initialize statistical and informational data.
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.
45 CURLcode Curl_initinfo(struct Curl_easy *data)
47 struct Progress *pro = &data->progress;
48 struct PureInfo *info = &data->info;
52 pro->t_appconnect = 0;
53 pro->t_pretransfer = 0;
54 pro->t_starttransfer = 0;
57 pro->is_t_startransfer_set = false;
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;
65 info->header_size = 0;
66 info->request_size = 0;
67 info->proxyauthavail = 0;
68 info->httpauthavail = 0;
69 info->numconnects = 0;
71 free(info->contenttype);
72 info->contenttype = NULL;
74 free(info->wouldredirect);
75 info->wouldredirect = NULL;
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;
83 info->conn_scheme = 0;
84 info->conn_protocol = 0;
87 Curl_ssl_free_certinfo(data);
92 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
93 const char **param_charp)
96 case CURLINFO_EFFECTIVE_URL:
97 *param_charp = data->state.url?data->state.url:(char *)"";
99 case CURLINFO_EFFECTIVE_METHOD: {
100 const char *m = data->set.str[STRING_CUSTOMREQUEST];
102 if(data->set.opt_no_body)
104 #ifndef CURL_DISABLE_HTTP
106 switch(data->state.httpreq) {
108 case HTTPREQ_POST_FORM:
109 case HTTPREQ_POST_MIME:
115 default: /* this should never happen */
129 case CURLINFO_CONTENT_TYPE:
130 *param_charp = data->info.contenttype;
132 case CURLINFO_PRIVATE:
133 *param_charp = (char *) data->set.private_data;
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;
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;
148 case CURLINFO_REFERER:
149 /* Return the referrer header for this request, or NULL if unset */
150 *param_charp = data->state.referer;
152 case CURLINFO_PRIMARY_IP:
153 /* Return the ip address of the most recent (primary) connection */
154 *param_charp = data->info.conn_primary_ip;
156 case CURLINFO_LOCAL_IP:
157 /* Return the source/local ip address of the most recent (primary)
159 *param_charp = data->info.conn_local_ip;
161 case CURLINFO_RTSP_SESSION_ID:
162 *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
164 case CURLINFO_SCHEME:
165 *param_charp = data->info.conn_scheme;
169 return CURLE_UNKNOWN_OPTION;
175 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
178 curl_socket_t sockfd;
181 unsigned long *to_ulong;
186 char *timestr = getenv("CURL_TIME");
188 unsigned long val = strtol(timestr, NULL, 10);
190 case CURLINFO_LOCAL_PORT:
191 *param_longp = (long)val;
197 /* use another variable for this to allow different values */
198 timestr = getenv("CURL_DEBUG_SIZE");
200 unsigned long val = strtol(timestr, NULL, 10);
202 case CURLINFO_HEADER_SIZE:
203 case CURLINFO_REQUEST_SIZE:
204 *param_longp = (long)val;
213 case CURLINFO_RESPONSE_CODE:
214 *param_longp = data->info.httpcode;
216 case CURLINFO_HTTP_CONNECTCODE:
217 *param_longp = data->info.httpproxycode;
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;
225 *param_longp = (long)data->info.filetime;
227 case CURLINFO_HEADER_SIZE:
228 *param_longp = (long)data->info.header_size;
230 case CURLINFO_REQUEST_SIZE:
231 *param_longp = (long)data->info.request_size;
233 case CURLINFO_SSL_VERIFYRESULT:
234 *param_longp = data->set.ssl.certverifyresult;
236 #ifndef CURL_DISABLE_PROXY
237 case CURLINFO_PROXY_SSL_VERIFYRESULT:
238 *param_longp = data->set.proxy_ssl.certverifyresult;
241 case CURLINFO_REDIRECT_COUNT:
242 *param_longp = data->state.followlocation;
244 case CURLINFO_HTTPAUTH_AVAIL:
245 lptr.to_long = param_longp;
246 *lptr.to_ulong = data->info.httpauthavail;
248 case CURLINFO_PROXYAUTH_AVAIL:
249 lptr.to_long = param_longp;
250 *lptr.to_ulong = data->info.proxyauthavail;
252 case CURLINFO_OS_ERRNO:
253 *param_longp = data->state.os_errno;
255 case CURLINFO_NUM_CONNECTS:
256 *param_longp = data->info.numconnects;
258 case CURLINFO_LASTSOCKET:
259 sockfd = Curl_getconnectinfo(data, NULL);
261 /* note: this is not a good conversion for systems with 64 bit sockets and
263 if(sockfd != CURL_SOCKET_BAD)
264 *param_longp = (long)sockfd;
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 */
270 case CURLINFO_PRIMARY_PORT:
271 /* Return the (remote) port of the most recent (primary) connection */
272 *param_longp = data->info.conn_primary_port;
274 case CURLINFO_LOCAL_PORT:
275 /* Return the local port of the most recent (primary) connection */
276 *param_longp = data->info.conn_local_port;
278 case CURLINFO_PROXY_ERROR:
279 *param_longp = (long)data->info.pxcode;
281 case CURLINFO_CONDITION_UNMET:
282 if(data->info.httpcode == 304)
285 /* return if the condition prevented the document to get transferred */
286 *param_longp = data->info.timecond ? 1L : 0L;
288 case CURLINFO_RTSP_CLIENT_CSEQ:
289 *param_longp = data->state.rtsp_next_client_CSeq;
291 case CURLINFO_RTSP_SERVER_CSEQ:
292 *param_longp = data->state.rtsp_next_server_CSeq;
294 case CURLINFO_RTSP_CSEQ_RECV:
295 *param_longp = data->state.rtsp_CSeq_recv;
297 case CURLINFO_HTTP_VERSION:
298 switch(data->info.httpversion) {
300 *param_longp = CURL_HTTP_VERSION_1_0;
303 *param_longp = CURL_HTTP_VERSION_1_1;
306 *param_longp = CURL_HTTP_VERSION_2_0;
309 *param_longp = CURL_HTTP_VERSION_3;
312 *param_longp = CURL_HTTP_VERSION_NONE;
316 case CURLINFO_PROTOCOL:
317 *param_longp = data->info.conn_protocol;
320 return CURLE_UNKNOWN_OPTION;
326 #define DOUBLE_SECS(x) (double)(x)/1000000
328 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
329 curl_off_t *param_offt)
332 char *timestr = getenv("CURL_TIME");
334 unsigned long val = strtol(timestr, NULL, 10);
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;
353 case CURLINFO_FILETIME_T:
354 *param_offt = (curl_off_t)data->info.filetime;
356 case CURLINFO_SIZE_UPLOAD_T:
357 *param_offt = data->progress.uploaded;
359 case CURLINFO_SIZE_DOWNLOAD_T:
360 *param_offt = data->progress.downloaded;
362 case CURLINFO_SPEED_DOWNLOAD_T:
363 *param_offt = data->progress.dlspeed;
365 case CURLINFO_SPEED_UPLOAD_T:
366 *param_offt = data->progress.ulspeed;
368 case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
369 *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
370 data->progress.size_dl:-1;
372 case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
373 *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
374 data->progress.size_ul:-1;
376 case CURLINFO_TOTAL_TIME_T:
377 *param_offt = data->progress.timespent;
379 case CURLINFO_NAMELOOKUP_TIME_T:
380 *param_offt = data->progress.t_nslookup;
382 case CURLINFO_CONNECT_TIME_T:
383 *param_offt = data->progress.t_connect;
385 case CURLINFO_APPCONNECT_TIME_T:
386 *param_offt = data->progress.t_appconnect;
388 case CURLINFO_PRETRANSFER_TIME_T:
389 *param_offt = data->progress.t_pretransfer;
391 case CURLINFO_STARTTRANSFER_TIME_T:
392 *param_offt = data->progress.t_starttransfer;
394 case CURLINFO_REDIRECT_TIME_T:
395 *param_offt = data->progress.t_redirect;
397 case CURLINFO_RETRY_AFTER:
398 *param_offt = data->info.retry_after;
401 return CURLE_UNKNOWN_OPTION;
407 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
408 double *param_doublep)
411 char *timestr = getenv("CURL_TIME");
413 unsigned long val = strtol(timestr, NULL, 10);
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;
432 case CURLINFO_TOTAL_TIME:
433 *param_doublep = DOUBLE_SECS(data->progress.timespent);
435 case CURLINFO_NAMELOOKUP_TIME:
436 *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
438 case CURLINFO_CONNECT_TIME:
439 *param_doublep = DOUBLE_SECS(data->progress.t_connect);
441 case CURLINFO_APPCONNECT_TIME:
442 *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
444 case CURLINFO_PRETRANSFER_TIME:
445 *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
447 case CURLINFO_STARTTRANSFER_TIME:
448 *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
450 case CURLINFO_SIZE_UPLOAD:
451 *param_doublep = (double)data->progress.uploaded;
453 case CURLINFO_SIZE_DOWNLOAD:
454 *param_doublep = (double)data->progress.downloaded;
456 case CURLINFO_SPEED_DOWNLOAD:
457 *param_doublep = (double)data->progress.dlspeed;
459 case CURLINFO_SPEED_UPLOAD:
460 *param_doublep = (double)data->progress.ulspeed;
462 case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
463 *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
464 (double)data->progress.size_dl:-1;
466 case CURLINFO_CONTENT_LENGTH_UPLOAD:
467 *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
468 (double)data->progress.size_ul:-1;
470 case CURLINFO_REDIRECT_TIME:
471 *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
475 return CURLE_UNKNOWN_OPTION;
481 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
482 struct curl_slist **param_slistp)
485 struct curl_certinfo *to_certinfo;
486 struct curl_slist *to_slist;
490 case CURLINFO_SSL_ENGINES:
491 *param_slistp = Curl_ssl_engines_list(data);
493 case CURLINFO_COOKIELIST:
494 *param_slistp = Curl_cookie_list(data);
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;
502 case CURLINFO_TLS_SESSION:
503 case CURLINFO_TLS_SSL_PTR:
505 struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
507 struct curl_tlssessioninfo *tsi = &data->tsi;
509 struct connectdata *conn = data->conn;
513 tsi->backend = Curl_ssl_backend();
514 tsi->internals = NULL;
517 if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
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);
530 return CURLE_UNKNOWN_OPTION;
536 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
537 curl_socket_t *param_socketp)
540 case CURLINFO_ACTIVESOCKET:
541 *param_socketp = Curl_getconnectinfo(data, NULL);
544 return CURLE_UNKNOWN_OPTION;
550 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
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;
560 CURLcode result = CURLE_UNKNOWN_OPTION;
567 type = CURLINFO_TYPEMASK & (int)info;
569 case CURLINFO_STRING:
570 param_charp = va_arg(arg, const char **);
572 result = getinfo_char(data, info, param_charp);
575 param_longp = va_arg(arg, long *);
577 result = getinfo_long(data, info, param_longp);
579 case CURLINFO_DOUBLE:
580 param_doublep = va_arg(arg, double *);
582 result = getinfo_double(data, info, param_doublep);
585 param_offt = va_arg(arg, curl_off_t *);
587 result = getinfo_offt(data, info, param_offt);
590 param_slistp = va_arg(arg, struct curl_slist **);
592 result = getinfo_slist(data, info, param_slistp);
594 case CURLINFO_SOCKET:
595 param_socketp = va_arg(arg, curl_socket_t *);
597 result = getinfo_socket(data, info, param_socketp);