Coverage Report

Created: 2026-08-31 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/curl_trc.c
Line
Count
Source
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
#include "curl_setup.h"
25
26
#include "curl_trc.h"
27
#include "urldata.h"
28
#include "cfilters.h"
29
#include "multiif.h"
30
31
#include "cf-recvbuf.h"
32
#include "cf-socket.h"
33
#include "cf-setup.h"
34
#include "http2.h"
35
#include "http_proxy.h"
36
#include "cf-h1-proxy.h"
37
#include "cf-h2-proxy.h"
38
#include "cf-haproxy.h"
39
#include "cf-https-connect.h"
40
#include "cf-ip-happy.h"
41
#include "progress.h"
42
#include "socks.h"
43
#include "curlx/strparse.h"
44
#include "vdns/cf-dns.h"
45
#include "vtls/vtls.h"
46
#include "vquic/vquic.h"
47
#include "curlx/strcopy.h"
48
49
static void trc_write(struct Curl_easy *data, curl_infotype type,
50
                      const char *ptr, size_t size)
51
0
{
52
0
  if(data->set.verbose) {
53
0
    if(data->set.fdebug) {
54
0
      struct Curl_mapi_guard guard;
55
0
      CURL_CBAPI_START(&guard, data, easy_fdebug);
56
0
      (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
57
0
                                data->set.debugdata);
58
0
      CURL_CBAPI_END(&guard);
59
0
    }
60
0
    else {
61
0
      static const char s_infotype[CURLINFO_END][3] = {
62
0
        "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
63
0
      switch(type) {
64
0
      case CURLINFO_TEXT:
65
0
      case CURLINFO_HEADER_OUT:
66
0
      case CURLINFO_HEADER_IN:
67
0
        fwrite(s_infotype[type], 2, 1, data->set.err);
68
0
        fwrite(ptr, size, 1, data->set.err);
69
0
        break;
70
0
      default: /* nada */
71
0
        break;
72
0
      }
73
0
    }
74
0
  }
75
0
}
76
77
/* max length we trace before ending in '...' */
78
0
#define TRC_LINE_MAX 2048
79
80
0
#define CURL_TRC_FMT_IDSC   "[x-%" CURL_FORMAT_CURL_OFF_T "] "
81
0
#define CURL_TRC_FMT_IDSD   "[%" CURL_FORMAT_CURL_OFF_T "-x] "
82
0
#define CURL_TRC_FMT_IDSDC  "[%" CURL_FORMAT_CURL_OFF_T "-%" \
83
0
                            CURL_FORMAT_CURL_OFF_T "] "
84
85
static struct curl_trc_feat Curl_trc_feat_ids = {
86
  "LIB-IDS",
87
  CURL_LOG_LVL_NONE,
88
};
89
#define CURL_TRC_IDS(data) \
90
0
  (Curl_trc_is_verbose(data) && \
91
0
  Curl_trc_feat_ids.log_level >= CURL_LOG_LVL_INFO)
92
93
static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
94
0
{
95
0
  curl_off_t cid = data->state.lastconnect_id;
96
0
  if(data->id >= 0) {
97
0
    if(cid >= 0)
98
0
      return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
99
0
    else
100
0
      return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
101
0
  }
102
0
  else if(cid >= 0)
103
0
    return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
104
0
  else {
105
0
    return curl_msnprintf(buf, maxlen, "[x-x] ");
106
0
  }
107
0
}
108
109
static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
110
0
{
111
  /* make sure we end the trace line in `buf` properly. It needs
112
   * to end with a terminating '\0' or '\n\0' */
113
0
  if(len >= (maxlen - (addnl ? 2 : 1))) {
114
0
    len = maxlen - 5;
115
0
    buf[len++] = '.';
116
0
    buf[len++] = '.';
117
0
    buf[len++] = '.';
118
0
    buf[len++] = '\n';
119
0
  }
120
0
  else if(addnl)
121
0
    buf[len++] = '\n';
122
0
  buf[len] = '\0';
123
0
  return len;
124
0
}
125
126
void Curl_debug(struct Curl_easy *data, curl_infotype type,
127
                const char *ptr, size_t size)
128
0
{
129
0
  if(data->set.verbose) {
130
0
    static const char s_infotype[CURLINFO_END][3] = {
131
0
      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
132
0
    char buf[TRC_LINE_MAX];
133
0
    size_t len;
134
0
    if(data->set.fdebug) {
135
0
      struct Curl_mapi_guard guard;
136
0
      if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
137
0
        len = trc_print_ids(data, buf, TRC_LINE_MAX);
138
0
        len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
139
0
                              (int)size, ptr);
140
0
        len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
141
0
        CURL_CBAPI_START(&guard, data, easy_fdebug);
142
0
        (void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
143
0
        CURL_CBAPI_END(&guard);
144
0
      }
145
0
      else {
146
0
        CURL_CBAPI_START(&guard, data, easy_fdebug);
147
0
        (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
148
0
                                  size, data->set.debugdata);
149
0
        CURL_CBAPI_END(&guard);
150
0
      }
151
0
    }
152
0
    else {
153
0
      switch(type) {
154
0
      case CURLINFO_TEXT:
155
0
      case CURLINFO_HEADER_OUT:
156
0
      case CURLINFO_HEADER_IN:
157
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
158
0
        if(CURL_TRC_IDS(data)) {
159
0
          len = trc_print_ids(data, buf, TRC_LINE_MAX);
160
0
          fwrite(buf, len, 1, data->set.err);
161
0
        }
162
0
#endif
163
0
        fwrite(s_infotype[type], 2, 1, data->set.err);
164
0
        fwrite(ptr, size, 1, data->set.err);
165
0
        break;
166
0
      default: /* nada */
167
0
        break;
168
0
      }
169
0
    }
170
0
  }
171
0
}
172
173
/* Curl_failf() is for messages stating why we failed.
174
 * The message SHALL NOT include any LF or CR.
175
 */
176
void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
177
0
{
178
0
  DEBUGASSERT(!strchr(fmt, '\n'));
179
0
  if(data->set.verbose || data->set.errorbuffer) {
180
0
    va_list ap;
181
0
    size_t len;
182
0
    char error[CURL_ERROR_SIZE + 2];
183
0
    va_start(ap, fmt);
184
0
    len = curl_mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
185
186
0
    if(data->set.errorbuffer && !data->state.errorbuf) {
187
0
      curlx_strcopy(data->set.errorbuffer, CURL_ERROR_SIZE, error, len);
188
0
      data->state.errorbuf = TRUE; /* wrote error string */
189
0
    }
190
0
    error[len++] = '\n';
191
0
    error[len] = '\0';
192
0
    trc_write(data, CURLINFO_TEXT, error, len);
193
0
    va_end(ap);
194
0
  }
195
0
}
196
197
void Curl_reset_fail(struct Curl_easy *data)
198
0
{
199
0
  if(data->set.errorbuffer)
200
0
    data->set.errorbuffer[0] = 0;
201
0
  data->state.errorbuf = FALSE;
202
0
}
203
204
#ifdef CURLVERBOSE
205
struct curl_trc_feat Curl_trc_feat_multi = {
206
  "MULTI",
207
  CURL_LOG_LVL_NONE,
208
};
209
struct curl_trc_feat Curl_trc_feat_read = {
210
  "READ",
211
  CURL_LOG_LVL_NONE,
212
};
213
struct curl_trc_feat Curl_trc_feat_write = {
214
  "WRITE",
215
  CURL_LOG_LVL_NONE,
216
};
217
struct curl_trc_feat Curl_trc_feat_dns = {
218
  "DNS",
219
  CURL_LOG_LVL_NONE,
220
};
221
#ifndef CURL_DISABLE_DOH
222
struct curl_trc_feat Curl_trc_feat_doh = {
223
  "DoH",
224
  CURL_LOG_LVL_NONE,
225
};
226
#endif
227
struct curl_trc_feat Curl_trc_feat_timer = {
228
  "TIMER",
229
  CURL_LOG_LVL_NONE,
230
};
231
#ifdef USE_THREADS
232
struct curl_trc_feat Curl_trc_feat_threads = {
233
  "THREADS",
234
  CURL_LOG_LVL_NONE,
235
};
236
#endif
237
#endif
238
239
#ifndef CURL_DISABLE_VERBOSE_STRINGS
240
241
static void trc_infof(struct Curl_easy *data,
242
                      struct curl_trc_feat *feat,
243
                      const char *opt_id, int opt_id_idx,
244
                      const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
245
246
static void trc_infof(struct Curl_easy *data,
247
                      struct curl_trc_feat *feat,
248
                      const char *opt_id, int opt_id_idx,
249
                      const char * const fmt, va_list ap)
250
0
{
251
0
  size_t len = 0;
252
0
  char buf[TRC_LINE_MAX];
253
254
0
  if(CURL_TRC_IDS(data))
255
0
    len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
256
0
  if(feat)
257
0
    len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
258
0
  if(opt_id) {
259
0
    if(opt_id_idx > 0)
260
0
      len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
261
0
                            opt_id, opt_id_idx);
262
0
    else
263
0
      len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
264
0
  }
265
0
  len += curl_mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap);
266
0
  len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE);
