quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

tool_cb_dbg.c (8624B)


      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 "tool_setup.h"
     25 
     26 #include "tool_cfgable.h"
     27 #include "tool_msgs.h"
     28 #include "tool_cb_dbg.h"
     29 #include "tool_util.h"
     30 
     31 #include "memdebug.h" /* keep this as LAST include */
     32 
     33 static void dump(const char *timebuf, const char *idsbuf, const char *text,
     34                  FILE *stream, const unsigned char *ptr, size_t size,
     35                  trace tracetype, curl_infotype infotype);
     36 
     37 /*
     38  * Return the formatted HH:MM:SS for the tv_sec given.
     39  * NOT thread safe.
     40  */
     41 static const char *hms_for_sec(time_t tv_sec)
     42 {
     43   static time_t cached_tv_sec;
     44   static char hms_buf[12];
     45 
     46   if(tv_sec != cached_tv_sec) {
     47     /* !checksrc! disable BANNEDFUNC 1 */
     48     struct tm *now = localtime(&tv_sec);  /* not thread safe either */
     49     msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
     50               now->tm_hour, now->tm_min, now->tm_sec);
     51     cached_tv_sec = tv_sec;
     52   }
     53   return hms_buf;
     54 }
     55 
     56 static void log_line_start(FILE *log, const char *timebuf,
     57                            const char *idsbuf, curl_infotype type)
     58 {
     59   /*
     60    * This is the trace look that is similar to what libcurl makes on its
     61    * own.
     62    */
     63   static const char * const s_infotype[] = {
     64     "* ", "< ", "> ", "{ ", "} ", "{ ", "} "
     65   };
     66   if((timebuf && *timebuf) || (idsbuf && *idsbuf))
     67     fprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]);
     68   else
     69     fputs(s_infotype[type], log);
     70 }
     71 
     72 #define TRC_IDS_FORMAT_IDS_1  "[%" CURL_FORMAT_CURL_OFF_T "-x] "
     73 #define TRC_IDS_FORMAT_IDS_2  "[%" CURL_FORMAT_CURL_OFF_T "-%" \
     74                                    CURL_FORMAT_CURL_OFF_T "] "
     75 /*
     76 ** callback for CURLOPT_DEBUGFUNCTION
     77 */
     78 int tool_debug_cb(CURL *handle, curl_infotype type,
     79                   char *data, size_t size,
     80                   void *userdata)
     81 {
     82   struct OperationConfig *operation = userdata;
     83   struct GlobalConfig *global = operation->global;
     84   FILE *output = tool_stderr;
     85   const char *text;
     86   struct timeval tv;
     87   char timebuf[20];
     88   /* largest signed 64-bit is: 9,223,372,036,854,775,807
     89    * max length in decimal: 1 + (6*3) = 19
     90    * formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
     91    * negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
     92    */
     93   char idsbuf[60];
     94   curl_off_t xfer_id, conn_id;
     95 
     96   (void)handle; /* not used */
     97 
     98   if(global->tracetime) {
     99     tv = tvrealnow();
    100     msnprintf(timebuf, sizeof(timebuf), "%s.%06ld ",
    101               hms_for_sec(tv.tv_sec), (long)tv.tv_usec);
    102   }
    103   else
    104     timebuf[0] = 0;
    105 
    106   if(handle && global->traceids &&
    107      !curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) {
    108     if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) &&
    109         conn_id >= 0) {
    110       msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2,
    111                 xfer_id, conn_id);
    112     }
    113     else {
    114       msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id);
    115     }
    116   }
    117   else
    118     idsbuf[0] = 0;
    119 
    120   if(!global->trace_stream) {
    121     /* open for append */
    122     if(!strcmp("-", global->trace_dump))
    123       global->trace_stream = stdout;
    124     else if(!strcmp("%", global->trace_dump))
    125       /* Ok, this is somewhat hackish but we do it undocumented for now */
    126       global->trace_stream = tool_stderr;
    127     else {
    128       global->trace_stream = fopen(global->trace_dump, FOPEN_WRITETEXT);
    129       global->trace_fopened = TRUE;
    130     }
    131   }
    132 
    133   if(global->trace_stream)
    134     output = global->trace_stream;
    135 
    136   if(!output) {
    137     warnf(global, "Failed to create/open output");
    138     return 0;
    139   }
    140 
    141   if(global->tracetype == TRACE_PLAIN) {
    142     static bool newl = FALSE;
    143     static bool traced_data = FALSE;
    144 
    145     switch(type) {
    146     case CURLINFO_HEADER_OUT:
    147       if(size > 0) {
    148         size_t st = 0;
    149         size_t i;
    150         for(i = 0; i < size - 1; i++) {
    151           if(data[i] == '\n') { /* LF */
    152             if(!newl) {
    153               log_line_start(output, timebuf, idsbuf, type);
    154             }
    155             (void)fwrite(data + st, i - st + 1, 1, output);
    156             st = i + 1;
    157             newl = FALSE;
    158           }
    159         }
    160         if(!newl)
    161           log_line_start(output, timebuf, idsbuf, type);
    162         (void)fwrite(data + st, i - st + 1, 1, output);
    163       }
    164       newl = (size && (data[size - 1] != '\n'));
    165       traced_data = FALSE;
    166       break;
    167     case CURLINFO_TEXT:
    168     case CURLINFO_HEADER_IN:
    169       if(!newl)
    170         log_line_start(output, timebuf, idsbuf, type);
    171       (void)fwrite(data, size, 1, output);
    172       newl = (size && (data[size - 1] != '\n'));
    173       traced_data = FALSE;
    174       break;
    175     case CURLINFO_DATA_OUT:
    176     case CURLINFO_DATA_IN:
    177     case CURLINFO_SSL_DATA_IN:
    178     case CURLINFO_SSL_DATA_OUT:
    179       if(!traced_data) {
    180         /* if the data is output to a tty and we are sending this debug trace
    181            to stderr or stdout, we do not display the alert about the data not
    182            being shown as the data _is_ shown then just not via this
    183            function */
    184         if(!global->isatty ||
    185            ((output != tool_stderr) && (output != stdout))) {
    186           if(!newl)
    187             log_line_start(output, timebuf, idsbuf, type);
    188           fprintf(output, "[%zu bytes data]\n", size);
    189           newl = FALSE;
    190           traced_data = TRUE;
    191         }
    192       }
    193       break;
    194     default: /* nada */
    195       newl = FALSE;
    196       traced_data = FALSE;
    197       break;
    198     }
    199 
    200     return 0;
    201   }
    202 
    203   switch(type) {
    204   case CURLINFO_TEXT:
    205     fprintf(output, "%s%s== Info: %.*s", timebuf, idsbuf, (int)size, data);
    206     FALLTHROUGH();
    207   default: /* in case a new one is introduced to shock us */
    208     return 0;
    209 
    210   case CURLINFO_HEADER_OUT:
    211     text = "=> Send header";
    212     break;
    213   case CURLINFO_DATA_OUT:
    214     text = "=> Send data";
    215     break;
    216   case CURLINFO_HEADER_IN:
    217     text = "<= Recv header";
    218     break;
    219   case CURLINFO_DATA_IN:
    220     text = "<= Recv data";
    221     break;
    222   case CURLINFO_SSL_DATA_IN:
    223     text = "<= Recv SSL data";
    224     break;
    225   case CURLINFO_SSL_DATA_OUT:
    226     text = "=> Send SSL data";
    227     break;
    228   }
    229 
    230   dump(timebuf, idsbuf, text, output, (unsigned char *) data, size,
    231        global->tracetype, type);
    232   return 0;
    233 }
    234 
    235 static void dump(const char *timebuf, const char *idsbuf, const char *text,
    236                  FILE *stream, const unsigned char *ptr, size_t size,
    237                  trace tracetype, curl_infotype infotype)
    238 {
    239   size_t i;
    240   size_t c;
    241 
    242   unsigned int width = 0x10;
    243 
    244   if(tracetype == TRACE_ASCII)
    245     /* without the hex output, we can fit more on screen */
    246     width = 0x40;
    247 
    248   fprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf,
    249           text, size, size);
    250 
    251   for(i = 0; i < size; i += width) {
    252 
    253     fprintf(stream, "%04zx: ", i);
    254 
    255     if(tracetype == TRACE_BIN) {
    256       /* hex not disabled, show it */
    257       for(c = 0; c < width; c++)
    258         if(i + c < size)
    259           fprintf(stream, "%02x ", ptr[i + c]);
    260         else
    261           fputs("   ", stream);
    262     }
    263 
    264     for(c = 0; (c < width) && (i + c < size); c++) {
    265       /* check for 0D0A; if found, skip past and start a new line of output */
    266       if((tracetype == TRACE_ASCII) &&
    267          (i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
    268          (ptr[i + c + 1] == 0x0A)) {
    269         i += (c + 2 - width);
    270         break;
    271       }
    272       (void)infotype;
    273       fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
    274               ptr[i + c] : UNPRINTABLE_CHAR);
    275       /* check again for 0D0A, to avoid an extra \n if it is at width */
    276       if((tracetype == TRACE_ASCII) &&
    277          (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
    278          (ptr[i + c + 2] == 0x0A)) {
    279         i += (c + 3 - width);
    280         break;
    281       }
    282     }
    283     fputc('\n', stream); /* newline */
    284   }
    285   fflush(stream);
    286 }