Coverage Report

Created: 2026-07-14 07:09

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-recvbuf.h"
33
#include "cf-socket.h"
34
#include "cf-setup.h"
35
#include "http2.h"
36
#include "http_proxy.h"
37
#include "cf-h1-proxy.h"
38
#include "cf-h2-proxy.h"
39
#include "cf-haproxy.h"
40
#include "cf-https-connect.h"
41
#include "cf-ip-happy.h"
42
#include "progress.h"
43
#include "socks.h"
44
#include "curlx/strparse.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
      bool inCallback = Curl_is_in_callback(data);
55
0
      Curl_set_in_callback(data, TRUE);
56
0
      (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
57
0
                                data->set.debugdata);
58
0
      Curl_set_in_callback(data, inCallback);
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->conn ?
96
0
                   data->conn->connection_id : data->state.recent_conn_id;
97
0
  if(data->id >= 0) {
98
0
    if(cid >= 0)
99
0
      return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
100
0
    else
101
0
      return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
102
0
  }
103
0
  else if(cid >= 0)
104
0
    return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
105
0
  else {
106
0
    return curl_msnprintf(buf, maxlen, "[x-x] ");
107
0
  }
108
0
}
109
110
static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
111
0
{
112
  /* make sure we end the trace line in `buf` properly. It needs
113
   * to end with a terminating '\0' or '\n\0' */
114
0
  if(len >= (maxlen - (addnl ? 2 : 1))) {
115
0
    len = maxlen - 5;
116
0
    buf[len++] = '.';
117
0
    buf[len++] = '.';
118
0
    buf[len++] = '.';
119
0
    buf[len++] = '\n';
120
0
  }
121
0
  else if(addnl)
122
0
    buf[len++] = '\n';
123
0
  buf[len] = '\0';
124
0
  return len;
125
0
}
126
127
void Curl_debug(struct Curl_easy *data, curl_infotype type,
128
                const char *ptr, size_t size)
129
0
{
130
0
  if(data->set.verbose) {
131
0
    static const char s_infotype[CURLINFO_END][3] = {
132
0
      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
133
0
    char buf[TRC_LINE_MAX];
134
0
    size_t len;
135
0
    if(data->set.fdebug) {
136
0
      bool inCallback = Curl_is_in_callback(data);
137
138
0
      if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
139
0
        len = trc_print_ids(data, buf, TRC_LINE_MAX);
140
0
        len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
141
0
                              (int)size, ptr);
142
0
        len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
143
0
        Curl_set_in_callback(data, TRUE);
144
0
        (void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
145
0
        Curl_set_in_callback(data, inCallback);
146
0
      }
147
0
      else {
148
0
        Curl_set_in_callback(data, TRUE);
149
0
        (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
150
0
                                  size, data->set.debugdata);
151
0
        Curl_set_in_callback(data, inCallback);
152
0
      }
153
0
    }
154
0
    else {
155
0
      switch(type) {
156
0
      case CURLINFO_TEXT:
157
0
      case CURLINFO_HEADER_OUT:
158
0
      case CURLINFO_HEADER_IN:
159
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
160
0
        if(CURL_TRC_IDS(data)) {
161
0
          len = trc_print_ids(data, buf, TRC_LINE_MAX);
162
0
          fwrite(buf, len, 1, data->set.err);
163
0
        }
164
0
#endif
165
0
        fwrite(s_infotype[type], 2, 1, data->set.err);
166
0
        fwrite(ptr, size, 1, data->set.err);
167
0
        break;
168
0
      default: /* nada */
169
0
        break;
170
0
      }
171
0
    }
172
0
  }
173
0
}
174
175
/* Curl_failf() is for messages stating why we failed.
176
 * The message SHALL NOT include any LF or CR.
177
 */
