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