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