178
void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
179
0
{
180
0
  DEBUGASSERT(!strchr(fmt, '\n'));
181
0
  if(data->set.verbose || data->set.errorbuffer) {
182
0
    va_list ap;
183
0
    size_t len;
184
0
    char error[CURL_ERROR_SIZE + 2];
185
0
    va_start(ap, fmt);
186
0
    len = curl_mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
187
188
0
    if(data->set.errorbuffer && !data->state.errorbuf) {
189
0
      curlx_strcopy(data->set.errorbuffer, CURL_ERROR_SIZE, error, len);
190
0
      data->state.errorbuf = TRUE; /* wrote error string */
191
0
    }
192
0
    error[len++] = '\n';
193
0
    error[len] = '\0';
194
0
    trc_write(data, CURLINFO_TEXT, error, len);
195
0
    va_end(ap);
196
0
  }
197
0
}
198
199
void Curl_reset_fail(struct Curl_easy *data)
200
0
{
201
0
  if(data->set.errorbuffer)
202
0
    data->set.errorbuffer[0] = 0;
203
0
  data->state.errorbuf = FALSE;
204
0
}
205
206
#ifdef CURLVERBOSE
207
struct curl_trc_feat Curl_trc_feat_multi = {
208
  "MULTI",
209
  CURL_LOG_LVL_NONE,
210
};
211
struct curl_trc_feat Curl_trc_feat_read = {
212
  "READ",
213
  CURL_LOG_LVL_NONE,
214
};
215
struct curl_trc_feat Curl_trc_feat_write = {
216
  "WRITE",
217
  CURL_LOG_LVL_NONE,
218
};
219
struct curl_trc_feat Curl_trc_feat_dns = {
220
  "DNS",
221
  CURL_LOG_LVL_NONE,
222
};
223
struct curl_trc_feat Curl_trc_feat_timer = {
224
  "TIMER",
225
  CURL_LOG_LVL_NONE,
226
};
227
#ifdef USE_THREADS
228
struct curl_trc_feat Curl_trc_feat_threads = {
229
  "THREADS",
230
  CURL_LOG_LVL_NONE,
231
};
232
#endif
233
#endif
234
235
#ifndef CURL_DISABLE_VERBOSE_STRINGS
236
237
static void trc_infof(struct Curl_easy *data,
238
                      struct curl_trc_feat *feat,
239
                      const char *opt_id, int opt_id_idx,
240
                      const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
241
242
static void trc_infof(struct Curl_easy *data,
243
                      struct curl_trc_feat *feat,
244
                      const char *opt_id, int opt_id_idx,
245
                      const char * const fmt, va_list ap)
246
0
{
247
0
  size_t len = 0;
248
0
  char buf[TRC_LINE_MAX];
249
250
0
  if(CURL_TRC_IDS(data))
251
0
    len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
252
0
  if(feat)
253
0
    len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
254
0
  if(opt_id) {
255
0
    if(opt_id_idx > 0)
256
0
      len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
257
0
                            opt_id, opt_id_idx);
258
0
    else
259
0
      len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
260
0
  }
261
0
  len += curl_mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap);
262
0
  len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE);
263
0
  trc_write(data, CURLINFO_TEXT, buf, len);
264
0
}
265
266
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
267
0
{
268
0
  DEBUGASSERT(!strchr(fmt, '\n'));
269
0
  if(Curl_trc_is_verbose(data)) {
270
0
    va_list ap;
271
0
    va_start(ap, fmt);
272
0
    trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
273
0
    va_end(ap);
274
0
  }
275
0
}
276
277
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
278
                       const char *fmt, ...)
279
0
{
280
0
  DEBUGASSERT(cf);
281
0
  if(Curl_trc_cf_is_verbose(cf, data)) {
282
0
    va_list ap;
283
0
    va_start(ap, fmt);
284
0
    trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
285
0
    va_end(ap);
286
0
  }
287
0
}
288
289
void Curl_trc_feat_infof(struct Curl_easy *data,
290
                         struct curl_trc_feat *feat,
291
                         const char *fmt, ...)
292
0
{
293
0
  DEBUGASSERT(feat);
294
0
  if(Curl_trc_ft_is_verbose(data, feat)) {
295
0
    va_list ap;
296
0
    va_start(ap, fmt);
297
0
    trc_infof(data, feat, NULL, 0, fmt, ap);
298
0
    va_end(ap);
299
0
  }
300
0
}
301
302
static const char * const Curl_trc_timer_names[] = {
303
  "100_TIMEOUT",
304
  "ASYNC_NAME",
305
  "CONNECTTIMEOUT",
306
  "DNS_PER_NAME",
307
  "DNS_PER_NAME2",
308
  "HAPPY_EYEBALLS_DNS",
309
  "HAPPY_EYEBALLS",
310
  "MULTI_PENDING",
311
  "SPEEDCHECK",
312
  "TIMEOUT",
313
  "TOOFAST",
314
  "QUIC",
315
  "FTP_ACCEPT",
316
  "ALPN_EYEBALLS",
317
  "SHUTDOWN",
318
};
319
320
static const char *trc_timer_name(int tid)
321
0
{
322
0
  if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names)))