267
0
  trc_write(data, CURLINFO_TEXT, buf, len);
268
0
}
269
270
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
271
0
{
272
0
  DEBUGASSERT(!strchr(fmt, '\n'));
273
0
  if(Curl_trc_is_verbose(data)) {
274
0
    va_list ap;
275
0
    va_start(ap, fmt);
276
0
    trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
277
0
    va_end(ap);
278
0
  }
279
0
}
280
281
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
282
                       const char *fmt, ...)
283
0
{
284
0
  DEBUGASSERT(cf);
285
0
  if(Curl_trc_cf_is_verbose(cf, data)) {
286
0
    va_list ap;
287
0
    va_start(ap, fmt);
288
0
    trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
289
0
    va_end(ap);
290
0
  }
291
0
}
292
293
void Curl_trc_feat_infof(struct Curl_easy *data,
294
                         struct curl_trc_feat *feat,
295
                         const char *fmt, ...)
296
0
{
297
0
  DEBUGASSERT(feat);
298
0
  if(Curl_trc_ft_is_verbose(data, feat)) {
299
0
    va_list ap;
300
0
    va_start(ap, fmt);
301
0
    trc_infof(data, feat, NULL, 0, fmt, ap);
302
0
    va_end(ap);
303
0
  }
304
0
}
305
306
static const char * const Curl_trc_timer_names[] = {
307
  "100_TIMEOUT",
308
  "ASYNC_NAME",
309
  "CONNECTTIMEOUT",
310
  "HAPPY_EYEBALLS",
311
  "MULTI_PENDING",
312
  "SPEEDCHECK",
313
  "TIMEOUT",
314
  "TOOFAST",
315
  "QUIC",
316
  "FTP_ACCEPT",
317
  "ALPN_EYEBALLS",
318
  "SHUTDOWN",
319
};
320
321
static const char *trc_timer_name(int tid)
322
0
{
323
0
  if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names)))
