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 */
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 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
getinfo_char(struct Curl_easy * data,CURLINFO info,const char ** param_charp)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
getinfo_long(struct Curl_easy * data,CURLINFO info,long * param_longp)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
getinfo_double(struct Curl_easy * data,CURLINFO info,double * param_doublep)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
getinfo_slist(struct Curl_easy * data,CURLINFO info,struct curl_slist ** param_slistp)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
getinfo_socket(struct Curl_easy * data,CURLINFO info,curl_socket_t * param_socketp)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
Curl_getinfo(struct Curl_easy * data,CURLINFO info,...)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 }
443