323
0
    return Curl_trc_timer_names[(size_t)tid];
324
0
  return "UNKNOWN?";
325
0
}
326
327
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
328
0
{
329
0
  DEBUGASSERT(!strchr(fmt, '\n'));
330
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)) {
331
0
    const char *tname = trc_timer_name(tid);
332
0
    va_list ap;
333
0
    va_start(ap, fmt);
334
0
    trc_infof(data, &Curl_trc_feat_timer, tname, 0, fmt, ap);
335
0
    va_end(ap);
336
0
  }
337
0
}
338
339
void Curl_trc_easy_timers(struct Curl_easy *data)
340
0
{
341
0
  if(CURL_TRC_TIMER_is_verbose(data)) {
342
0
    struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
343
0
    if(e) {
344
0
      const struct curltime *pnow = Curl_pgrs_now(data);
345
0
      while(e) {
346
0
        struct time_node *n = Curl_node_elem(e);
347
0
        e = Curl_node_next(e);
348
0
        CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns",
349
0
                       curlx_ptimediff_us(&n->time, pnow));
350
0
      }
351
0
    }
352
0
  }
353
0
}
354
355
static const char * const Curl_trc_mstate_names[] = {
356
  "INIT",
357
  "PENDING",
358
  "SETUP",
359
  "CONNECT",
360
  "CONNECTING",
361
  "PROTOCONNECT",
362
  "PROTOCONNECTING",
363
  "DO",
364
  "DOING",
365
  "DOING_MORE",
366
  "DID",
367
  "PERFORMING",
368
  "RATELIMITING",
369
  "DONE",
370
  "COMPLETED",
371
  "MSGSENT",
372
};
373
374
const char *Curl_trc_mstate_name(int state)
375
0
{
376
0
  if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
377
0
    return Curl_trc_mstate_names[(size_t)state];
378
0
  return "?";
379
0
}
380
381
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
382
0
{
383
0
  DEBUGASSERT(!strchr(fmt, '\n'));
384
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
385
0
    const char *sname = (data->id >= 0) ?
386
0
                        Curl_trc_mstate_name(data->mstate) : NULL;
387
0
    va_list ap;
388
0
    va_start(ap, fmt);
389
0
    trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
390
0
    va_end(ap);
391
0
  }
392
0
}
393
394
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
395
0
{
396
0
  DEBUGASSERT(!strchr(fmt, '\n'));
397
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
398
0
    va_list ap;
399
0
    va_start(ap, fmt);
400
0
    trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
401
0
    va_end(ap);
402
0
  }
403
0
}
404
405
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
406
0
{
407
0
  DEBUGASSERT(!strchr(fmt, '\n'));
408
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
409
0
    va_list ap;
410
0
    va_start(ap, fmt);
411
0
    trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
412
0
    va_end(ap);
413
0
  }
414
0
}
415
416
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
417
0
{
418
0
  DEBUGASSERT(!strchr(fmt, '\n'));
419
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
420
0
    va_list ap;
421
0
    va_start(ap, fmt);
422
0
    trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
423
0
    va_end(ap);
424
0
  }
425
0
}
426
427
#ifndef CURL_DISABLE_FTP
428
struct curl_trc_feat Curl_trc_feat_ftp = {
429
  "FTP",
430
  CURL_LOG_LVL_NONE,
431
};
432
433
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
434
0
{
435
0
  DEBUGASSERT(!strchr(fmt, '\n'));
436
0
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
437
0
    va_list ap;
438
0
    va_start(ap, fmt);
439
0
    trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
440
0
    va_end(ap);
441
0
  }
442
0
}
443
#endif /* !CURL_DISABLE_FTP */
444
445
#ifndef CURL_DISABLE_SMTP
446
struct curl_trc_feat Curl_trc_feat_smtp = {
447
  "SMTP",
448
  CURL_LOG_LVL_NONE,
449
};
450
451
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
452
{
453
  DEBUGASSERT(!strchr(fmt, '\n'));
454
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
455
    va_list ap;
456
    va_start(ap, fmt);
457
    trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
458
    va_end(ap);
459
  }
