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