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