1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2020, 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.haxx.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->change.url?data->change.url:(char *)"";
99 case CURLINFO_EFFECTIVE_METHOD: {
100 const char *m = data->set.str[STRING_CUSTOMREQUEST];
102 if(data->set.opt_no_body)
105 switch(data->state.httpreq) {
107 case HTTPREQ_POST_FORM:
108 case HTTPREQ_POST_MIME:
114 default: /* this should never happen */
127 case CURLINFO_CONTENT_TYPE:
128 *param_charp = data->info.contenttype;
130 case CURLINFO_PRIVATE:
131 *param_charp = (char *) data->set.private_data;
133 case CURLINFO_FTP_ENTRY_PATH:
134 /* Return the entrypath string from the most recent connection.
135 This pointer was copied from the connectdata structure by FTP.
136 The actual string may be free()ed by subsequent libcurl calls so
137 it must be copied to a safer area before the next libcurl call.
138 Callers must never free it themselves. */
139 *param_charp = data->state.most_recent_ftp_entrypath;
141 case CURLINFO_REDIRECT_URL:
142 /* Return the URL this request would have been redirected to if that
143 option had been enabled! */
144 *param_charp = data->info.wouldredirect;
146 case CURLINFO_PRIMARY_IP:
147 /* Return the ip address of the most recent (primary) connection */
148 *param_charp = data->info.conn_primary_ip;
150 case CURLINFO_LOCAL_IP:
151 /* Return the source/local ip address of the most recent (primary)
153 *param_charp = data->info.conn_local_ip;
155 case CURLINFO_RTSP_SESSION_ID:
156 *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
158 case CURLINFO_SCHEME:
159 *param_charp = data->info.conn_scheme;
163 return CURLE_UNKNOWN_OPTION;
169 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
172 curl_socket_t sockfd;
175 unsigned long *to_ulong;
180 char *timestr = getenv("CURL_TIME");
182 unsigned long val = strtol(timestr, NULL, 10);
184 case CURLINFO_LOCAL_PORT:
185 *param_longp = (long)val;
191 /* use another variable for this to allow different values */
192 timestr = getenv("CURL_DEBUG_SIZE");
194 unsigned long val = strtol(timestr, NULL, 10);
196 case CURLINFO_HEADER_SIZE:
197 case CURLINFO_REQUEST_SIZE:
198 *param_longp = (long)val;
207 case CURLINFO_RESPONSE_CODE:
208 *param_longp = data->info.httpcode;
210 case CURLINFO_HTTP_CONNECTCODE:
211 *param_longp = data->info.httpproxycode;
213 case CURLINFO_FILETIME:
214 if(data->info.filetime > LONG_MAX)
215 *param_longp = LONG_MAX;
216 else if(data->info.filetime < LONG_MIN)
217 *param_longp = LONG_MIN;
219 *param_longp = (long)data->info.filetime;
221 case CURLINFO_HEADER_SIZE:
222 *param_longp = (long)data->info.header_size;
224 case CURLINFO_REQUEST_SIZE:
225 *param_longp = (long)data->info.request_size;
227 case CURLINFO_SSL_VERIFYRESULT:
228 *param_longp = data->set.ssl.certverifyresult;
230 #ifndef CURL_DISABLE_PROXY
231 case CURLINFO_PROXY_SSL_VERIFYRESULT:
232 *param_longp = data->set.proxy_ssl.certverifyresult;
235 case CURLINFO_REDIRECT_COUNT:
236 *param_longp = data->set.followlocation;
238 case CURLINFO_HTTPAUTH_AVAIL:
239 lptr.to_long = param_longp;
240 *lptr.to_ulong = data->info.httpauthavail;
242 case CURLINFO_PROXYAUTH_AVAIL:
243 lptr.to_long = param_longp;
244 *lptr.to_ulong = data->info.proxyauthavail;
246 case CURLINFO_OS_ERRNO:
247 *param_longp = data->state.os_errno;
249 case CURLINFO_NUM_CONNECTS:
250 *param_longp = data->info.numconnects;
252 case CURLINFO_LASTSOCKET:
253 sockfd = Curl_getconnectinfo(data, NULL);
255 /* note: this is not a good conversion for systems with 64 bit sockets and
257 if(sockfd != CURL_SOCKET_BAD)
258 *param_longp = (long)sockfd;
260 /* this interface is documented to return -1 in case of badness, which
261 may not be the same as the CURL_SOCKET_BAD value */
264 case CURLINFO_PRIMARY_PORT:
265 /* Return the (remote) port of the most recent (primary) connection */
266 *param_longp = data->info.conn_primary_port;
268 case CURLINFO_LOCAL_PORT:
269 /* Return the local port of the most recent (primary) connection */
270 *param_longp = data->info.conn_local_port;
272 case CURLINFO_PROXY_ERROR:
273 *param_longp = (long)data->info.pxcode;
275 case CURLINFO_CONDITION_UNMET:
276 if(data->info.httpcode == 304)
279 /* return if the condition prevented the document to get transferred */
280 *param_longp = data->info.timecond ? 1L : 0L;
282 case CURLINFO_RTSP_CLIENT_CSEQ:
283 *param_longp = data->state.rtsp_next_client_CSeq;
285 case CURLINFO_RTSP_SERVER_CSEQ:
286 *param_longp = data->state.rtsp_next_server_CSeq;
288 case CURLINFO_RTSP_CSEQ_RECV:
289 *param_longp = data->state.rtsp_CSeq_recv;
291 case CURLINFO_HTTP_VERSION:
292 switch(data->info.httpversion) {
294 *param_longp = CURL_HTTP_VERSION_1_0;
297 *param_longp = CURL_HTTP_VERSION_1_1;
300 *param_longp = CURL_HTTP_VERSION_2_0;
303 *param_longp = CURL_HTTP_VERSION_3;
306 *param_longp = CURL_HTTP_VERSION_NONE;
310 case CURLINFO_PROTOCOL:
311 *param_longp = data->info.conn_protocol;
314 return CURLE_UNKNOWN_OPTION;
320 #define DOUBLE_SECS(x) (double)(x)/1000000
322 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
323 curl_off_t *param_offt)
326 char *timestr = getenv("CURL_TIME");
328 unsigned long val = strtol(timestr, NULL, 10);
330 case CURLINFO_TOTAL_TIME_T:
331 case CURLINFO_NAMELOOKUP_TIME_T:
332 case CURLINFO_CONNECT_TIME_T:
333 case CURLINFO_APPCONNECT_TIME_T:
334 case CURLINFO_PRETRANSFER_TIME_T:
335 case CURLINFO_STARTTRANSFER_TIME_T:
336 case CURLINFO_REDIRECT_TIME_T:
337 case CURLINFO_SPEED_DOWNLOAD_T:
338 case CURLINFO_SPEED_UPLOAD_T:
339 *param_offt = (curl_off_t)val;
347 case CURLINFO_FILETIME_T:
348 *param_offt = (curl_off_t)data->info.filetime;
350 case CURLINFO_SIZE_UPLOAD_T:
351 *param_offt = data->progress.uploaded;
353 case CURLINFO_SIZE_DOWNLOAD_T:
354 *param_offt = data->progress.downloaded;
356 case CURLINFO_SPEED_DOWNLOAD_T:
357 *param_offt = data->progress.dlspeed;
359 case CURLINFO_SPEED_UPLOAD_T:
360 *param_offt = data->progress.ulspeed;
362 case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
363 *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
364 data->progress.size_dl:-1;
366 case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
367 *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
368 data->progress.size_ul:-1;
370 case CURLINFO_TOTAL_TIME_T:
371 *param_offt = data->progress.timespent;
373 case CURLINFO_NAMELOOKUP_TIME_T:
374 *param_offt = data->progress.t_nslookup;
376 case CURLINFO_CONNECT_TIME_T:
377 *param_offt = data->progress.t_connect;
379 case CURLINFO_APPCONNECT_TIME_T:
380 *param_offt = data->progress.t_appconnect;
382 case CURLINFO_PRETRANSFER_TIME_T:
383 *param_offt = data->progress.t_pretransfer;
385 case CURLINFO_STARTTRANSFER_TIME_T:
386 *param_offt = data->progress.t_starttransfer;
388 case CURLINFO_REDIRECT_TIME_T:
389 *param_offt = data->progress.t_redirect;
391 case CURLINFO_RETRY_AFTER:
392 *param_offt = data->info.retry_after;
395 return CURLE_UNKNOWN_OPTION;
401 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
402 double *param_doublep)
405 char *timestr = getenv("CURL_TIME");
407 unsigned long val = strtol(timestr, NULL, 10);
409 case CURLINFO_TOTAL_TIME:
410 case CURLINFO_NAMELOOKUP_TIME:
411 case CURLINFO_CONNECT_TIME:
412 case CURLINFO_APPCONNECT_TIME:
413 case CURLINFO_PRETRANSFER_TIME:
414 case CURLINFO_STARTTRANSFER_TIME:
415 case CURLINFO_REDIRECT_TIME:
416 case CURLINFO_SPEED_DOWNLOAD:
417 case CURLINFO_SPEED_UPLOAD:
418 *param_doublep = (double)val;
426 case CURLINFO_TOTAL_TIME:
427 *param_doublep = DOUBLE_SECS(data->progress.timespent);
429 case CURLINFO_NAMELOOKUP_TIME:
430 *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
432 case CURLINFO_CONNECT_TIME:
433 *param_doublep = DOUBLE_SECS(data->progress.t_connect);
435 case CURLINFO_APPCONNECT_TIME:
436 *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
438 case CURLINFO_PRETRANSFER_TIME:
439 *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
441 case CURLINFO_STARTTRANSFER_TIME:
442 *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
444 case CURLINFO_SIZE_UPLOAD:
445 *param_doublep = (double)data->progress.uploaded;
447 case CURLINFO_SIZE_DOWNLOAD:
448 *param_doublep = (double)data->progress.downloaded;
450 case CURLINFO_SPEED_DOWNLOAD:
451 *param_doublep = (double)data->progress.dlspeed;
453 case CURLINFO_SPEED_UPLOAD:
454 *param_doublep = (double)data->progress.ulspeed;
456 case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
457 *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
458 (double)data->progress.size_dl:-1;
460 case CURLINFO_CONTENT_LENGTH_UPLOAD:
461 *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
462 (double)data->progress.size_ul:-1;
464 case CURLINFO_REDIRECT_TIME:
465 *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
469 return CURLE_UNKNOWN_OPTION;
475 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
476 struct curl_slist **param_slistp)
479 struct curl_certinfo *to_certinfo;
480 struct curl_slist *to_slist;
484 case CURLINFO_SSL_ENGINES:
485 *param_slistp = Curl_ssl_engines_list(data);
487 case CURLINFO_COOKIELIST:
488 *param_slistp = Curl_cookie_list(data);
490 case CURLINFO_CERTINFO:
491 /* Return the a pointer to the certinfo struct. Not really an slist
492 pointer but we can pretend it is here */
493 ptr.to_certinfo = &data->info.certs;
494 *param_slistp = ptr.to_slist;
496 case CURLINFO_TLS_SESSION:
497 case CURLINFO_TLS_SSL_PTR:
499 struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
501 struct curl_tlssessioninfo *tsi = &data->tsi;
503 struct connectdata *conn = data->conn;
507 tsi->backend = Curl_ssl_backend();
508 tsi->internals = NULL;
511 if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
513 for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
514 if(conn->ssl[i].use) {
515 tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
524 return CURLE_UNKNOWN_OPTION;
530 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
531 curl_socket_t *param_socketp)
534 case CURLINFO_ACTIVESOCKET:
535 *param_socketp = Curl_getconnectinfo(data, NULL);
538 return CURLE_UNKNOWN_OPTION;
544 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
547 long *param_longp = NULL;
548 double *param_doublep = NULL;
549 curl_off_t *param_offt = NULL;
550 const char **param_charp = NULL;
551 struct curl_slist **param_slistp = NULL;
552 curl_socket_t *param_socketp = NULL;
554 CURLcode result = CURLE_UNKNOWN_OPTION;
561 type = CURLINFO_TYPEMASK & (int)info;
563 case CURLINFO_STRING:
564 param_charp = va_arg(arg, const char **);
566 result = getinfo_char(data, info, param_charp);
569 param_longp = va_arg(arg, long *);
571 result = getinfo_long(data, info, param_longp);
573 case CURLINFO_DOUBLE:
574 param_doublep = va_arg(arg, double *);
576 result = getinfo_double(data, info, param_doublep);
579 param_offt = va_arg(arg, curl_off_t *);
581 result = getinfo_offt(data, info, param_offt);
584 param_slistp = va_arg(arg, struct curl_slist **);
586 result = getinfo_slist(data, info, param_slistp);
588 case CURLINFO_SOCKET:
589 param_socketp = va_arg(arg, curl_socket_t *);
591 result = getinfo_socket(data, info, param_socketp);