Coverage Report

Created: 2026-10-15 06:18

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.last_conn_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 null-terminator '\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
  "SERVER_RESPONSE",
320
};
321
322
static const char *trc_timer_name(int tid)
323
0
{
324
0
  if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names)))
325
0
    return Curl_trc_timer_names[(size_t)tid];
326
0
  return "TIMER-???";
327
0
}
328
329
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
330
0
{
331
0
  DEBUGASSERT(!strchr(fmt, '\n'));
332
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)) {
333
0
    const char *tname = trc_timer_name(tid);
334
0
    va_list ap;
335
0
    va_start(ap, fmt);
336
0
    trc_infof(data, &Curl_trc_feat_timer, tname, 0, fmt, ap);
337
0
    va_end(ap);
338
0
  }
339
0
}
340
341
void Curl_trc_easy_timers(struct Curl_easy *data)
342
0
{
343
0
  if(CURL_TRC_TIMER_is_verbose(data) && data->multi) {
344
0
    if(data->state.timeouts.first < EXPIRE_LAST) {
345
0
      struct expire_timers *timeouts = &data->state.timeouts;
346
0
      timediff_t base_us =
347
0
        Curl_timeouts_offset_us(&data->multi->timeouts, Curl_pgrs_now(data));
348
0
      uint8_t id = data->state.timeouts.first;
349
0
      for(; id < EXPIRE_LAST; id = timeouts->next[id]) {
350
0
        CURL_TRC_TIMER(data, id, "expires in %" FMT_TIMEDIFF_T "us",
351
0
                       timeouts->offset_us[id] - base_us);
352
0
      }
353
0
    }
354
0
  }
355
0
}
356
357
static const char * const Curl_trc_mstate_names[] = {
358
  "INIT",
359
  "PENDING",
360
  "SETUP",
361
  "CONNECT",
362
  "CONNECTING",
363
  "PROTOCONNECT",
364
  "PROTOCONNECTING",
365
  "DO",
366
  "DOING",
367
  "DOING_MORE",
368
  "DID",
369
  "PERFORMING",
370
  "RATELIMITING",
371
  "DONE",
372
  "COMPLETED",
373
  "MSGSENT",
374
};
375
376
const char *Curl_trc_mstate_name(int state)
377
0
{
378
0
  if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
379
0
    return Curl_trc_mstate_names[(size_t)state];
380
0
  return "?";
381
0
}
382
383
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
384
0
{
385
0
  DEBUGASSERT(!strchr(fmt, '\n'));
386
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
387
0
    const char *sname = (data->id >= 0) ?
388
0
                        Curl_trc_mstate_name(data->mstate) : NULL;
389
0
    va_list ap;
390
0
    va_start(ap, fmt);
391
0
    trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
392
0
    va_end(ap);
393
0
  }
394
0
}
395
396
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
397
0
{
398
0
  DEBUGASSERT(!strchr(fmt, '\n'));
399
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
400
0
    va_list ap;
401
0
    va_start(ap, fmt);
402
0
    trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
403
0
    va_end(ap);
404
0
  }
405
0
}
406
407
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
408
0
{
409
0
  DEBUGASSERT(!strchr(fmt, '\n'));
410
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
411
0
    va_list ap;
412
0
    va_start(ap, fmt);
413
0
    trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
414
0
    va_end(ap);
415
0
  }
416
0
}
417
418
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
419
0
{
420
0
  DEBUGASSERT(!strchr(fmt, '\n'));
421
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
422
0
    va_list ap;
423
0
    va_start(ap, fmt);
424
0
    trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
425
0
    va_end(ap);
426
0
  }
427
0
}
428
429
#ifndef CURL_DISABLE_FTP
430
struct curl_trc_feat Curl_trc_feat_ftp = {
431
  "FTP",
432
  CURL_LOG_LVL_NONE,
433
};
434
435
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
436
0
{
437
0
  DEBUGASSERT(!strchr(fmt, '\n'));
438
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
439
0
    va_list ap;
440
0
    va_start(ap, fmt);
441
0
    trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
442
0
    va_end(ap);
443
0
  }
444
0
}
445
#endif /* !CURL_DISABLE_FTP */
446
447
#ifndef CURL_DISABLE_SMTP
448
struct curl_trc_feat Curl_trc_feat_smtp = {
449
  "SMTP",
450
  CURL_LOG_LVL_NONE,
451
};
452
453
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
454
0
{
455
0
  DEBUGASSERT(!strchr(fmt, '\n'));
456
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
457
0
    va_list ap;
458
0
    va_start(ap, fmt);
459
0
    trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
460
0
    va_end(ap);
461
0
  }
462
0
}
463
#endif /* !CURL_DISABLE_SMTP */
464
465
#ifdef USE_SSL
466
struct curl_trc_feat Curl_trc_feat_ssls = {
467
  "SSLS",
468
  CURL_LOG_LVL_NONE,
469
};
470
471
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
472
0
{
473
0
  DEBUGASSERT(!strchr(fmt, '\n'));
474
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
475
0
    va_list ap;
476
0
    va_start(ap, fmt);
477
0
    trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
478
0
    va_end(ap);
479
0
  }