324
0
    return Curl_trc_timer_names[(size_t)tid];
325
0
  return "TIMER-???";
326
0
}
327
328
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
329
0
{
330
0
  DEBUGASSERT(!strchr(fmt, '\n'));
331
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)) {
332
0
    const char *tname = trc_timer_name(tid);
333
0
    va_list ap;
334
0
    va_start(ap, fmt);
335
0
    trc_infof(data, &Curl_trc_feat_timer, tname, 0, fmt, ap);
336
0
    va_end(ap);
337
0
  }
338
0
}
339
340
void Curl_trc_easy_timers(struct Curl_easy *data)
341
0
{
342
0
  if(CURL_TRC_TIMER_is_verbose(data) && data->multi) {
343
0
    if(data->state.timeouts.first < EXPIRE_LAST) {
344
0
      struct expire_timers *timeouts = &data->state.timeouts;
345
0
      timediff_t base_us =
346
0
        Curl_timeouts_offset_us(&data->multi->timeouts, Curl_pgrs_now(data));
347
0
      uint8_t id = data->state.timeouts.first;
348
0
      for(; id < EXPIRE_LAST; id = timeouts->next[id]) {
349
0
        CURL_TRC_TIMER(data, id, "expires in %" FMT_TIMEDIFF_T "us",
350
0
                       timeouts->offset_us[id] - base_us);
351
0
      }
352
0
    }
353
0
  }
354
0
}
355
356
static const char * const Curl_trc_mstate_names[] = {
357
  "INIT",
358
  "PENDING",
359
  "SETUP",
360
  "CONNECT",
361
  "CONNECTING",
362
  "PROTOCONNECT",
363
  "PROTOCONNECTING",
364
  "DO",
365
  "DOING",
366
  "DOING_MORE",
367
  "DID",
368
  "PERFORMING",
369
  "RATELIMITING",
370
  "DONE",
371
  "COMPLETED",
372
  "MSGSENT",
373
};
374
375
const char *Curl_trc_mstate_name(int state)
376
0
{
377
0
  if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
378
0
    return Curl_trc_mstate_names[(size_t)state];
379
0
  return "?";
380
0
}
381
382
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
383
0
{
384
0
  DEBUGASSERT(!strchr(fmt, '\n'));
385
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
386
0
    const char *sname = (data->id >= 0) ?
387
0
                        Curl_trc_mstate_name(data->mstate) : NULL;
388
0
    va_list ap;
389
0
    va_start(ap, fmt);
390
0
    trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
391
0
    va_end(ap);
392
0
  }
