tool_cb_dbg.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "tool_setup.h"
00023 
00024 #define ENABLE_CURLX_PRINTF
00025 /* use our own printf() functions */
00026 #include "curlx.h"
00027 
00028 #include "tool_cfgable.h"
00029 #include "tool_msgs.h"
00030 #include "tool_cb_dbg.h"
00031 #include "tool_util.h"
00032 
00033 #include "memdebug.h" /* keep this as LAST include */
00034 
00035 static void dump(const char *timebuf, const char *text,
00036                  FILE *stream, const unsigned char *ptr, size_t size,
00037                  trace tracetype, curl_infotype infotype);
00038 
00039 /*
00040 ** callback for CURLOPT_DEBUGFUNCTION
00041 */
00042 
00043 int tool_debug_cb(CURL *handle, curl_infotype type,
00044                   unsigned char *data, size_t size,
00045                   void *userdata)
00046 {
00047   struct OperationConfig *operation = userdata;
00048   struct GlobalConfig *config = operation->global;
00049   FILE *output = config->errors;
00050   const char *text;
00051   struct timeval tv;
00052   struct tm *now;
00053   char timebuf[20];
00054   time_t secs;
00055   static time_t epoch_offset;
00056   static int    known_offset;
00057 
00058   (void)handle; /* not used */
00059 
00060   if(config->tracetime) {
00061     tv = tvnow();
00062     if(!known_offset) {
00063       epoch_offset = time(NULL) - tv.tv_sec;
00064       known_offset = 1;
00065     }
00066     secs = epoch_offset + tv.tv_sec;
00067     now = localtime(&secs);  /* not thread safe but we don't care */
00068     snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
00069              now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
00070   }
00071   else
00072     timebuf[0] = 0;
00073 
00074   if(!config->trace_stream) {
00075     /* open for append */
00076     if(!strcmp("-", config->trace_dump))
00077       config->trace_stream = stdout;
00078     else if(!strcmp("%", config->trace_dump))
00079       /* Ok, this is somewhat hackish but we do it undocumented for now */
00080       config->trace_stream = config->errors;  /* aka stderr */
00081     else {
00082       config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT);
00083       config->trace_fopened = TRUE;
00084     }
00085   }
00086 
00087   if(config->trace_stream)
00088     output = config->trace_stream;
00089 
00090   if(!output) {
00091     warnf(config, "Failed to create/open output");
00092     return 0;
00093   }
00094 
00095   if(config->tracetype == TRACE_PLAIN) {
00096     /*
00097      * This is the trace look that is similar to what libcurl makes on its
00098      * own.
00099      */
00100     static const char * const s_infotype[] = {
00101       "*", "<", ">", "{", "}", "{", "}"
00102     };
00103     size_t i;
00104     size_t st = 0;
00105     static bool newl = FALSE;
00106     static bool traced_data = FALSE;
00107 
00108     switch(type) {
00109     case CURLINFO_HEADER_OUT:
00110       if(size > 0) {
00111         for(i = 0; i < size - 1; i++) {
00112           if(data[i] == '\n') { /* LF */
00113             if(!newl) {
00114               fprintf(output, "%s%s ", timebuf, s_infotype[type]);
00115             }
00116             (void)fwrite(data + st, i - st + 1, 1, output);
00117             st = i + 1;
00118             newl = FALSE;
00119           }
00120         }
00121         if(!newl)
00122           fprintf(output, "%s%s ", timebuf, s_infotype[type]);
00123         (void)fwrite(data + st, i - st + 1, 1, output);
00124       }
00125       newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
00126       traced_data = FALSE;
00127       break;
00128     case CURLINFO_TEXT:
00129     case CURLINFO_HEADER_IN:
00130       if(!newl)
00131         fprintf(output, "%s%s ", timebuf, s_infotype[type]);
00132       (void)fwrite(data, size, 1, output);
00133       newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
00134       traced_data = FALSE;
00135       break;
00136     case CURLINFO_DATA_OUT:
00137     case CURLINFO_DATA_IN:
00138     case CURLINFO_SSL_DATA_IN:
00139     case CURLINFO_SSL_DATA_OUT:
00140       if(!traced_data) {
00141         /* if the data is output to a tty and we're sending this debug trace
00142            to stderr or stdout, we don't display the alert about the data not
00143            being shown as the data _is_ shown then just not via this
00144            function */
00145         if(!config->isatty || ((output != stderr) && (output != stdout))) {
00146           if(!newl)
00147             fprintf(output, "%s%s ", timebuf, s_infotype[type]);
00148           fprintf(output, "[%zd bytes data]\n", size);
00149           newl = FALSE;
00150           traced_data = TRUE;
00151         }
00152       }
00153       break;
00154     default: /* nada */
00155       newl = FALSE;
00156       traced_data = FALSE;
00157       break;
00158     }
00159 
00160     return 0;
00161   }
00162 
00163 #ifdef CURL_DOES_CONVERSIONS
00164   /* Special processing is needed for CURLINFO_HEADER_OUT blocks
00165    * if they contain both headers and data (separated by CRLFCRLF).
00166    * We dump the header text and then switch type to CURLINFO_DATA_OUT.
00167    */
00168   if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
00169     size_t i;
00170     for(i = 0; i < size - 4; i++) {
00171       if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
00172         /* dump everything through the CRLFCRLF as a sent header */
00173         text = "=> Send header";
00174         dump(timebuf, text, output, data, i + 4, config->tracetype, type);
00175         data += i + 3;
00176         size -= i + 4;
00177         type = CURLINFO_DATA_OUT;
00178         data += 1;
00179         break;
00180       }
00181     }
00182   }
00183 #endif /* CURL_DOES_CONVERSIONS */
00184 
00185   switch(type) {
00186   case CURLINFO_TEXT:
00187     fprintf(output, "%s== Info: %s", timebuf, data);
00188   default: /* in case a new one is introduced to shock us */
00189     return 0;
00190 
00191   case CURLINFO_HEADER_OUT:
00192     text = "=> Send header";
00193     break;
00194   case CURLINFO_DATA_OUT:
00195     text = "=> Send data";
00196     break;
00197   case CURLINFO_HEADER_IN:
00198     text = "<= Recv header";
00199     break;
00200   case CURLINFO_DATA_IN:
00201     text = "<= Recv data";
00202     break;
00203   case CURLINFO_SSL_DATA_IN:
00204     text = "<= Recv SSL data";
00205     break;
00206   case CURLINFO_SSL_DATA_OUT:
00207     text = "=> Send SSL data";
00208     break;
00209   }
00210 
00211   dump(timebuf, text, output, data, size, config->tracetype, type);
00212   return 0;
00213 }
00214 
00215 static void dump(const char *timebuf, const char *text,
00216                  FILE *stream, const unsigned char *ptr, size_t size,
00217                  trace tracetype, curl_infotype infotype)
00218 {
00219   size_t i;
00220   size_t c;
00221 
00222   unsigned int width = 0x10;
00223 
00224   if(tracetype == TRACE_ASCII)
00225     /* without the hex output, we can fit more on screen */
00226     width = 0x40;
00227 
00228   fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
00229 
00230   for(i = 0; i < size; i += width) {
00231 
00232     fprintf(stream, "%04zx: ", i);
00233 
00234     if(tracetype == TRACE_BIN) {
00235       /* hex not disabled, show it */
00236       for(c = 0; c < width; c++)
00237         if(i+c < size)
00238           fprintf(stream, "%02x ", ptr[i+c]);
00239         else
00240           fputs("   ", stream);
00241     }
00242 
00243     for(c = 0; (c < width) && (i+c < size); c++) {
00244       /* check for 0D0A; if found, skip past and start a new line of output */
00245       if((tracetype == TRACE_ASCII) &&
00246          (i+c+1 < size) && (ptr[i+c] == 0x0D) && (ptr[i+c+1] == 0x0A)) {
00247         i += (c+2-width);
00248         break;
00249       }
00250 #ifdef CURL_DOES_CONVERSIONS
00251       /* repeat the 0D0A check above but use the host encoding for CRLF */
00252       if((tracetype == TRACE_ASCII) &&
00253          (i+c+1 < size) && (ptr[i+c] == '\r') && (ptr[i+c+1] == '\n')) {
00254         i += (c+2-width);
00255         break;
00256       }
00257       /* convert to host encoding and print this character */
00258       fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
00259 #else
00260       (void)infotype;
00261       fprintf(stream, "%c", ((ptr[i+c] >= 0x20) && (ptr[i+c] < 0x80)) ?
00262               ptr[i+c] : UNPRINTABLE_CHAR);
00263 #endif /* CURL_DOES_CONVERSIONS */
00264       /* check again for 0D0A, to avoid an extra \n if it's at width */
00265       if((tracetype == TRACE_ASCII) &&
00266          (i+c+2 < size) && (ptr[i+c+1] == 0x0D) && (ptr[i+c+2] == 0x0A)) {
00267         i += (c+3-width);
00268         break;
00269       }
00270     }
00271     fputc('\n', stream); /* newline */
00272   }
00273   fflush(stream);
00274 }
00275 


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06