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 #ifndef ARRAYSIZE
57 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
58 #endif
59
Curl_debug(struct Curl_easy * data,curl_infotype type,char * ptr,size_t size)60 void Curl_debug(struct Curl_easy *data, curl_infotype type,
61 char *ptr, size_t size)
62 {
63 if(data->set.verbose) {
64 static const char s_infotype[CURLINFO_END][3] = {
65 "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
66 if(data->set.fdebug) {
67 bool inCallback = Curl_is_in_callback(data);
68 Curl_set_in_callback(data, TRUE);
69 (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
70 Curl_set_in_callback(data, inCallback);
71 }
72 else {
73 switch(type) {
74 case CURLINFO_TEXT:
75 case CURLINFO_HEADER_OUT:
76 case CURLINFO_HEADER_IN:
77 fwrite(s_infotype[type], 2, 1, data->set.err);
78 fwrite(ptr, size, 1, data->set.err);
79 break;
80 default: /* nada */
81 break;
82 }
83 }
84 }
85 }
86
87
88 /* Curl_failf() is for messages stating why we failed.
89 * The message SHALL NOT include any LF or CR.
90 */
Curl_failf(struct Curl_easy * data,const char * fmt,...)91 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
92 {
93 DEBUGASSERT(!strchr(fmt, '\n'));
94 if(data->set.verbose || data->set.errorbuffer) {
95 va_list ap;
96 int len;
97 char error[CURL_ERROR_SIZE + 2];
98 va_start(ap, fmt);
99 len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
100
101 if(data->set.errorbuffer && !data->state.errorbuf) {
102 strcpy(data->set.errorbuffer, error);
103 data->state.errorbuf = TRUE; /* wrote error string */
104 }
105 error[len++] = '\n';
106 error[len] = '\0';
107 Curl_debug(data, CURLINFO_TEXT, error, len);
108 va_end(ap);
109 }
110 }
111
112 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
113
114 /* Curl_infof() is for info message along the way */
115 #define MAXINFO 2048
116
117 static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
118 const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
119
trc_infof(struct Curl_easy * data,struct curl_trc_feat * feat,const char * const fmt,va_list ap)120 static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
121 const char * const fmt, va_list ap)
122 {
123 int len = 0;
124 char buffer[MAXINFO + 5];
125 if(feat)
126 len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
127 len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
128 if(len >= MAXINFO) { /* too long, shorten with '...' */
129 --len;
130 buffer[len++] = '.';
131 buffer[len++] = '.';
132 buffer[len++] = '.';
133 }
134 buffer[len++] = '\n';
135 buffer[len] = '\0';
136 Curl_debug(data, CURLINFO_TEXT, buffer, len);
137 }
138
Curl_infof(struct Curl_easy * data,const char * fmt,...)139 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
140 {
141 DEBUGASSERT(!strchr(fmt, '\n'));
142 if(Curl_trc_is_verbose(data)) {
143 va_list ap;
144 va_start(ap, fmt);
145 trc_infof(data, data->state.feat, fmt, ap);
146 va_end(ap);
147 }
148 }
149
Curl_trc_cf_infof(struct Curl_easy * data,struct Curl_cfilter * cf,const char * fmt,...)150 void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
151 const char *fmt, ...)
152 {
153 DEBUGASSERT(cf);
154 if(Curl_trc_cf_is_verbose(cf, data)) {
155 va_list ap;
156 int len = 0;
157 char buffer[MAXINFO + 2];
158 if(data->state.feat)
159 len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
160 data->state.feat->name);
161 if(cf->sockindex)
162 len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
163 cf->cft->name, cf->sockindex);
164 else
165 len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
166 va_start(ap, fmt);
167 len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
168 va_end(ap);
169 buffer[len++] = '\n';
170 buffer[len] = '\0';
171 Curl_debug(data, CURLINFO_TEXT, buffer, len);
172 }
173 }
174
175 struct curl_trc_feat Curl_trc_feat_read = {
176 "READ",
177 CURL_LOG_LVL_NONE,
178 };
179 struct curl_trc_feat Curl_trc_feat_write = {
180 "WRITE",
181 CURL_LOG_LVL_NONE,
182 };
183
Curl_trc_read(struct Curl_easy * data,const char * fmt,...)184 void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
185 {
186 DEBUGASSERT(!strchr(fmt, '\n'));
187 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
188 va_list ap;
189 va_start(ap, fmt);
190 trc_infof(data, &Curl_trc_feat_read, fmt, ap);
191 va_end(ap);
192 }
193 }
194
Curl_trc_write(struct Curl_easy * data,const char * fmt,...)195 void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
196 {
197 DEBUGASSERT(!strchr(fmt, '\n'));
198 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
199 va_list ap;
200 va_start(ap, fmt);
201 trc_infof(data, &Curl_trc_feat_write, fmt, ap);
202 va_end(ap);
203 }
204 }
205
206 #ifndef CURL_DISABLE_FTP
207 struct curl_trc_feat Curl_trc_feat_ftp = {
208 "FTP",
209 CURL_LOG_LVL_NONE,
210 };
211
Curl_trc_ftp(struct Curl_easy * data,const char * fmt,...)212 void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
213 {
214 DEBUGASSERT(!strchr(fmt, '\n'));
215 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
216 va_list ap;
217 va_start(ap, fmt);
218 trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
219 va_end(ap);
220 }
221 }
222 #endif /* !CURL_DISABLE_FTP */
223
224 #ifndef CURL_DISABLE_SMTP
225 struct curl_trc_feat Curl_trc_feat_smtp = {
226 "SMTP",
227 CURL_LOG_LVL_NONE,
228 };
229
Curl_trc_smtp(struct Curl_easy * data,const char * fmt,...)230 void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
231 {
232 DEBUGASSERT(!strchr(fmt, '\n'));
233 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
234 va_list ap;
235 va_start(ap, fmt);
236 trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
237 va_end(ap);
238 }
239 }
240 #endif /* !CURL_DISABLE_SMTP */
241
242 #ifdef USE_SSL
243 struct curl_trc_feat Curl_trc_feat_ssls = {
244 "SSLS",
245 CURL_LOG_LVL_NONE,
246 };
247
Curl_trc_ssls(struct Curl_easy * data,const char * fmt,...)248 void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
249 {
250 DEBUGASSERT(!strchr(fmt, '\n'));
251 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
252 va_list ap;
253 va_start(ap, fmt);
254 trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
255 va_end(ap);
256 }
257 }
258 #endif /* USE_SSL */
259
260 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
261 struct curl_trc_feat Curl_trc_feat_ws = {
262 "WS",
263 CURL_LOG_LVL_NONE,
264 };
265
Curl_trc_ws(struct Curl_easy * data,const char * fmt,...)266 void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
267 {
268 DEBUGASSERT(!strchr(fmt, '\n'));
269 if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
270 va_list ap;
271 va_start(ap, fmt);
272 trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
273 va_end(ap);
274 }
275 }
276 #endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
277
278 #define TRC_CT_NONE (0)
279 #define TRC_CT_PROTOCOL (1<<(0))
280 #define TRC_CT_NETWORK (1<<(1))
281 #define TRC_CT_PROXY (1<<(2))
282
283 struct trc_feat_def {
284 struct curl_trc_feat *feat;
285 unsigned int category;
286 };
287
288 static struct trc_feat_def trc_feats[] = {
289 { &Curl_trc_feat_read, TRC_CT_NONE },
290 { &Curl_trc_feat_write, TRC_CT_NONE },
291 #ifndef CURL_DISABLE_FTP
292 { &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
293 #endif
294 #ifndef CURL_DISABLE_DOH
295 { &Curl_doh_trc, TRC_CT_NETWORK },
296 #endif
297 #ifndef CURL_DISABLE_SMTP
298 { &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
299 #endif
300 #ifdef USE_SSL
301 { &Curl_trc_feat_ssls, TRC_CT_NETWORK },
302 #endif
303 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
304 { &Curl_trc_feat_ws, TRC_CT_PROTOCOL },
305 #endif
306 };
307
308 struct trc_cft_def {
309 struct Curl_cftype *cft;
310 unsigned int category;
311 };
312
313 static struct trc_cft_def trc_cfts[] = {
314 { &Curl_cft_tcp, TRC_CT_NETWORK },
315 { &Curl_cft_udp, TRC_CT_NETWORK },
316 { &Curl_cft_unix, TRC_CT_NETWORK },
317 { &Curl_cft_tcp_accept, TRC_CT_NETWORK },
318 { &Curl_cft_happy_eyeballs, TRC_CT_NETWORK },
319 { &Curl_cft_setup, TRC_CT_PROTOCOL },
320 #ifdef USE_NGHTTP2
321 { &Curl_cft_nghttp2, TRC_CT_PROTOCOL },
322 #endif
323 #ifdef USE_SSL
324 { &Curl_cft_ssl, TRC_CT_NETWORK },
325 #ifndef CURL_DISABLE_PROXY
326 { &Curl_cft_ssl_proxy, TRC_CT_PROXY },
327 #endif
328 #endif
329 #if !defined(CURL_DISABLE_PROXY)
330 #if !defined(CURL_DISABLE_HTTP)
331 { &Curl_cft_h1_proxy, TRC_CT_PROXY },
332 #ifdef USE_NGHTTP2
333 { &Curl_cft_h2_proxy, TRC_CT_PROXY },
334 #endif
335 { &Curl_cft_http_proxy, TRC_CT_PROXY },
336 #endif /* !CURL_DISABLE_HTTP */
337 { &Curl_cft_haproxy, TRC_CT_PROXY },
338 { &Curl_cft_socks_proxy, TRC_CT_PROXY },
339 #endif /* !CURL_DISABLE_PROXY */
340 #ifdef USE_HTTP3
341 { &Curl_cft_http3, TRC_CT_PROTOCOL },
342 #endif
343 #if !defined(CURL_DISABLE_HTTP)
344 { &Curl_cft_http_connect, TRC_CT_PROTOCOL },
345 #endif
346 };
347
trc_apply_level_by_name(const char * const token,int lvl)348 static void trc_apply_level_by_name(const char * const token, int lvl)
349 {
350 size_t i;
351
352 for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
353 if(strcasecompare(token, trc_cfts[i].cft->name)) {
354 trc_cfts[i].cft->log_level = lvl;
355 break;
356 }
357 }
358 for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
359 if(strcasecompare(token, trc_feats[i].feat->name)) {
360 trc_feats[i].feat->log_level = lvl;
361 break;
362 }
363 }
364 }
365
trc_apply_level_by_category(int category,int lvl)366 static void trc_apply_level_by_category(int category, int lvl)
367 {
368 size_t i;
369
370 for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
371 if(!category || (trc_cfts[i].category & category))
372 trc_cfts[i].cft->log_level = lvl;
373 }
374 for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
375 if(!category || (trc_feats[i].category & category))
376 trc_feats[i].feat->log_level = lvl;
377 }
378 }
379
trc_opt(const char * config)380 static CURLcode trc_opt(const char *config)
381 {
382 char *token, *tok_buf, *tmp;
383 int lvl;
384
385 tmp = strdup(config);
386 if(!tmp)
387 return CURLE_OUT_OF_MEMORY;
388
389 token = Curl_strtok_r(tmp, ", ", &tok_buf);
390 while(token) {
391 switch(*token) {
392 case '-':
393 lvl = CURL_LOG_LVL_NONE;
394 ++token;
395 break;
396 case '+':
397 lvl = CURL_LOG_LVL_INFO;
398 ++token;
399 break;
400 default:
401 lvl = CURL_LOG_LVL_INFO;
402 break;
403 }
404 if(strcasecompare(token, "all"))
405 trc_apply_level_by_category(TRC_CT_NONE, lvl);
406 else if(strcasecompare(token, "protocol"))
407 trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
408 else if(strcasecompare(token, "network"))
409 trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
410 else if(strcasecompare(token, "proxy"))
411 trc_apply_level_by_category(TRC_CT_PROXY, lvl);
412 else
413 trc_apply_level_by_name(token, lvl);
414
415 token = Curl_strtok_r(NULL, ", ", &tok_buf);
416 }
417 free(tmp);
418 return CURLE_OK;
419 }
420
Curl_trc_opt(const char * config)421 CURLcode Curl_trc_opt(const char *config)
422 {
423 CURLcode result = config ? trc_opt(config) : CURLE_OK;
424 #ifdef DEBUGBUILD
425 /* CURL_DEBUG can override anything */
426 if(!result) {
427 const char *dbg_config = getenv("CURL_DEBUG");
428 if(dbg_config)
429 result = trc_opt(dbg_config);
430 }
431 #endif /* DEBUGBUILD */
432 return result;
433 }
434
Curl_trc_init(void)435 CURLcode Curl_trc_init(void)
436 {
437 #ifdef DEBUGBUILD
438 return Curl_trc_opt(NULL);
439 #else
440 return CURLE_OK;
441 #endif
442 }
443
444 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
445
Curl_trc_init(void)446 CURLcode Curl_trc_init(void)
447 {
448 return CURLE_OK;
449 }
450
Curl_infof(struct Curl_easy * data,const char * fmt,...)451 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
452 {
453 (void)data; (void)fmt;
454 }
455
Curl_trc_cf_infof(struct Curl_easy * data,struct Curl_cfilter * cf,const char * fmt,...)456 void Curl_trc_cf_infof(struct Curl_easy *data,
457 struct Curl_cfilter *cf,
458 const char *fmt, ...)
459 {
460 (void)data; (void)cf; (void)fmt;
461 }
462
463 struct curl_trc_feat;
464
Curl_trc_write(struct Curl_easy * data,const char * fmt,...)465 void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
466 {
467 (void)data; (void)fmt;
468 }
469
Curl_trc_read(struct Curl_easy * data,const char * fmt,...)470 void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
471 {
472 (void)data; (void)fmt;
473 }
474
475 #ifndef CURL_DISABLE_FTP
Curl_trc_ftp(struct Curl_easy * data,const char * fmt,...)476 void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
477 {
478 (void)data; (void)fmt;
479 }
480 #endif
481 #ifndef CURL_DISABLE_SMTP
Curl_trc_smtp(struct Curl_easy * data,const char * fmt,...)482 void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
483 {
484 (void)data; (void)fmt;
485 }
486 #endif
487 #if !defined(CURL_DISABLE_WEBSOCKETS) || !defined(CURL_DISABLE_HTTP)
Curl_trc_ws(struct Curl_easy * data,const char * fmt,...)488 void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
489 {
490 (void)data; (void)fmt;
491 }
492 #endif
493
Curl_trc_ssls(struct Curl_easy * data,const char * fmt,...)494 void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
495 {
496 (void)data;
497 (void)fmt;
498 }
499
500 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
501