Coverage Report

Created: 2026-03-12 06:35

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