Revert "Update to 7.40.1"
[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   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_BAD_FUNCTION_ARGUMENT;
204   }
205   return CURLE_OK;
206 }
207
208 static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info,
209                                double *param_doublep)
210 {
211   switch(info) {
212   case CURLINFO_TOTAL_TIME:
213     *param_doublep = data->progress.timespent;
214     break;
215   case CURLINFO_NAMELOOKUP_TIME:
216     *param_doublep = data->progress.t_nslookup;
217     break;
218   case CURLINFO_CONNECT_TIME:
219     *param_doublep = data->progress.t_connect;
220     break;
221   case CURLINFO_APPCONNECT_TIME:
222     *param_doublep = data->progress.t_appconnect;
223     break;
224   case CURLINFO_PRETRANSFER_TIME:
225     *param_doublep =  data->progress.t_pretransfer;
226     break;
227   case CURLINFO_STARTTRANSFER_TIME:
228     *param_doublep = data->progress.t_starttransfer;
229     break;
230   case CURLINFO_SIZE_UPLOAD:
231     *param_doublep =  (double)data->progress.uploaded;
232     break;
233   case CURLINFO_SIZE_DOWNLOAD:
234     *param_doublep = (double)data->progress.downloaded;
235     break;
236   case CURLINFO_SPEED_DOWNLOAD:
237     *param_doublep =  (double)data->progress.dlspeed;
238     break;
239   case CURLINFO_SPEED_UPLOAD:
240     *param_doublep = (double)data->progress.ulspeed;
241     break;
242   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
243     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
244       (double)data->progress.size_dl:-1;
245     break;
246   case CURLINFO_CONTENT_LENGTH_UPLOAD:
247     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
248       (double)data->progress.size_ul:-1;
249     break;
250   case CURLINFO_REDIRECT_TIME:
251     *param_doublep =  data->progress.t_redirect;
252     break;
253
254   default:
255     return CURLE_BAD_FUNCTION_ARGUMENT;
256   }
257   return CURLE_OK;
258 }
259
260 static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
261                               struct curl_slist **param_slistp)
262 {
263   union {
264     struct curl_certinfo * to_certinfo;
265     struct curl_slist    * to_slist;
266   } ptr;
267
268   switch(info) {
269   case CURLINFO_SSL_ENGINES:
270     *param_slistp = Curl_ssl_engines_list(data);
271     break;
272   case CURLINFO_COOKIELIST:
273     *param_slistp = Curl_cookie_list(data);
274     break;
275   case CURLINFO_CERTINFO:
276     /* Return the a pointer to the certinfo struct. Not really an slist
277        pointer but we can pretend it is here */
278     ptr.to_certinfo = &data->info.certs;
279     *param_slistp = ptr.to_slist;
280     break;
281   case CURLINFO_TLS_SESSION:
282     {
283       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
284                                           param_slistp;
285       struct curl_tlssessioninfo *tsi = &data->tsi;
286       struct connectdata *conn = data->easy_conn;
287       unsigned int sockindex = 0;
288
289       *tsip = tsi;
290       tsi->backend = CURLSSLBACKEND_NONE;
291       tsi->internals = NULL;
292
293       if(!conn)
294         break;
295
296       /* Find the active ("in use") SSL connection, if any */
297       while((sockindex < sizeof(conn->ssl) / sizeof(conn->ssl[0])) &&
298             (!conn->ssl[sockindex].use))
299         sockindex++;
300
301       if(sockindex == sizeof(conn->ssl) / sizeof(conn->ssl[0]))
302         break; /* no SSL session found */
303
304       /* Return the TLS session information from the relevant backend */
305 #ifdef USE_SSLEAY
306       tsi->backend = CURLSSLBACKEND_OPENSSL;
307       tsi->internals = conn->ssl[sockindex].ctx;
308 #endif
309 #ifdef USE_GNUTLS
310       tsi->backend = CURLSSLBACKEND_GNUTLS;
311       tsi->internals = conn->ssl[sockindex].session;
312 #endif
313 #ifdef USE_NSS
314       tsi->backend = CURLSSLBACKEND_NSS;
315       tsi->internals = conn->ssl[sockindex].handle;
316 #endif
317 #ifdef USE_QSOSSL
318       tsi->backend = CURLSSLBACKEND_QSOSSL;
319       tsi->internals = conn->ssl[sockindex].handle;
320 #endif
321 #ifdef USE_GSKIT
322       tsi->backend = CURLSSLBACKEND_GSKIT;
323       tsi->internals = conn->ssl[sockindex].handle;
324 #endif
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   return CURLE_OK;
335 }
336
337 CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
338 {
339   va_list arg;
340   long *param_longp=NULL;
341   double *param_doublep=NULL;
342   char **param_charp=NULL;
343   struct curl_slist **param_slistp=NULL;
344   int type;
345   /* default return code is to error out! */
346   CURLcode ret = CURLE_BAD_FUNCTION_ARGUMENT;
347
348   if(!data)
349     return ret;
350
351   va_start(arg, info);
352
353   type = CURLINFO_TYPEMASK & (int)info;
354   switch(type) {
355   case CURLINFO_STRING:
356     param_charp = va_arg(arg, char **);
357     if(NULL != param_charp)
358       ret = getinfo_char(data, info, param_charp);
359     break;
360   case CURLINFO_LONG:
361     param_longp = va_arg(arg, long *);
362     if(NULL != param_longp)
363       ret = getinfo_long(data, info, param_longp);
364     break;
365   case CURLINFO_DOUBLE:
366     param_doublep = va_arg(arg, double *);
367     if(NULL != param_doublep)
368       ret = getinfo_double(data, info, param_doublep);
369     break;
370   case CURLINFO_SLIST:
371     param_slistp = va_arg(arg, struct curl_slist **);
372     if(NULL != param_slistp)
373       ret = getinfo_slist(data, info, param_slistp);
374     break;
375   default:
376     break;
377   }
378
379   va_end(arg);
380   return ret;
381 }