393
0
}
394
395
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
396
0
{
397
0
  DEBUGASSERT(!strchr(fmt, '\n'));
398
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
399
0
    va_list ap;
400
0
    va_start(ap, fmt);
401
0
    trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
402
0
    va_end(ap);
403
0
  }
404
0
}
405
406
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
407
0
{
408
0
  DEBUGASSERT(!strchr(fmt, '\n'));
409
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
410
0
    va_list ap;
411
0
    va_start(ap, fmt);
412
0
    trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
413
0
    va_end(ap);
414
0
  }
415
0
}
416
417
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
418
0
{
419
0
  DEBUGASSERT(!strchr(fmt, '\n'));
420
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
421
0
    va_list ap;
422
0
    va_start(ap, fmt);
423
0
    trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
424
0
    va_end(ap);
425
0
  }
426
0
}
427
428
#ifndef CURL_DISABLE_FTP
429
struct curl_trc_feat Curl_trc_feat_ftp = {
430
  "FTP",
431
  CURL_LOG_LVL_NONE,
432
};
433
434
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
435
0
{
436
0
  DEBUGASSERT(!strchr(fmt, '\n'));
437
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
438
0
    va_list ap;
439
0
    va_start(ap, fmt);
440
0
    trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
441
0
    va_end(ap);
442
0
  }
443
0
}
444
#endif /* !CURL_DISABLE_FTP */
445
446
#ifndef CURL_DISABLE_SMTP
447
struct curl_trc_feat Curl_trc_feat_smtp = {
448
  "SMTP",
449
  CURL_LOG_LVL_NONE,
450
};
451
452
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
453
0
{
454
0
  DEBUGASSERT(!strchr(fmt, '\n'));
455
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
456
0
    va_list ap;
457
0
    va_start(ap, fmt);
458
0
    trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
459
0
    va_end(ap);
460
0
  }
461
0
}
462
#endif /* !CURL_DISABLE_SMTP */
463
464
#ifdef USE_SSL
465
struct curl_trc_feat Curl_trc_feat_ssls = {
466
  "SSLS",
467
  CURL_LOG_LVL_NONE,
468
};
469
470
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
471
0
{
472
0
  DEBUGASSERT(!strchr(fmt, '\n'));
473
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
474
0
    va_list ap;
475
0
    va_start(ap, fmt);
476
0
    trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
477
0
    va_end(ap);
478
0
  }
479
0
}
480
#endif /* USE_SSL */
481
482
#ifdef USE_SSH
483
struct curl_trc_feat Curl_trc_feat_ssh = {
484
  "SSH",
485
  CURL_LOG_LVL_NONE,
486
};
487
488
void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
489
{
490
  DEBUGASSERT(!strchr(fmt, '\n'));
491
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) {
492
    va_list ap;
493
    va_start(ap, fmt);
494
    trc_infof(data, &Curl_trc_feat_ssh, NULL, 0, fmt, ap);
495
    va_end(ap);
496
  }
497
}
498
#endif /* USE_SSH */
499
500
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
501
struct curl_trc_feat Curl_trc_feat_ws = {
502
  "WS",
503
  CURL_LOG_LVL_NONE,
504
};
505
506
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
507
0
{
508
0
  DEBUGASSERT(!strchr(fmt, '\n'));
509
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
510
0
    va_list ap;
511
0
    va_start(ap, fmt);
512
0
    trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
513
0
    va_end(ap);
514
0
  }
