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