123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
- #include "tool_setup.h"
- #define ENABLE_CURLX_PRINTF
- /* use our own printf() functions */
- #include "curlx.h"
- #include "tool_cfgable.h"
- #include "tool_convert.h"
- #include "tool_msgs.h"
- #include "tool_cb_dbg.h"
- #include "tool_util.h"
- #include "memdebug.h" /* keep this as LAST include */
- static void dump(const char *timebuf, const char *text,
- FILE *stream, const unsigned char *ptr, size_t size,
- trace tracetype, curl_infotype infotype);
- /*
- ** callback for CURLOPT_DEBUGFUNCTION
- */
- int tool_debug_cb(CURL *handle, curl_infotype type,
- char *data, size_t size,
- void *userdata)
- {
- struct OperationConfig *operation = userdata;
- struct GlobalConfig *config = operation->global;
- FILE *output = config->errors;
- const char *text;
- struct timeval tv;
- char timebuf[20];
- time_t secs;
- (void)handle; /* not used */
- if(config->tracetime) {
- struct tm *now;
- static time_t epoch_offset;
- static int known_offset;
- tv = tvnow();
- if(!known_offset) {
- epoch_offset = time(NULL) - tv.tv_sec;
- known_offset = 1;
- }
- secs = epoch_offset + tv.tv_sec;
- /* !checksrc! disable BANNEDFUNC 1 */
- now = localtime(&secs); /* not thread safe but we don't care */
- msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
- now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
- }
- else
- timebuf[0] = 0;
- if(!config->trace_stream) {
- /* open for append */
- if(!strcmp("-", config->trace_dump))
- config->trace_stream = stdout;
- else if(!strcmp("%", config->trace_dump))
- /* Ok, this is somewhat hackish but we do it undocumented for now */
- config->trace_stream = config->errors; /* aka stderr */
- else {
- config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT);
- config->trace_fopened = TRUE;
- }
- }
- if(config->trace_stream)
- output = config->trace_stream;
- if(!output) {
- warnf(config, "Failed to create/open output");
- return 0;
- }
- if(config->tracetype == TRACE_PLAIN) {
- /*
- * This is the trace look that is similar to what libcurl makes on its
- * own.
- */
- static const char * const s_infotype[] = {
- "*", "<", ">", "{", "}", "{", "}"
- };
- static bool newl = FALSE;
- static bool traced_data = FALSE;
- switch(type) {
- case CURLINFO_HEADER_OUT:
- if(size > 0) {
- size_t st = 0;
- size_t i;
- for(i = 0; i < size - 1; i++) {
- if(data[i] == '\n') { /* LF */
- if(!newl) {
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- }
- (void)fwrite(data + st, i - st + 1, 1, output);
- st = i + 1;
- newl = FALSE;
- }
- }
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- (void)fwrite(data + st, i - st + 1, 1, output);
- }
- newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
- traced_data = FALSE;
- break;
- case CURLINFO_TEXT:
- case CURLINFO_HEADER_IN:
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- (void)fwrite(data, size, 1, output);
- newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
- traced_data = FALSE;
- break;
- case CURLINFO_DATA_OUT:
- case CURLINFO_DATA_IN:
- case CURLINFO_SSL_DATA_IN:
- case CURLINFO_SSL_DATA_OUT:
- if(!traced_data) {
- /* if the data is output to a tty and we're sending this debug trace
- to stderr or stdout, we don't display the alert about the data not
- being shown as the data _is_ shown then just not via this
- function */
- if(!config->isatty || ((output != stderr) && (output != stdout))) {
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- fprintf(output, "[%zu bytes data]\n", size);
- newl = FALSE;
- traced_data = TRUE;
- }
- }
- break;
- default: /* nada */
- newl = FALSE;
- traced_data = FALSE;
- break;
- }
- return 0;
- }
- #ifdef CURL_DOES_CONVERSIONS
- /* Special processing is needed for CURLINFO_HEADER_OUT blocks
- * if they contain both headers and data (separated by CRLFCRLF).
- * We dump the header text and then switch type to CURLINFO_DATA_OUT.
- */
- if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
- size_t i;
- for(i = 0; i < size - 4; i++) {
- if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
- /* dump everything through the CRLFCRLF as a sent header */
- text = "=> Send header";
- dump(timebuf, text, output, (unsigned char *)data, i + 4,
- config->tracetype, type);
- data += i + 3;
- size -= i + 4;
- type = CURLINFO_DATA_OUT;
- data += 1;
- break;
- }
- }
- }
- #endif /* CURL_DOES_CONVERSIONS */
- switch(type) {
- case CURLINFO_TEXT:
- fprintf(output, "%s== Info: %.*s", timebuf, (int)size, data);
- /* FALLTHROUGH */
- default: /* in case a new one is introduced to shock us */
- return 0;
- case CURLINFO_HEADER_OUT:
- text = "=> Send header";
- break;
- case CURLINFO_DATA_OUT:
- text = "=> Send data";
- break;
- case CURLINFO_HEADER_IN:
- text = "<= Recv header";
- break;
- case CURLINFO_DATA_IN:
- text = "<= Recv data";
- break;
- case CURLINFO_SSL_DATA_IN:
- text = "<= Recv SSL data";
- break;
- case CURLINFO_SSL_DATA_OUT:
- text = "=> Send SSL data";
- break;
- }
- dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype,
- type);
- return 0;
- }
- static void dump(const char *timebuf, const char *text,
- FILE *stream, const unsigned char *ptr, size_t size,
- trace tracetype, curl_infotype infotype)
- {
- size_t i;
- size_t c;
- unsigned int width = 0x10;
- if(tracetype == TRACE_ASCII)
- /* without the hex output, we can fit more on screen */
- width = 0x40;
- fprintf(stream, "%s%s, %zu bytes (0x%zx)\n", timebuf, text, size, size);
- for(i = 0; i < size; i += width) {
- fprintf(stream, "%04zx: ", i);
- if(tracetype == TRACE_BIN) {
- /* hex not disabled, show it */
- for(c = 0; c < width; c++)
- if(i + c < size)
- fprintf(stream, "%02x ", ptr[i + c]);
- else
- fputs(" ", stream);
- }
- for(c = 0; (c < width) && (i + c < size); c++) {
- /* check for 0D0A; if found, skip past and start a new line of output */
- if((tracetype == TRACE_ASCII) &&
- (i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
- (ptr[i + c + 1] == 0x0A)) {
- i += (c + 2 - width);
- break;
- }
- #ifdef CURL_DOES_CONVERSIONS
- /* repeat the 0D0A check above but use the host encoding for CRLF */
- if((tracetype == TRACE_ASCII) &&
- (i + c + 1 < size) && (ptr[i + c] == '\r') &&
- (ptr[i + c + 1] == '\n')) {
- i += (c + 2 - width);
- break;
- }
- /* convert to host encoding and print this character */
- fprintf(stream, "%c", convert_char(infotype, ptr[i + c]));
- #else
- (void)infotype;
- fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80)) ?
- ptr[i + c] : UNPRINTABLE_CHAR);
- #endif /* CURL_DOES_CONVERSIONS */
- /* check again for 0D0A, to avoid an extra \n if it's at width */
- if((tracetype == TRACE_ASCII) &&
- (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
- (ptr[i + c + 2] == 0x0A)) {
- i += (c + 3 - width);
- break;
- }
- }
- fputc('\n', stream); /* newline */
- }
- fflush(stream);
- }
|