• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #include <curl/curl.h>
28 
29 #include "urldata.h"
30 #include "getinfo.h"
31 
32 #include "vtls/vtls.h"
33 #include "connect.h" /* Curl_getconnectinfo() */
34 #include "progress.h"
35 
36 /* The last #include files should be: */
37 #include "curl_memory.h"
38 #include "memdebug.h"
39 
40 /*
41  * Initialize statistical and informational data.
42  *
43  * This function is called in curl_easy_reset, curl_easy_duphandle and at the
44  * beginning of a perform session. It must reset the session-info variables,
45  * in particular all variables in struct PureInfo.
46  */
Curl_initinfo(struct Curl_easy * data)47 CURLcode Curl_initinfo(struct Curl_easy *data)
48 {
49   struct Progress *pro = &data->progress;
50   struct PureInfo *info = &data->info;
51 
52   pro->t_nslookup = 0;
53   pro->t_connect = 0;
54   pro->t_appconnect = 0;
55   pro->t_pretransfer = 0;
56   pro->t_starttransfer = 0;
57   pro->timespent = 0;
58   pro->t_redirect = 0;
59   pro->is_t_startransfer_set = false;
60 
61   info->httpcode = 0;
62   info->httpproxycode = 0;
63   info->httpversion = 0;
64   info->filetime = -1; /* -1 is an illegal time and thus means unknown */
65   info->timecond = FALSE;
66 
67   info->header_size = 0;
68   info->request_size = 0;
69   info->proxyauthavail = 0;
70   info->httpauthavail = 0;
71   info->numconnects = 0;
72 
73   free(info->contenttype);
74   info->contenttype = NULL;
75 
76   free(info->wouldredirect);
77   info->wouldredirect = NULL;
78 
79   info->primary.remote_ip[0] = '\0';
80   info->primary.local_ip[0] = '\0';
81   info->primary.remote_port = 0;
82   info->primary.local_port = 0;
83   info->retry_after = 0;
84 
85   info->conn_scheme = 0;
86   info->conn_protocol = 0;
87 
88 #ifdef USE_SSL
89   Curl_ssl_free_certinfo(data);
90 #endif
91   return CURLE_OK;
92 }
93 
getinfo_pchar(struct Curl_easy * data,CURLINFO info,const char *** param_pcharp)94 static CURLcode getinfo_pchar(struct Curl_easy *data, CURLINFO info,
95                               const char ***param_pcharp) {
96   switch (info) {
97     case CURLINFO_CIPHERS:
98       *param_pcharp = data->ciphers;
99       break;
100     default:
101       break;
102   }
103   return CURLE_OK;
104 }
105 
getinfo_char(struct Curl_easy * data,CURLINFO info,const char ** param_charp)106 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
107                              const char **param_charp)
108 {
109   switch(info) {
110   case CURLINFO_LAST_RECV_SSL_ERROR:
111     *param_charp = data->last_ssl_recv_err;
112     break;
113   case CURLINFO_LAST_SEND_SSL_ERROR:
114     *param_charp = data->last_ssl_send_err;
115     break;
116   case CURLINFO_SSL_ERROR:
117     *param_charp = data->ssl_err;
118     break;
119   case CURLINFO_EFFECTIVE_URL:
120     *param_charp = data->state.url?data->state.url:(char *)"";
121     break;
122   case CURLINFO_EFFECTIVE_METHOD: {
123     const char *m = data->set.str[STRING_CUSTOMREQUEST];
124     if(!m) {
125       if(data->set.opt_no_body)
126         m = "HEAD";
127 #ifndef CURL_DISABLE_HTTP
128       else {
129         switch(data->state.httpreq) {
130         case HTTPREQ_POST:
131         case HTTPREQ_POST_FORM:
132         case HTTPREQ_POST_MIME:
133           m = "POST";
134           break;
135         case HTTPREQ_PUT:
136           m = "PUT";
137           break;
138         default: /* this should never happen */
139         case HTTPREQ_GET:
140           m = "GET";
141           break;
142         case HTTPREQ_HEAD:
143           m = "HEAD";
144           break;
145         }
146       }
147 #endif
148     }
149     *param_charp = m;
150   }
151     break;
152   case CURLINFO_CONTENT_TYPE:
153     *param_charp = data->info.contenttype;
154     break;
155   case CURLINFO_PRIVATE:
156     *param_charp = (char *) data->set.private_data;
157     break;
158   case CURLINFO_FTP_ENTRY_PATH:
159     /* Return the entrypath string from the most recent connection.
160        This pointer was copied from the connectdata structure by FTP.
161        The actual string may be free()ed by subsequent libcurl calls so
162        it must be copied to a safer area before the next libcurl call.
163        Callers must never free it themselves. */
164     *param_charp = data->state.most_recent_ftp_entrypath;
165     break;
166   case CURLINFO_REDIRECT_URL:
167     /* Return the URL this request would have been redirected to if that
168        option had been enabled! */
169     *param_charp = data->info.wouldredirect;
170     break;
171   case CURLINFO_REFERER:
172     /* Return the referrer header for this request, or NULL if unset */
173     *param_charp = data->state.referer;
174     break;
175   case CURLINFO_PRIMARY_IP:
176     /* Return the ip address of the most recent (primary) connection */
177     *param_charp = data->info.primary.remote_ip;
178     break;
179   case CURLINFO_LOCAL_IP:
180     /* Return the source/local ip address of the most recent (primary)
181        connection */
182     *param_charp = data->info.primary.local_ip;
183     break;
184   case CURLINFO_RTSP_SESSION_ID:
185 #ifndef CURL_DISABLE_RTSP
186     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
187 #else
188     *param_charp = NULL;
189 #endif
190     break;
191   case CURLINFO_SCHEME:
192     *param_charp = data->info.conn_scheme;
193     break;
194   case CURLINFO_CAPATH:
195 #ifdef CURL_CA_PATH
196     *param_charp = CURL_CA_PATH;
197 #else
198     *param_charp = NULL;
199 #endif
200     break;
201   case CURLINFO_CAINFO:
202 #ifdef CURL_CA_BUNDLE
203     *param_charp = CURL_CA_BUNDLE;
204 #else
205     *param_charp = NULL;
206 #endif
207     break;
208   default:
209     return CURLE_UNKNOWN_OPTION;
210   }
211 
212   return CURLE_OK;
213 }
214 
getinfo_long(struct Curl_easy * data,CURLINFO info,long * param_longp)215 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
216                              long *param_longp)
217 {
218   curl_socket_t sockfd;
219 
220   union {
221     unsigned long *to_ulong;
222     long          *to_long;
223   } lptr;
224 
225 #ifdef DEBUGBUILD
226   char *timestr = getenv("CURL_TIME");
227   if(timestr) {
228     unsigned long val = strtol(timestr, NULL, 10);
229     switch(info) {
230     case CURLINFO_LOCAL_PORT:
231       *param_longp = (long)val;
232       return CURLE_OK;
233     default:
234       break;
235     }
236   }
237   /* use another variable for this to allow different values */
238   timestr = getenv("CURL_DEBUG_SIZE");
239   if(timestr) {
240     unsigned long val = strtol(timestr, NULL, 10);
241     switch(info) {
242     case CURLINFO_HEADER_SIZE:
243     case CURLINFO_REQUEST_SIZE:
244       *param_longp = (long)val;
245       return CURLE_OK;
246     default:
247       break;
248     }
249   }
250 #endif
251 
252   switch(info) {
253   case CURLINFO_TCP_CONNECT_ERRNO:
254     *param_longp = data->tcp_connect_errno;
255     break;
256   case CURLINFO_SSL_CONNECT_ERRNO:
257     *param_longp = data->ssl_connect_errno;
258     break;
259   case CURLINFO_LAST_POLLIN_TIME:
260     *param_longp = 1000 * data->last_pollin_time.tv_sec + data->last_pollin_time.tv_usec / 1000;
261     break;
262   case CURLINFO_LAST_OS_POLLIN_TIME:
263     *param_longp = 1000 * data->last_os_pollin_time.tv_sec + data->last_os_pollin_time.tv_usec / 1000;
264     break;
265   case CURLINFO_LAST_POLLOUT_TIME:
266     *param_longp = 1000 * data->last_pollout_time.tv_sec + data->last_pollout_time.tv_usec / 1000;
267     break;
268   case CURLINFO_LAST_OS_POLLOUT_TIME:
269     *param_longp = 1000 * data->last_os_pollout_time.tv_sec + data->last_os_pollout_time.tv_usec / 1000;
270     break;
271   case CURLINFO_LAST_SSL_RECV_SIZE:
272     *param_longp = data->last_ssl_recv_size;
273     break;
274   case CURLINFO_LAST_SSL_SEND_SIZE:
275     *param_longp = data->last_ssl_send_size;
276     break;
277   case CURLINFO_TOTAL_SSL_RECV_SIZE:
278     *param_longp = data->total_ssl_recv_size;
279     break;
280   case CURLINFO_TOTAL_SSL_SEND_SIZE:
281     *param_longp = data->total_ssl_send_size;
282     break;
283   case CURLINFO_LAST_RECV_ERRNO:
284     *param_longp = data->last_recv_errno;
285     break;
286   case CURLINFO_LAST_SEND_ERRNO:
287     *param_longp = data->last_send_errno;
288     break;
289   case CURLINFO_CIPHER_NUM:
290     *param_longp = data->cipher_num;
291     break;
292   case CURLINFO_MIN_TLS_VERSION:
293     *param_longp = data->min_tls_version;
294     break;
295   case CURLINFO_MAX_TLS_VERSION:
296     *param_longp = data->max_tls_version;
297     break;
298   case CURLINFO_RESPONSE_CODE:
299     *param_longp = data->info.httpcode;
300     break;
301   case CURLINFO_HTTP_CONNECTCODE:
302     *param_longp = data->info.httpproxycode;
303     break;
304   case CURLINFO_FILETIME:
305     if(data->info.filetime > LONG_MAX)
306       *param_longp = LONG_MAX;
307     else if(data->info.filetime < LONG_MIN)
308       *param_longp = LONG_MIN;
309     else
310       *param_longp = (long)data->info.filetime;
311     break;
312   case CURLINFO_HEADER_SIZE:
313     *param_longp = (long)data->info.header_size;
314     break;
315   case CURLINFO_REQUEST_SIZE:
316     *param_longp = (long)data->info.request_size;
317     break;
318   case CURLINFO_SSL_VERIFYRESULT:
319     *param_longp = data->set.ssl.certverifyresult;
320     break;
321 #ifndef CURL_DISABLE_PROXY
322   case CURLINFO_PROXY_SSL_VERIFYRESULT:
323     *param_longp = data->set.proxy_ssl.certverifyresult;
324     break;
325 #endif
326   case CURLINFO_REDIRECT_COUNT:
327     *param_longp = data->state.followlocation;
328     break;
329   case CURLINFO_HTTPAUTH_AVAIL:
330     lptr.to_long = param_longp;
331     *lptr.to_ulong = data->info.httpauthavail;
332     break;
333   case CURLINFO_PROXYAUTH_AVAIL:
334     lptr.to_long = param_longp;
335     *lptr.to_ulong = data->info.proxyauthavail;
336     break;
337   case CURLINFO_OS_ERRNO:
338     *param_longp = data->state.os_errno;
339     break;
340   case CURLINFO_NUM_CONNECTS:
341     *param_longp = data->info.numconnects;
342     break;
343   case CURLINFO_LASTSOCKET:
344     sockfd = Curl_getconnectinfo(data, NULL);
345 
346     /* note: this is not a good conversion for systems with 64 bit sockets and
347        32 bit longs */
348     if(sockfd != CURL_SOCKET_BAD)
349       *param_longp = (long)sockfd;
350     else
351       /* this interface is documented to return -1 in case of badness, which
352          may not be the same as the CURL_SOCKET_BAD value */
353       *param_longp = -1;
354     break;
355   case CURLINFO_PRIMARY_PORT:
356     /* Return the (remote) port of the most recent (primary) connection */
357     *param_longp = data->info.primary.remote_port;
358     break;
359   case CURLINFO_LOCAL_PORT:
360     /* Return the local port of the most recent (primary) connection */
361     *param_longp = data->info.primary.local_port;
362     break;
363   case CURLINFO_PROXY_ERROR:
364     *param_longp = (long)data->info.pxcode;
365     break;
366   case CURLINFO_CONDITION_UNMET:
367     if(data->info.httpcode == 304)
368       *param_longp = 1L;
369     else
370       /* return if the condition prevented the document to get transferred */
371       *param_longp = data->info.timecond ? 1L : 0L;
372     break;
373 #ifndef CURL_DISABLE_RTSP
374   case CURLINFO_RTSP_CLIENT_CSEQ:
375     *param_longp = data->state.rtsp_next_client_CSeq;
376     break;
377   case CURLINFO_RTSP_SERVER_CSEQ:
378     *param_longp = data->state.rtsp_next_server_CSeq;
379     break;
380   case CURLINFO_RTSP_CSEQ_RECV:
381     *param_longp = data->state.rtsp_CSeq_recv;
382     break;
383 #endif
384   case CURLINFO_HTTP_VERSION:
385     switch(data->info.httpversion) {
386     case 10:
387       *param_longp = CURL_HTTP_VERSION_1_0;
388       break;
389     case 11:
390       *param_longp = CURL_HTTP_VERSION_1_1;
391       break;
392     case 20:
393       *param_longp = CURL_HTTP_VERSION_2_0;
394       break;
395     case 30:
396       *param_longp = CURL_HTTP_VERSION_3;
397       break;
398     default:
399       *param_longp = CURL_HTTP_VERSION_NONE;
400       break;
401     }
402     break;
403   case CURLINFO_PROTOCOL:
404     *param_longp = data->info.conn_protocol;
405     break;
406   case CURLINFO_USED_PROXY:
407     *param_longp =
408 #ifdef CURL_DISABLE_PROXY
409       0
410 #else
411       data->info.used_proxy
412 #endif
413       ;
414     break;
415   default:
416     return CURLE_UNKNOWN_OPTION;
417   }
418 
419   return CURLE_OK;
420 }
421 
422 #define DOUBLE_SECS(x) (double)(x)/1000000
423 
getinfo_offt(struct Curl_easy * data,CURLINFO info,curl_off_t * param_offt)424 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
425                              curl_off_t *param_offt)
426 {
427 #ifdef DEBUGBUILD
428   char *timestr = getenv("CURL_TIME");
429   if(timestr) {
430     unsigned long val = strtol(timestr, NULL, 10);
431     switch(info) {
432     case CURLINFO_TOTAL_TIME_T:
433     case CURLINFO_NAMELOOKUP_TIME_T:
434     case CURLINFO_CONNECT_TIME_T:
435     case CURLINFO_APPCONNECT_TIME_T:
436     case CURLINFO_PRETRANSFER_TIME_T:
437     case CURLINFO_STARTTRANSFER_TIME_T:
438     case CURLINFO_REDIRECT_TIME_T:
439     case CURLINFO_SPEED_DOWNLOAD_T:
440     case CURLINFO_SPEED_UPLOAD_T:
441       *param_offt = (curl_off_t)val;
442       return CURLE_OK;
443     default:
444       break;
445     }
446   }
447 #endif
448   switch(info) {
449   case CURLINFO_FILETIME_T:
450     *param_offt = (curl_off_t)data->info.filetime;
451     break;
452   case CURLINFO_SIZE_UPLOAD_T:
453     *param_offt = data->progress.uploaded;
454     break;
455   case CURLINFO_SIZE_DOWNLOAD_T:
456     *param_offt = data->progress.downloaded;
457     break;
458   case CURLINFO_SPEED_DOWNLOAD_T:
459     *param_offt = data->progress.dlspeed;
460     break;
461   case CURLINFO_SPEED_UPLOAD_T:
462     *param_offt = data->progress.ulspeed;
463     break;
464   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
465     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
466       data->progress.size_dl:-1;
467     break;
468   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
469     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
470       data->progress.size_ul:-1;
471     break;
472    case CURLINFO_TOTAL_TIME_T:
473     *param_offt = data->progress.timespent;
474     break;
475   case CURLINFO_NAMELOOKUP_TIME_T:
476     *param_offt = data->progress.t_nslookup;
477     break;
478   case CURLINFO_CONNECT_TIME_T:
479     *param_offt = data->progress.t_connect;
480     break;
481   case CURLINFO_APPCONNECT_TIME_T:
482     *param_offt = data->progress.t_appconnect;
483     break;
484   case CURLINFO_PRETRANSFER_TIME_T:
485     *param_offt = data->progress.t_pretransfer;
486     break;
487   case CURLINFO_STARTTRANSFER_TIME_T:
488     *param_offt = data->progress.t_starttransfer;
489     break;
490   case CURLINFO_QUEUE_TIME_T:
491     *param_offt = data->progress.t_postqueue;
492     break;
493   case CURLINFO_REDIRECT_TIME_T:
494     *param_offt = data->progress.t_redirect;
495     break;
496   case CURLINFO_RETRY_AFTER:
497     *param_offt = data->info.retry_after;
498     break;
499   case CURLINFO_XFER_ID:
500     *param_offt = data->id;
501     break;
502   case CURLINFO_CONN_ID:
503     *param_offt = data->conn?
504       data->conn->connection_id : data->state.recent_conn_id;
505     break;
506   default:
507     return CURLE_UNKNOWN_OPTION;
508   }
509 
510   return CURLE_OK;
511 }
512 
getinfo_double(struct Curl_easy * data,CURLINFO info,double * param_doublep)513 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
514                                double *param_doublep)
515 {
516 #ifdef DEBUGBUILD
517   char *timestr = getenv("CURL_TIME");
518   if(timestr) {
519     unsigned long val = strtol(timestr, NULL, 10);
520     switch(info) {
521     case CURLINFO_TOTAL_TIME:
522     case CURLINFO_NAMELOOKUP_TIME:
523     case CURLINFO_CONNECT_TIME:
524     case CURLINFO_APPCONNECT_TIME:
525     case CURLINFO_PRETRANSFER_TIME:
526     case CURLINFO_STARTTRANSFER_TIME:
527     case CURLINFO_REDIRECT_TIME:
528     case CURLINFO_SPEED_DOWNLOAD:
529     case CURLINFO_SPEED_UPLOAD:
530       *param_doublep = (double)val;
531       return CURLE_OK;
532     default:
533       break;
534     }
535   }
536 #endif
537   switch(info) {
538   case CURLINFO_TOTAL_TIME:
539     *param_doublep = DOUBLE_SECS(data->progress.timespent);
540     break;
541   case CURLINFO_NAMELOOKUP_TIME:
542     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
543     break;
544   case CURLINFO_CONNECT_TIME:
545     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
546     break;
547   case CURLINFO_APPCONNECT_TIME:
548     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
549     break;
550   case CURLINFO_PRETRANSFER_TIME:
551     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
552     break;
553   case CURLINFO_STARTTRANSFER_TIME:
554     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
555     break;
556   case CURLINFO_SIZE_UPLOAD:
557     *param_doublep = (double)data->progress.uploaded;
558     break;
559   case CURLINFO_SIZE_DOWNLOAD:
560     *param_doublep = (double)data->progress.downloaded;
561     break;
562   case CURLINFO_SPEED_DOWNLOAD:
563     *param_doublep = (double)data->progress.dlspeed;
564     break;
565   case CURLINFO_SPEED_UPLOAD:
566     *param_doublep = (double)data->progress.ulspeed;
567     break;
568   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
569     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
570       (double)data->progress.size_dl:-1;
571     break;
572   case CURLINFO_CONTENT_LENGTH_UPLOAD:
573     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
574       (double)data->progress.size_ul:-1;
575     break;
576   case CURLINFO_REDIRECT_TIME:
577     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
578     break;
579 
580   default:
581     return CURLE_UNKNOWN_OPTION;
582   }
583 
584   return CURLE_OK;
585 }
586 
getinfo_slist(struct Curl_easy * data,CURLINFO info,struct curl_slist ** param_slistp)587 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
588                               struct curl_slist **param_slistp)
589 {
590   union {
591     struct curl_certinfo *to_certinfo;
592     struct curl_slist    *to_slist;
593   } ptr;
594 
595   switch(info) {
596   case CURLINFO_SSL_ENGINES:
597     *param_slistp = Curl_ssl_engines_list(data);
598     break;
599   case CURLINFO_COOKIELIST:
600     *param_slistp = Curl_cookie_list(data);
601     break;
602   case CURLINFO_CERTINFO:
603     /* Return the a pointer to the certinfo struct. Not really an slist
604        pointer but we can pretend it is here */
605     ptr.to_certinfo = &data->info.certs;
606     *param_slistp = ptr.to_slist;
607     break;
608   case CURLINFO_TLS_SESSION:
609   case CURLINFO_TLS_SSL_PTR:
610     {
611       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
612                                           param_slistp;
613       struct curl_tlssessioninfo *tsi = &data->tsi;
614 #ifdef USE_SSL
615       struct connectdata *conn = data->conn;
616 #endif
617 
618       *tsip = tsi;
619       tsi->backend = Curl_ssl_backend();
620       tsi->internals = NULL;
621 
622 #ifdef USE_SSL
623       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
624         tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
625       }
626 #endif
627     }
628     break;
629   default:
630     return CURLE_UNKNOWN_OPTION;
631   }
632 
633   return CURLE_OK;
634 }
635 
getinfo_socket(struct Curl_easy * data,CURLINFO info,curl_socket_t * param_socketp)636 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
637                                curl_socket_t *param_socketp)
638 {
639   switch(info) {
640   case CURLINFO_ACTIVESOCKET:
641     *param_socketp = Curl_getconnectinfo(data, NULL);
642     break;
643   default:
644     return CURLE_UNKNOWN_OPTION;
645   }
646 
647   return CURLE_OK;
648 }
649 
Curl_getinfo(struct Curl_easy * data,CURLINFO info,...)650 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
651 {
652   va_list arg;
653   long *param_longp = NULL;
654   double *param_doublep = NULL;
655   curl_off_t *param_offt = NULL;
656   const char **param_charp = NULL;
657   const char ***param_pcharp = NULL;
658   struct curl_slist **param_slistp = NULL;
659   curl_socket_t *param_socketp = NULL;
660   int type;
661   CURLcode result = CURLE_UNKNOWN_OPTION;
662 
663   if(!data)
664     return CURLE_BAD_FUNCTION_ARGUMENT;
665 
666   va_start(arg, info);
667 
668   type = CURLINFO_TYPEMASK & (int)info;
669   switch(type) {
670   case CURLINFO_P_STRING:
671     param_pcharp = va_arg(arg, const char ***);
672     if(param_pcharp)
673       result = getinfo_pchar(data, info, param_pcharp);
674     break;
675   case CURLINFO_STRING:
676     param_charp = va_arg(arg, const char **);
677     if(param_charp)
678       result = getinfo_char(data, info, param_charp);
679     break;
680   case CURLINFO_LONG:
681     param_longp = va_arg(arg, long *);
682     if(param_longp)
683       result = getinfo_long(data, info, param_longp);
684     break;
685   case CURLINFO_DOUBLE:
686     param_doublep = va_arg(arg, double *);
687     if(param_doublep)
688       result = getinfo_double(data, info, param_doublep);
689     break;
690   case CURLINFO_OFF_T:
691     param_offt = va_arg(arg, curl_off_t *);
692     if(param_offt)
693       result = getinfo_offt(data, info, param_offt);
694     break;
695   case CURLINFO_SLIST:
696     param_slistp = va_arg(arg, struct curl_slist **);
697     if(param_slistp)
698       result = getinfo_slist(data, info, param_slistp);
699     break;
700   case CURLINFO_SOCKET:
701     param_socketp = va_arg(arg, curl_socket_t *);
702     if(param_socketp)
703       result = getinfo_socket(data, info, param_socketp);
704     break;
705   default:
706     break;
707   }
708 
709   va_end(arg);
710 
711   return result;
712 }
713