Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / getinfo.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2018, 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  */
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
82   info->conn_scheme = 0;
83   info->conn_protocol = 0;
84
85 #ifdef USE_SSL
86   Curl_ssl_free_certinfo(data);
87 #endif
88
89   return CURLE_OK;
90 }
91
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_CONTENT_TYPE:
100     *param_charp = data->info.contenttype;
101     break;
102   case CURLINFO_PRIVATE:
103     *param_charp = (char *) data->set.private_data;
104     break;
105   case CURLINFO_FTP_ENTRY_PATH:
106     /* Return the entrypath string from the most recent connection.
107        This pointer was copied from the connectdata structure by FTP.
108        The actual string may be free()ed by subsequent libcurl calls so
109        it must be copied to a safer area before the next libcurl call.
110        Callers must never free it themselves. */
111     *param_charp = data->state.most_recent_ftp_entrypath;
112     break;
113   case CURLINFO_REDIRECT_URL:
114     /* Return the URL this request would have been redirected to if that
115        option had been enabled! */
116     *param_charp = data->info.wouldredirect;
117     break;
118   case CURLINFO_PRIMARY_IP:
119     /* Return the ip address of the most recent (primary) connection */
120     *param_charp = data->info.conn_primary_ip;
121     break;
122   case CURLINFO_LOCAL_IP:
123     /* Return the source/local ip address of the most recent (primary)
124        connection */
125     *param_charp = data->info.conn_local_ip;
126     break;
127   case CURLINFO_RTSP_SESSION_ID:
128     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
129     break;
130   case CURLINFO_SCHEME:
131     *param_charp = data->info.conn_scheme;
132     break;
133
134   default:
135     return CURLE_UNKNOWN_OPTION;
136   }
137
138   return CURLE_OK;
139 }
140
141 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
142                              long *param_longp)
143 {
144   curl_socket_t sockfd;
145
146   union {
147     unsigned long *to_ulong;
148     long          *to_long;
149   } lptr;
150
151   switch(info) {
152   case CURLINFO_RESPONSE_CODE:
153     *param_longp = data->info.httpcode;
154     break;
155   case CURLINFO_HTTP_CONNECTCODE:
156     *param_longp = data->info.httpproxycode;
157     break;
158   case CURLINFO_FILETIME:
159     if(data->info.filetime > LONG_MAX)
160       *param_longp = LONG_MAX;
161     else if(data->info.filetime < LONG_MIN)
162       *param_longp = LONG_MIN;
163     else
164       *param_longp = (long)data->info.filetime;
165     break;
166   case CURLINFO_HEADER_SIZE:
167     *param_longp = data->info.header_size;
168     break;
169   case CURLINFO_REQUEST_SIZE:
170     *param_longp = data->info.request_size;
171     break;
172   case CURLINFO_SSL_VERIFYRESULT:
173     *param_longp = data->set.ssl.certverifyresult;
174     break;
175   case CURLINFO_PROXY_SSL_VERIFYRESULT:
176     *param_longp = data->set.proxy_ssl.certverifyresult;
177     break;
178   case CURLINFO_REDIRECT_COUNT:
179     *param_longp = data->set.followlocation;
180     break;
181   case CURLINFO_HTTPAUTH_AVAIL:
182     lptr.to_long = param_longp;
183     *lptr.to_ulong = data->info.httpauthavail;
184     break;
185   case CURLINFO_PROXYAUTH_AVAIL:
186     lptr.to_long = param_longp;
187     *lptr.to_ulong = data->info.proxyauthavail;
188     break;
189   case CURLINFO_OS_ERRNO:
190     *param_longp = data->state.os_errno;
191     break;
192   case CURLINFO_NUM_CONNECTS:
193     *param_longp = data->info.numconnects;
194     break;
195   case CURLINFO_LASTSOCKET:
196     sockfd = Curl_getconnectinfo(data, NULL);
197
198     /* note: this is not a good conversion for systems with 64 bit sockets and
199        32 bit longs */
200     if(sockfd != CURL_SOCKET_BAD)
201       *param_longp = (long)sockfd;
202     else
203       /* this interface is documented to return -1 in case of badness, which
204          may not be the same as the CURL_SOCKET_BAD value */
205       *param_longp = -1;
206     break;
207   case CURLINFO_PRIMARY_PORT:
208     /* Return the (remote) port of the most recent (primary) connection */
209     *param_longp = data->info.conn_primary_port;
210     break;
211   case CURLINFO_LOCAL_PORT:
212     /* Return the local port of the most recent (primary) connection */
213     *param_longp = data->info.conn_local_port;
214     break;
215   case CURLINFO_CONDITION_UNMET:
216     /* return if the condition prevented the document to get transferred */
217     *param_longp = data->info.timecond ? 1L : 0L;
218     break;
219   case CURLINFO_RTSP_CLIENT_CSEQ:
220     *param_longp = data->state.rtsp_next_client_CSeq;
221     break;
222   case CURLINFO_RTSP_SERVER_CSEQ:
223     *param_longp = data->state.rtsp_next_server_CSeq;
224     break;
225   case CURLINFO_RTSP_CSEQ_RECV:
226     *param_longp = data->state.rtsp_CSeq_recv;
227     break;
228   case CURLINFO_HTTP_VERSION:
229     switch(data->info.httpversion) {
230     case 10:
231       *param_longp = CURL_HTTP_VERSION_1_0;
232       break;
233     case 11:
234       *param_longp = CURL_HTTP_VERSION_1_1;
235       break;
236     case 20:
237       *param_longp = CURL_HTTP_VERSION_2_0;
238       break;
239     default:
240       *param_longp = CURL_HTTP_VERSION_NONE;
241       break;
242     }
243     break;
244   case CURLINFO_PROTOCOL:
245     *param_longp = data->info.conn_protocol;
246     break;
247
248   default:
249     return CURLE_UNKNOWN_OPTION;
250   }
251
252   return CURLE_OK;
253 }
254
255 #define DOUBLE_SECS(x) (double)(x)/1000000
256
257 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
258                              curl_off_t *param_offt)
259 {
260   switch(info) {
261   case CURLINFO_FILETIME_T:
262     *param_offt = (curl_off_t)data->info.filetime;
263     break;
264   case CURLINFO_SIZE_UPLOAD_T:
265     *param_offt = data->progress.uploaded;
266     break;
267   case CURLINFO_SIZE_DOWNLOAD_T:
268     *param_offt = data->progress.downloaded;
269     break;
270   case CURLINFO_SPEED_DOWNLOAD_T:
271     *param_offt =  data->progress.dlspeed;
272     break;
273   case CURLINFO_SPEED_UPLOAD_T:
274     *param_offt = data->progress.ulspeed;
275     break;
276   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
277     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
278       data->progress.size_dl:-1;
279     break;
280   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
281     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
282       data->progress.size_ul:-1;
283     break;
284   default:
285     return CURLE_UNKNOWN_OPTION;
286   }
287
288   return CURLE_OK;
289 }
290
291 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
292                                double *param_doublep)
293 {
294   switch(info) {
295   case CURLINFO_TOTAL_TIME:
296     *param_doublep = DOUBLE_SECS(data->progress.timespent);
297     break;
298   case CURLINFO_NAMELOOKUP_TIME:
299     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
300     break;
301   case CURLINFO_CONNECT_TIME:
302     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
303     break;
304   case CURLINFO_APPCONNECT_TIME:
305     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
306     break;
307   case CURLINFO_PRETRANSFER_TIME:
308     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
309     break;
310   case CURLINFO_STARTTRANSFER_TIME:
311     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
312     break;
313   case CURLINFO_SIZE_UPLOAD:
314     *param_doublep =  (double)data->progress.uploaded;
315     break;
316   case CURLINFO_SIZE_DOWNLOAD:
317     *param_doublep = (double)data->progress.downloaded;
318     break;
319   case CURLINFO_SPEED_DOWNLOAD:
320     *param_doublep =  (double)data->progress.dlspeed;
321     break;
322   case CURLINFO_SPEED_UPLOAD:
323     *param_doublep = (double)data->progress.ulspeed;
324     break;
325   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
326     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
327       (double)data->progress.size_dl:-1;
328     break;
329   case CURLINFO_CONTENT_LENGTH_UPLOAD:
330     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
331       (double)data->progress.size_ul:-1;
332     break;
333   case CURLINFO_REDIRECT_TIME:
334     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
335     break;
336
337   default:
338     return CURLE_UNKNOWN_OPTION;
339   }
340
341   return CURLE_OK;
342 }
343
344 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
345                               struct curl_slist **param_slistp)
346 {
347   union {
348     struct curl_certinfo *to_certinfo;
349     struct curl_slist    *to_slist;
350   } ptr;
351
352   switch(info) {
353   case CURLINFO_SSL_ENGINES:
354     *param_slistp = Curl_ssl_engines_list(data);
355     break;
356   case CURLINFO_COOKIELIST:
357     *param_slistp = Curl_cookie_list(data);
358     break;
359   case CURLINFO_CERTINFO:
360     /* Return the a pointer to the certinfo struct. Not really an slist
361        pointer but we can pretend it is here */
362     ptr.to_certinfo = &data->info.certs;
363     *param_slistp = ptr.to_slist;
364     break;
365   case CURLINFO_TLS_SESSION:
366   case CURLINFO_TLS_SSL_PTR:
367     {
368       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
369                                           param_slistp;
370       struct curl_tlssessioninfo *tsi = &data->tsi;
371 #ifdef USE_SSL
372       struct connectdata *conn = data->easy_conn;
373 #endif
374
375       *tsip = tsi;
376       tsi->backend = Curl_ssl_backend();
377       tsi->internals = NULL;
378
379 #ifdef USE_SSL
380       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
381         unsigned int i;
382         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
383           if(conn->ssl[i].use) {
384             tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
385             break;
386           }
387         }
388       }
389 #endif
390     }
391     break;
392   default:
393     return CURLE_UNKNOWN_OPTION;
394   }
395
396   return CURLE_OK;
397 }
398
399 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
400                                curl_socket_t *param_socketp)
401 {
402   switch(info) {
403   case CURLINFO_ACTIVESOCKET:
404     *param_socketp = Curl_getconnectinfo(data, NULL);
405     break;
406   default:
407     return CURLE_UNKNOWN_OPTION;
408   }
409
410   return CURLE_OK;
411 }
412
413 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
414 {
415   va_list arg;
416   long *param_longp = NULL;
417   double *param_doublep = NULL;
418   curl_off_t *param_offt = NULL;
419   const char **param_charp = NULL;
420   struct curl_slist **param_slistp = NULL;
421   curl_socket_t *param_socketp = NULL;
422   int type;
423   CURLcode result = CURLE_UNKNOWN_OPTION;
424
425   if(!data)
426     return result;
427
428   va_start(arg, info);
429
430   type = CURLINFO_TYPEMASK & (int)info;
431   switch(type) {
432   case CURLINFO_STRING:
433     param_charp = va_arg(arg, const char **);
434     if(param_charp)
435       result = getinfo_char(data, info, param_charp);
436     break;
437   case CURLINFO_LONG:
438     param_longp = va_arg(arg, long *);
439     if(param_longp)
440       result = getinfo_long(data, info, param_longp);
441     break;
442   case CURLINFO_DOUBLE:
443     param_doublep = va_arg(arg, double *);
444     if(param_doublep)
445       result = getinfo_double(data, info, param_doublep);
446     break;
447   case CURLINFO_OFF_T:
448     param_offt = va_arg(arg, curl_off_t *);
449     if(param_offt)
450       result = getinfo_offt(data, info, param_offt);
451     break;
452   case CURLINFO_SLIST:
453     param_slistp = va_arg(arg, struct curl_slist **);
454     if(param_slistp)
455       result = getinfo_slist(data, info, param_slistp);
456     break;
457   case CURLINFO_SOCKET:
458     param_socketp = va_arg(arg, curl_socket_t *);
459     if(param_socketp)
460       result = getinfo_socket(data, info, param_socketp);
461     break;
462   default:
463     break;
464   }
465
466   va_end(arg);
467
468   return result;
469 }