460
}
461
#endif /* !CURL_DISABLE_SMTP */
462
463
#ifdef USE_SSL
464
struct curl_trc_feat Curl_trc_feat_ssls = {
465
  "SSLS",
466
  CURL_LOG_LVL_NONE,
467
};
468
469
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
470
{
471
  DEBUGASSERT(!strchr(fmt, '\n'));
472
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
473
    va_list ap;
474
    va_start(ap, fmt);
475
    trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
476
    va_end(ap);
477
  }
478
}
479
#endif /* USE_SSL */
480
481
#ifdef USE_SSH
482
struct curl_trc_feat Curl_trc_feat_ssh = {
483
  "SSH",
484
  CURL_LOG_LVL_NONE,
485
};
486
487
void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
488
{
489
  DEBUGASSERT(!strchr(fmt, '\n'));
490
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) {
491
    va_list ap;
492
    va_start(ap, fmt);
493
    trc_infof(data, &Curl_trc_feat_ssh, NULL, 0, fmt, ap);
494
    va_end(ap);
495
  }
496
}
497
#endif /* USE_SSH */
498
499
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
500
struct curl_trc_feat Curl_trc_feat_ws = {
501
  "WS",
502
  CURL_LOG_LVL_NONE,
503
};
504
505
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
506
{
507
  DEBUGASSERT(!strchr(fmt, '\n'));
508
  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
509
    va_list ap;
510
    va_start(ap, fmt);
511
    trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
512
    va_end(ap);
513
  }