480
0
}
481
#endif /* USE_SSL */
482
483
#ifdef USE_SSH
484
struct curl_trc_feat Curl_trc_feat_ssh = {
485
  "SSH",
486
  CURL_LOG_LVL_NONE,
487
};
488
489
void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
490
{
491
  DEBUGASSERT(!strchr(fmt, '\n'));
492
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) {
493
    va_list ap;
494
    va_start(ap, fmt);
495
    trc_infof(data, &Curl_trc_feat_ssh, NULL, 0, fmt, ap);
496
    va_end(ap);
497
  }
498
}
499
#endif /* USE_SSH */
500
501
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
502
struct curl_trc_feat Curl_trc_feat_ws = {
503
  "WS",
504
  CURL_LOG_LVL_NONE,
505
};
506
507
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
508
0
{
509
0
  DEBUGASSERT(!strchr(fmt, '\n'));
510
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
511
0
    va_list ap;
512
0
    va_start(ap, fmt);
513
0
    trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
514
0
    va_end(ap);
515
0
  }
516
0
}
517
#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
518
519
0
#define TRC_CT_NONE        0
520
0
#define TRC_CT_PROTOCOL    (1 << 0)
521
0
#define TRC_CT_NETWORK     (1 << 1)
522
0
#define TRC_CT_PROXY       (1 << 2)
523
#define TRC_CT_INTERNALS   (1 << 3)
524
525
struct trc_feat_def {
526
  struct curl_trc_feat *feat;
527
  unsigned int category;
528
};
529
530
static struct trc_feat_def trc_feats[] = {
531
  { &Curl_trc_feat_ids,       TRC_CT_INTERNALS },
532
  { &Curl_trc_feat_multi,     TRC_CT_NETWORK },
533
  { &Curl_trc_feat_read,      TRC_CT_NONE },
534
  { &Curl_trc_feat_write,     TRC_CT_NONE },
535
  { &Curl_trc_feat_dns,       TRC_CT_NETWORK },
536
#ifndef CURL_DISABLE_DOH
537
  { &Curl_trc_feat_doh,       TRC_CT_NETWORK },
538
#endif
539
  { &Curl_trc_feat_timer,     TRC_CT_NETWORK },
540
#ifdef USE_THREADS
541
  { &Curl_trc_feat_threads,   TRC_CT_NONE },
542
#endif
543
#ifndef CURL_DISABLE_FTP
544
  { &Curl_trc_feat_ftp,       TRC_CT_PROTOCOL },
545
#endif
546
#ifndef CURL_DISABLE_SMTP
547
  { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
548
#endif
549
#ifdef USE_SSL
550
  { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
551
#endif
552
#ifdef USE_SSH
553
  { &Curl_trc_feat_ssh,       TRC_CT_PROTOCOL },
554
#endif
555
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
556
  { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
557
#endif
558
};
559
560
struct trc_cft_def {
561
  struct Curl_cftype *cft;
562
  unsigned int category;
563
};
564
565
static struct trc_cft_def trc_cfts[] = {
566
  { &Curl_cft_dns,            TRC_CT_NETWORK },
567
  { &Curl_cft_tcp,            TRC_CT_NETWORK },
568
  { &Curl_cft_udp,            TRC_CT_NETWORK },
569
  { &Curl_cft_unix,           TRC_CT_NETWORK },
570
  { &Curl_cft_tcp_accept,     TRC_CT_NETWORK },
571
  { &Curl_cft_ip_happy,       TRC_CT_NETWORK },
572
#ifndef CURL_DISABLE_WEBSOCKETS
573
  { &Curl_cft_recvbuf,        TRC_CT_PROTOCOL },
574
#endif
575
  { &Curl_cft_setup,          TRC_CT_PROTOCOL },
576
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
577
  { &Curl_cft_nghttp2,        TRC_CT_PROTOCOL },
578
#endif
579
#ifdef USE_SSL
580
  { &Curl_cft_ssl,            TRC_CT_NETWORK },
581
#ifndef CURL_DISABLE_PROXY
582
  { &Curl_cft_ssl_proxy,      TRC_CT_PROXY },
583
#endif
584
#endif
585
#ifndef CURL_DISABLE_PROXY
586
#ifndef CURL_DISABLE_HTTP
587
  { &Curl_cft_h1_proxy,       TRC_CT_PROXY },
588
#ifdef USE_NGHTTP2
589
  { &Curl_cft_h2_proxy,       TRC_CT_PROXY },
590
#endif
591
#if defined(USE_PROXY_HTTP3) && defined(USE_NGHTTP3)
592
  { &Curl_cft_h3_proxy,       TRC_CT_PROXY },
593
#endif
594
  { &Curl_cft_http_proxy,     TRC_CT_PROXY },
595
#endif /* !CURL_DISABLE_HTTP */
596
  { &Curl_cft_haproxy,        TRC_CT_PROXY },
597
  { &Curl_cft_socks_proxy,    TRC_CT_PROXY },
598
#endif /* !CURL_DISABLE_PROXY */
599
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
600
  { &Curl_cft_http3,          TRC_CT_PROTOCOL },
601
#endif
602
#ifndef CURL_DISABLE_HTTP
603
  { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
604
#endif
605
};
606
607
static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
608
0
{
609
0
  size_t i;
610
611
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
612
0
    if(curlx_str_casecompare(token, trc_cfts[i].cft->name)) {
613
0
      trc_cfts[i].cft->log_level = lvl;
614
0
      break;
615
0
    }
616
0
  }
617
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
618
0
    if(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
619
0
      trc_feats[i].feat->log_level = lvl;
620
0
      break;
621
0
    }
622
0
  }
623
0
}
624
625
static void trc_apply_level_by_category(unsigned int category, int lvl)
626
0
{
627
0
  size_t i;
628
629
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
630
0
    if(!category || (trc_cfts[i].category & category))
631
0
      trc_cfts[i].cft->log_level = lvl;
632
0
  }
633
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
634
0
    if(!category || (trc_feats[i].category & category))
635
0
      trc_feats[i].feat->log_level = lvl;
636
0
  }
637
0
}
638
639
static CURLcode trc_opt(const char *config)
640
0
{
641
0
  struct Curl_str out;
642
0
  while(!curlx_str_until(&config, &out, 32, ',')) {
643
0
    int lvl = CURL_LOG_LVL_INFO;
644
0
    const char *token = curlx_str(&out);
645
646
0
    if(*token == '-') {
647
0
      lvl = CURL_LOG_LVL_NONE;
648
0
      curlx_str_nudge(&out, 1);
649
0
    }
650
0
    else if(*token == '+')
651
0
      curlx_str_nudge(&out, 1);
652
653
0
    if(curlx_str_casecompare(&out, "all"))
654
0
      trc_apply_level_by_category(TRC_CT_NONE, lvl);
655
0
    else if(curlx_str_casecompare(&out, "protocol"))
656
0
      trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
657
0
    else if(curlx_str_casecompare(&out, "network"))
658
0
      trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
659
0
    else if(curlx_str_casecompare(&out, "proxy"))
660
0
      trc_apply_level_by_category(TRC_CT_PROXY, lvl);
661
0
    else
662
0
      trc_apply_level_by_name(&out, lvl);
663
664
0
    if(curlx_str_single(&config, ','))
665
0
      break;
666
0
  }
667
0
  return CURLE_OK;
668
0
}
669
670
CURLcode Curl_trc_opt(const char *config)
671
1
{
672
1
  CURLcode result = config ? trc_opt(config) : CURLE_OK;
673
1
#ifdef DEBUGBUILD
674
  /* CURL_DEBUG can override anything */
675
1
  if(!result) {
676
1
    const char *dbg_config = getenv("CURL_DEBUG");
677
1
    if(dbg_config)
678
0
      result = trc_opt(dbg_config);
679
1
  }
680
1
#endif /* DEBUGBUILD */
681
1
  return result;
682
1
}
683
684
CURLcode Curl_trc_init(void)
685
1
{
686
1
#ifdef DEBUGBUILD
687
1
  return Curl_trc_opt(NULL);
688
#else
689
  return CURLE_OK;
690
#endif
691
1
}
692
693
#else /* CURL_DISABLE_VERBOSE_STRINGS */
694
695
CURLcode Curl_trc_init(void)
696
{
697
  return CURLE_OK;
698
}
699
700
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
701
{
702
  (void)data;
703
  (void)fmt;
704
}
705
706
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
707
                       const char *fmt, ...)
708
{
709
  (void)data;
710
  (void)cf;
711
  (void)fmt;
712
}
713
714
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
715
{
716
  (void)data;
717
  (void)fmt;
718
}
719
720
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
721
{
722
  (void)data;
723
  (void)fmt;
724
}
725
726
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
727
{
728
  (void)data;
729
  (void)fmt;
730
}
731
732
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
733
{
734
  (void)data;
735
  (void)tid;
736
  (void)fmt;
737
}
738
739
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
740
{
741
  (void)data;
742
  (void)fmt;
743
}
744
745
#ifndef CURL_DISABLE_FTP
746
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
747
{
748
  (void)data;
749
  (void)fmt;
750
}
751
#endif
752
#ifndef CURL_DISABLE_SMTP
753
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
754
{
755
  (void)data;
756
  (void)fmt;
757
}
758
#endif
759
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
760
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
761
{
762
  (void)data;
763
  (void)fmt;
764
}
765
#endif
766
#ifdef USE_SSH
767
void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
768
{
769
  (void)data;
770
  (void)fmt;
771
}
772
#endif
773
#ifdef USE_SSL
774
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
775
{
776
  (void)data;
777
  (void)fmt;
778
}
779
#endif
780
781
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */