• 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 "curl_trc.h"
30 #include "urldata.h"
31 #include "easyif.h"
32 #include "cfilters.h"
33 #include "timeval.h"
34 #include "multiif.h"
35 #include "strcase.h"
36 
37 #include "cf-socket.h"
38 #include "connect.h"
39 #include "doh.h"
40 #include "http2.h"
41 #include "http_proxy.h"
42 #include "cf-h1-proxy.h"
43 #include "cf-h2-proxy.h"
44 #include "cf-haproxy.h"
45 #include "cf-https-connect.h"
46 #include "socks.h"
47 #include "strtok.h"
48 #include "vtls/vtls.h"
49 #include "vquic/vquic.h"
50 
51 /* The last 3 #include files should be in this order */
52 #include "curl_printf.h"
53 #include "curl_memory.h"
54 #include "memdebug.h"
55 
56 
Curl_debug(struct Curl_easy * data,curl_infotype type,char * ptr,size_t size)57 void Curl_debug(struct Curl_easy *data, curl_infotype type,
58                 char *ptr, size_t size)
59 {
60   if(data->set.verbose) {
61     static const char s_infotype[CURLINFO_END][3] = {
62       "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
63     if(data->set.fdebug) {
64       bool inCallback = Curl_is_in_callback(data);
65       Curl_set_in_callback(data, true);
66       (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
67       Curl_set_in_callback(data, inCallback);
68     }
69     else {
70       switch(type) {
71       case CURLINFO_TEXT:
72       case CURLINFO_HEADER_OUT:
73       case CURLINFO_HEADER_IN:
74         fwrite(s_infotype[type], 2, 1, data->set.err);
75         fwrite(ptr, size, 1, data->set.err);
76         break;
77       default: /* nada */
78         break;
79       }
80     }
81   }
82 }
83 
84 
85 /* Curl_failf() is for messages stating why we failed.
86  * The message SHALL NOT include any LF or CR.
87  */
Curl_failf(struct Curl_easy * data,const char * fmt,...)88 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
89 {
90   DEBUGASSERT(!strchr(fmt, '\n'));
91   if(data->set.verbose || data->set.errorbuffer) {
92     va_list ap;
93     int len;
94     char error[CURL_ERROR_SIZE + 2];
95     va_start(ap, fmt);
96     len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
97 
98     if(data->set.errorbuffer && !data->state.errorbuf) {
99       strcpy(data->set.errorbuffer, error);
100       data->state.errorbuf = TRUE; /* wrote error string */
101     }
102     error[len++] = '\n';
103     error[len] = '\0';
104     Curl_debug(data, CURLINFO_TEXT, error, len);
105     va_end(ap);
106   }
107 }
108 
109 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
110 
111 /* Curl_infof() is for info message along the way */
112 #define MAXINFO 2048
113 
114 static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
115                       const char * const fmt, va_list ap)  CURL_PRINTF(3, 0);
116 
trc_infof(struct Curl_easy * data,struct curl_trc_feat * feat,const char * const fmt,va_list ap)117 static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
118                       const char * const fmt, va_list ap)
119 {
120   int len = 0;
121   char buffer[MAXINFO + 2];
122   if(feat)
123     len = msnprintf(buffer, MAXINFO, "[%s] ", feat->name);
124   len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
125   buffer[len++] = '\n';
126   buffer[len] = '\0';
127   Curl_debug(data, CURLINFO_TEXT, buffer, len);
128 }
129 
Curl_infof(struct Curl_easy * data,const char * fmt,...)130 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
131 {
132   DEBUGASSERT(!strchr(fmt, '\n'));
133   if(Curl_trc_is_verbose(data)) {
134     va_list ap;
135     va_start(ap, fmt);
136     trc_infof(data, data->state.feat, fmt, ap);
137     va_end(ap);
138   }
139 }
140 
Curl_trc_cf_infof(struct Curl_easy * data,struct Curl_cfilter * cf,const char * fmt,...)141 void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
142                        const char *fmt, ...)
143 {
144   DEBUGASSERT(cf);
145   if(Curl_trc_cf_is_verbose(cf, data)) {
146     va_list ap;
147     int len = 0;
148     char buffer[MAXINFO + 2];
149     if(data->state.feat)
150       len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
151                        data->state.feat->name);
152     if(cf->sockindex)
153       len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
154                       cf->cft->name, cf->sockindex);
155     else
156       len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
157     va_start(ap, fmt);
158     len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
159     va_end(ap);
160     buffer[len++] = '\n';
161     buffer[len] = '\0';
162     Curl_debug(data, CURLINFO_TEXT, buffer, len);
163   }
164 }
165 
166 struct curl_trc_feat Curl_trc_feat_read = {
167   "READ",
168   CURL_LOG_LVL_NONE,
169 };
170 struct curl_trc_feat Curl_trc_feat_write = {
171   "WRITE",
172   CURL_LOG_LVL_NONE,
173 };
174 
Curl_trc_read(struct Curl_easy * data,const char * fmt,...)175 void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
176 {
177   DEBUGASSERT(!strchr(fmt, '\n'));
178   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
179     va_list ap;
180     va_start(ap, fmt);
181     trc_infof(data, &Curl_trc_feat_read, fmt, ap);
182     va_end(ap);
183   }
184 }
185 
Curl_trc_write(struct Curl_easy * data,const char * fmt,...)186 void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
187 {
188   DEBUGASSERT(!strchr(fmt, '\n'));
189   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
190     va_list ap;
191     va_start(ap, fmt);
192     trc_infof(data, &Curl_trc_feat_write, fmt, ap);
193     va_end(ap);
194   }
195 }
196 
197 #ifndef CURL_DISABLE_FTP
198 struct curl_trc_feat Curl_trc_feat_ftp = {
199   "FTP",
200   CURL_LOG_LVL_NONE,
201 };
202 
Curl_trc_ftp(struct Curl_easy * data,const char * fmt,...)203 void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
204 {
205   DEBUGASSERT(!strchr(fmt, '\n'));
206   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
207     va_list ap;
208     va_start(ap, fmt);
209     trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
210     va_end(ap);
211   }
212 }
213 #endif /* !CURL_DISABLE_FTP */
214 
215 static struct curl_trc_feat *trc_feats[] = {
216   &Curl_trc_feat_read,
217   &Curl_trc_feat_write,
218 #ifndef CURL_DISABLE_FTP
219   &Curl_trc_feat_ftp,
220 #endif
221 #ifndef CURL_DISABLE_DOH
222   &Curl_doh_trc,
223 #endif
224   NULL,
225 };
226 
227 static struct Curl_cftype *cf_types[] = {
228   &Curl_cft_tcp,
229   &Curl_cft_udp,
230   &Curl_cft_unix,
231   &Curl_cft_tcp_accept,
232   &Curl_cft_happy_eyeballs,
233   &Curl_cft_setup,
234 #ifdef USE_NGHTTP2
235   &Curl_cft_nghttp2,
236 #endif
237 #ifdef USE_SSL
238   &Curl_cft_ssl,
239 #ifndef CURL_DISABLE_PROXY
240   &Curl_cft_ssl_proxy,
241 #endif
242 #endif
243 #if !defined(CURL_DISABLE_PROXY)
244 #if !defined(CURL_DISABLE_HTTP)
245   &Curl_cft_h1_proxy,
246 #ifdef USE_NGHTTP2
247   &Curl_cft_h2_proxy,
248 #endif
249   &Curl_cft_http_proxy,
250 #endif /* !CURL_DISABLE_HTTP */
251   &Curl_cft_haproxy,
252   &Curl_cft_socks_proxy,
253 #endif /* !CURL_DISABLE_PROXY */
254 #ifdef USE_HTTP3
255   &Curl_cft_http3,
256 #endif
257 #if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
258   &Curl_cft_http_connect,
259 #endif
260   NULL,
261 };
262 
Curl_trc_opt(const char * config)263 CURLcode Curl_trc_opt(const char *config)
264 {
265   char *token, *tok_buf, *tmp;
266   size_t i;
267   int lvl;
268 
269   tmp = strdup(config);
270   if(!tmp)
271     return CURLE_OUT_OF_MEMORY;
272 
273   token = strtok_r(tmp, ", ", &tok_buf);
274   while(token) {
275     switch(*token) {
276       case '-':
277         lvl = CURL_LOG_LVL_NONE;
278         ++token;
279         break;
280       case '+':
281         lvl = CURL_LOG_LVL_INFO;
282         ++token;
283         break;
284       default:
285         lvl = CURL_LOG_LVL_INFO;
286         break;
287     }
288     for(i = 0; cf_types[i]; ++i) {
289       if(strcasecompare(token, "all")) {
290         cf_types[i]->log_level = lvl;
291       }
292       else if(strcasecompare(token, cf_types[i]->name)) {
293         cf_types[i]->log_level = lvl;
294         break;
295       }
296     }
297     for(i = 0; trc_feats[i]; ++i) {
298       if(strcasecompare(token, "all")) {
299         trc_feats[i]->log_level = lvl;
300       }
301       else if(strcasecompare(token, trc_feats[i]->name)) {
302         trc_feats[i]->log_level = lvl;
303         break;
304       }
305     }
306     token = strtok_r(NULL, ", ", &tok_buf);
307   }
308   free(tmp);
309   return CURLE_OK;
310 }
311 
Curl_trc_init(void)312 CURLcode Curl_trc_init(void)
313 {
314 #ifdef DEBUGBUILD
315   /* WIP: we use the auto-init from an env var only in DEBUG builds for
316    * convenience. */
317   const char *config = getenv("CURL_DEBUG");
318   if(config) {
319     return Curl_trc_opt(config);
320   }
321 #endif /* DEBUGBUILD */
322   return CURLE_OK;
323 }
324 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
325 
Curl_trc_init(void)326 CURLcode Curl_trc_init(void)
327 {
328   return CURLE_OK;
329 }
330 
331 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
332