Coverage Report

Created: 2025-10-10 06:31

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