515
0
}
516
#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
517
518
0
#define TRC_CT_NONE        0
519
0
#define TRC_CT_PROTOCOL    (1 << 0)
520
0
#define TRC_CT_NETWORK     (1 << 1)
521
0
#define TRC_CT_PROXY       (1 << 2)
522
#define TRC_CT_INTERNALS   (1 << 3)
523
524
struct trc_feat_def {
525
  struct curl_trc_feat *feat;
526
  unsigned int category;
527
};
528
529
static struct trc_feat_def trc_feats[] = {
530
  { &Curl_trc_feat_ids,       TRC_CT_INTERNALS },
531
  { &Curl_trc_feat_multi,     TRC_CT_NETWORK },
532
  { &Curl_trc_feat_read,      TRC_CT_NONE },
533
  { &Curl_trc_feat_write,     TRC_CT_NONE },
534
  { &Curl_trc_feat_dns,       TRC_CT_NETWORK },
535
#ifndef CURL_DISABLE_DOH
536
  { &Curl_trc_feat_doh,       TRC_CT_NETWORK },
537
#endif
538
  { &Curl_trc_feat_timer,     TRC_CT_NETWORK },
539
#ifdef USE_THREADS
540
  { &Curl_trc_feat_threads,   TRC_CT_NONE },
541
#endif
542
#ifndef CURL_DISABLE_FTP
543
  { &Curl_trc_feat_ftp,       TRC_CT_PROTOCOL },
544
#endif
545
#ifndef CURL_DISABLE_SMTP
546
  { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
547
#endif
548
#ifdef USE_SSL
549
  { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
550
#endif
551
#ifdef USE_SSH
552
  { &Curl_trc_feat_ssh,       TRC_CT_PROTOCOL },
553
#endif
554
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
555
  { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
556
#endif
557
};
558
559
struct trc_cft_def {
560
  struct Curl_cftype *cft;
561
  unsigned int category;
562
};
563
564
static struct trc_cft_def trc_cfts[] = {
565
  { &Curl_cft_dns,            TRC_CT_NETWORK },
566
  { &Curl_cft_tcp,            TRC_CT_NETWORK },
567
  { &Curl_cft_udp,            TRC_CT_NETWORK },
568
  { &Curl_cft_unix,           TRC_CT_NETWORK },
569
  { &Curl_cft_tcp_accept,     TRC_CT_NETWORK },
570
  { &Curl_cft_ip_happy,       TRC_CT_NETWORK },
571
#ifndef CURL_DISABLE_WEBSOCKETS
572
  { &Curl_cft_recvbuf,        TRC_CT_PROTOCOL },
573
#endif
574
  { &Curl_cft_setup,          TRC_CT_PROTOCOL },
575
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
576
  { &Curl_cft_nghttp2,        TRC_CT_PROTOCOL },
577
#endif
578
#ifdef USE_SSL
579
  { &Curl_cft_ssl,            TRC_CT_NETWORK },
580
#ifndef CURL_DISABLE_PROXY
581
  { &Curl_cft_ssl_proxy,      TRC_CT_PROXY },
582
#endif
583
#endif
584
#ifndef CURL_DISABLE_PROXY
585
#ifndef CURL_DISABLE_HTTP
586
  { &Curl_cft_h1_proxy,       TRC_CT_PROXY },
587
#ifdef USE_NGHTTP2
588
  { &Curl_cft_h2_proxy,       TRC_CT_PROXY },
589
#endif
590
#if defined(USE_PROXY_HTTP3) && defined(USE_NGHTTP3)
591
  { &Curl_cft_h3_proxy,       TRC_CT_PROXY },
592
#endif
593
  { &Curl_cft_http_proxy,     TRC_CT_PROXY },
594
#endif /* !CURL_DISABLE_HTTP */
595
  { &Curl_cft_haproxy,        TRC_CT_PROXY },
596
  { &Curl_cft_socks_proxy,    TRC_CT_PROXY },
597
#endif /* !CURL_DISABLE_PROXY */
598
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
599
  { &Curl_cft_http3,          TRC_CT_PROTOCOL },
600
#endif
601
#ifndef CURL_DISABLE_HTTP
602
  { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
603
#endif
604
};
605
606
static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
607
0
{
608
0
  size_t i;
609
610
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
611
0
    if(curlx_str_casecompare(token, trc_cfts[i].cft->name)) {
612
0
      trc_cfts[i].cft->log_level = lvl;
613
0
      break;
614
0
    }
615
0
  }
616
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
617
0
    if(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
618
0
      trc_feats[i].feat->log_level = lvl;
619
0
      break;
620
0
    }
621
0
  }
622
0
}
623
624
static void trc_apply_level_by_category(unsigned int category, int lvl)
625
0
{
626
0
  size_t i;
627
628
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
629
0
    if(!category || (trc_cfts[i].category & category))
630
0
      trc_cfts[i].cft->log_level = lvl;
631
0
  }
632
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
633
0
    if(!category || (trc_feats[i].category & category))
634
0
      trc_feats[i].feat->log_level = lvl;
635
0
  }
636
0
}
637
638
static CURLcode trc_opt(const char *config)
639
0
{
640
0
  struct Curl_str out;
641
0
  while(!curlx_str_until(&config, &out, 32, ',')) {
642
0
    int lvl = CURL_LOG_LVL_INFO;
643
0
    const char *token = curlx_str(&out);
644
645
0
    if(*token == '-') {
646
0
      lvl = CURL_LOG_LVL_NONE;
647
0
      curlx_str_nudge(&out, 1);
648
0
    }
649
0
    else if(*token == '+')
650
0
      curlx_str_nudge(&out, 1);
651
652
0
    if(curlx_str_casecompare(&out, "all"))
653
0
      trc_apply_level_by_category(TRC_CT_NONE, lvl);
654
0
    else if(curlx_str_casecompare(&out, "protocol"))
655
0
      trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
656
0
    else if(curlx_str_casecompare(&out, "network"))
657
0
      trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
658
0
    else if(curlx_str_casecompare(&out, "proxy"))
659
0
      trc_apply_level_by_category(TRC_CT_PROXY, lvl);
660
0
    else
661
0
      trc_apply_level_by_name(&out, lvl);
662
663
0
    if(curlx_str_single(&config, ','))
664
0
      break;
665
0
  }
666
0
  return CURLE_OK;
667
0
}
668
669
CURLcode Curl_trc_opt(const char *config)
670
0
{
671
0
  CURLcode result = config ? trc_opt(config) : CURLE_OK;
672
0
#ifdef DEBUGBUILD
673
  /* CURL_DEBUG can override anything */
674
0
  if(!result) {
675
0
    const char *dbg_config = getenv("CURL_DEBUG");
676
0
    if(dbg_config)
677
0
      result = trc_opt(dbg_config);
678
0
  }
679
0
#endif /* DEBUGBUILD */
680
0
  return result;
681
0
}
682
683
CURLcode Curl_trc_init(void)
684
0
{
685
0
#ifdef DEBUGBUILD
686
0
  return Curl_trc_opt(NULL);
687
#else
688
  return CURLE_OK;
689
#endif
690
0
}
691
692
#else /* CURL_DISABLE_VERBOSE_STRINGS */
693
694
CURLcode Curl_trc_init(void)
695
{
696
  return CURLE_OK;
697
}
698
699
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
700
{
701
  (void)data;
702
  (void)fmt;
703
}
704
705
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
706
                       const char *fmt, ...)
707
{
708
  (void)data;
709
  (void)cf;
710
  (void)fmt;
711
}
712
713
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
714
{
715
  (void)data;
716
  (void)fmt;
717
}
718
719
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
720
{
721
  (void)data;
722
  (void)fmt;
723
}
724
725
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
726
{
727
  (void)data;
728
  (void)fmt;
729
}
730
731
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
732
{
733
  (void)data;
734
  (void)tid;
735
  (void)fmt;
736
}
737
738
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
739
{
740
  (void)data;
741
  (void)fmt;
742
}
743
744
#ifndef CURL_DISABLE_FTP
745
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
746
{
747
  (void)data;
748
  (void)fmt;
749
}
750
#endif
751
#ifndef CURL_DISABLE_SMTP
752
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
753
{
754
  (void)data;
755
  (void)fmt;
756
}
757
#endif
758
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
759
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
760
{
761
  (void)data;
762
  (void)fmt;
763
}
764
#endif
765
#ifdef USE_SSH
766
void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
767
{
768
  (void)data;
769
  (void)fmt;
770
}
771
#endif
772
#ifdef USE_SSL
773
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
774
{
775
  (void)data;
776
  (void)fmt;
777
}
778
#endif
779
780
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */