Coverage Report

Created: 2026-06-15 07:03

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