514
}
515
#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
516
517
0
#define TRC_CT_NONE        0
518
0
#define TRC_CT_PROTOCOL    (1 << 0)
519
0
#define TRC_CT_NETWORK     (1 << 1)
520
0
#define TRC_CT_PROXY       (1 << 2)
521
#define TRC_CT_INTERNALS   (1 << 3)
522
523
struct trc_feat_def {
524
  struct curl_trc_feat *feat;
525
  unsigned int category;
526
};
527
528
static struct trc_feat_def trc_feats[] = {
529
  { &Curl_trc_feat_ids,       TRC_CT_INTERNALS },
530
  { &Curl_trc_feat_multi,     TRC_CT_NETWORK },
531
  { &Curl_trc_feat_read,      TRC_CT_NONE },
532
  { &Curl_trc_feat_write,     TRC_CT_NONE },
533
  { &Curl_trc_feat_dns,       TRC_CT_NETWORK },
534
  { &Curl_trc_feat_timer,     TRC_CT_NETWORK },
535
#ifdef USE_THREADS
536
  { &Curl_trc_feat_threads,   TRC_CT_NONE },
537
#endif
538
#ifndef CURL_DISABLE_FTP
539
  { &Curl_trc_feat_ftp,       TRC_CT_PROTOCOL },
540
#endif
541
#ifndef CURL_DISABLE_SMTP
542
  { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
543
#endif
544
#ifdef USE_SSL
545
  { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
546
#endif
547
#ifdef USE_SSH
548
  { &Curl_trc_feat_ssh,      TRC_CT_PROTOCOL },
549
#endif
550
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
551
  { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
552
#endif
553
};
554
555
struct trc_cft_def {
556
  struct Curl_cftype *cft;
557
  unsigned int category;
558
};
559
560
static struct trc_cft_def trc_cfts[] = {
561
  { &Curl_cft_dns,            TRC_CT_NETWORK },
562
  { &Curl_cft_tcp,            TRC_CT_NETWORK },
563
  { &Curl_cft_udp,            TRC_CT_NETWORK },
564
  { &Curl_cft_unix,           TRC_CT_NETWORK },
565
  { &Curl_cft_tcp_accept,     TRC_CT_NETWORK },
566
  { &Curl_cft_ip_happy,       TRC_CT_NETWORK },
567
#ifndef CURL_DISABLE_WEBSOCKETS
568
  { &Curl_cft_recvbuf,        TRC_CT_PROTOCOL },
569
#endif
570
  { &Curl_cft_setup,          TRC_CT_PROTOCOL },
571
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
572
  { &Curl_cft_nghttp2,        TRC_CT_PROTOCOL },
573
#endif
574
#ifdef USE_SSL
575
  { &Curl_cft_ssl,            TRC_CT_NETWORK },
576
#ifndef CURL_DISABLE_PROXY
577
  { &Curl_cft_ssl_proxy,      TRC_CT_PROXY },
578
#endif
579
#endif
580
#ifndef CURL_DISABLE_PROXY
581
#ifndef CURL_DISABLE_HTTP
582
  { &Curl_cft_h1_proxy,       TRC_CT_PROXY },
583
#ifdef USE_NGHTTP2
584
  { &Curl_cft_h2_proxy,       TRC_CT_PROXY },
585
#endif
586
#if defined(USE_PROXY_HTTP3) && defined(USE_NGHTTP3)
587
  { &Curl_cft_h3_proxy,       TRC_CT_PROXY },
588
#endif
589
  { &Curl_cft_http_proxy,     TRC_CT_PROXY },
590
#endif /* !CURL_DISABLE_HTTP */
591
  { &Curl_cft_haproxy,        TRC_CT_PROXY },
592
  { &Curl_cft_socks_proxy,    TRC_CT_PROXY },
593
#endif /* !CURL_DISABLE_PROXY */
594
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
595
  { &Curl_cft_http3,          TRC_CT_PROTOCOL },
596
#endif
597
#ifndef CURL_DISABLE_HTTP
598
  { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
599
#endif
600
};
601
602
static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
603
0
{
604
0
  size_t i;
605
606
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
607
0
    if(curlx_str_casecompare(token, trc_cfts[i].cft->name)) {
608
0
      trc_cfts[i].cft->log_level = lvl;
609
0
      break;
610
0
    }
611
0
  }
612
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
613
0
    if(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
614
0
      trc_feats[i].feat->log_level = lvl;
615
0
      break;
616
0
    }
617
0
  }
618
0
}
619
620
static void trc_apply_level_by_category(unsigned int category, int lvl)
621
0
{
622
0
  size_t i;
623
624
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
625
0
    if(!category || (trc_cfts[i].category & category))
626
0
      trc_cfts[i].cft->log_level = lvl;
627
0
  }
628
0
  for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
629
0
    if(!category || (trc_feats[i].category & category))
630
0
      trc_feats[i].feat->log_level = lvl;
631
0
  }
632
0
}
633
634
static CURLcode trc_opt(const char *config)
635
0
{
636
0
  struct Curl_str out;
637
0
  while(!curlx_str_until(&config, &out, 32, ',')) {
638
0
    int lvl = CURL_LOG_LVL_INFO;
639
0
    const char *token = curlx_str(&out);
640
641
0
    if(*token == '-') {
642
0
      lvl = CURL_LOG_LVL_NONE;
643
0
      curlx_str_nudge(&out, 1);
644
0
    }
645
0
    else if(*token == '+')
646
0
      curlx_str_nudge(&out, 1);
647
648
0
    if(curlx_str_casecompare(&out, "all"))
649
0
      trc_apply_level_by_category(TRC_CT_NONE, lvl);
650
0
    else if(curlx_str_casecompare(&out, "protocol"))
651
0
      trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
652
0
    else if(curlx_str_casecompare(&out, "network"))
653
0
      trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
654
0
    else if(curlx_str_casecompare(&out, "proxy"))
655
0
      trc_apply_level_by_category(TRC_CT_PROXY, lvl);
656
0
    else if(curlx_str_casecompare(&out, "doh")) {
657
0
      struct Curl_str dns = { "dns", 3 };
658
0
      trc_apply_level_by_name(&dns, lvl);
659
0
    }
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
#ifdef DEBUGBUILD
673
  /* CURL_DEBUG can override anything */
674
  if(!result) {
675
    const char *dbg_config = getenv("CURL_DEBUG");
676
    if(dbg_config)
677
      result = trc_opt(dbg_config);
678
  }
679
#endif /* DEBUGBUILD */
680
0
  return result;
681
0
}
682
683
CURLcode Curl_trc_init(void)
684
0
{
685
#ifdef DEBUGBUILD
686
  return Curl_trc_opt(NULL);
687
#else
688
0
  return CURLE_OK;
689
0
#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 */