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