tool_cb_dbg.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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.haxx.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  ***************************************************************************/
22 #include "tool_setup.h"
23 
24 #define ENABLE_CURLX_PRINTF
25 /* use our own printf() functions */
26 #include "curlx.h"
27 
28 #include "tool_cfgable.h"
29 #include "tool_convert.h"
30 #include "tool_msgs.h"
31 #include "tool_cb_dbg.h"
32 #include "tool_util.h"
33 
34 #include "memdebug.h" /* keep this as LAST include */
35 
36 static void dump(const char *timebuf, const char *text,
37  FILE *stream, const unsigned char *ptr, size_t size,
38  trace tracetype, curl_infotype infotype);
39 
40 /*
41 ** callback for CURLOPT_DEBUGFUNCTION
42 */
43 
44 int tool_debug_cb(CURL *handle, curl_infotype type,
45  char *data, size_t size,
46  void *userdata)
47 {
48  struct OperationConfig *operation = userdata;
49  struct GlobalConfig *config = operation->global;
50  FILE *output = config->errors;
51  const char *text;
52  struct timeval tv;
53  struct tm *now;
54  char timebuf[20];
55  time_t secs;
56  static time_t epoch_offset;
57  static int known_offset;
58 
59  (void)handle; /* not used */
60 
61  if(config->tracetime) {
62  tv = tvnow();
63  if(!known_offset) {
64  epoch_offset = time(NULL) - tv.tv_sec;
65  known_offset = 1;
66  }
67  secs = epoch_offset + tv.tv_sec;
68  now = localtime(&secs); /* not thread safe but we don't care */
69  snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
70  now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
71  }
72  else
73  timebuf[0] = 0;
74 
75  if(!config->trace_stream) {
76  /* open for append */
77  if(!strcmp("-", config->trace_dump))
78  config->trace_stream = stdout;
79  else if(!strcmp("%", config->trace_dump))
80  /* Ok, this is somewhat hackish but we do it undocumented for now */
81  config->trace_stream = config->errors; /* aka stderr */
82  else {
83  config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT);
84  config->trace_fopened = TRUE;
85  }
86  }
87 
88  if(config->trace_stream)
89  output = config->trace_stream;
90 
91  if(!output) {
92  warnf(config, "Failed to create/open output");
93  return 0;
94  }
95 
96  if(config->tracetype == TRACE_PLAIN) {
97  /*
98  * This is the trace look that is similar to what libcurl makes on its
99  * own.
100  */
101  static const char * const s_infotype[] = {
102  "*", "<", ">", "{", "}", "{", "}"
103  };
104  size_t i;
105  size_t st = 0;
106  static bool newl = FALSE;
107  static bool traced_data = FALSE;
108 
109  switch(type) {
110  case CURLINFO_HEADER_OUT:
111  if(size > 0) {
112  for(i = 0; i < size - 1; i++) {
113  if(data[i] == '\n') { /* LF */
114  if(!newl) {
115  fprintf(output, "%s%s ", timebuf, s_infotype[type]);
116  }
117  (void)fwrite(data + st, i - st + 1, 1, output);
118  st = i + 1;
119  newl = FALSE;
120  }
121  }
122  if(!newl)
123  fprintf(output, "%s%s ", timebuf, s_infotype[type]);
124  (void)fwrite(data + st, i - st + 1, 1, output);
125  }
126  newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
127  traced_data = FALSE;
128  break;
129  case CURLINFO_TEXT:
130  case CURLINFO_HEADER_IN:
131  if(!newl)
132  fprintf(output, "%s%s ", timebuf, s_infotype[type]);
133  (void)fwrite(data, size, 1, output);
134  newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
135  traced_data = FALSE;
136  break;
137  case CURLINFO_DATA_OUT:
138  case CURLINFO_DATA_IN:
141  if(!traced_data) {
142  /* if the data is output to a tty and we're sending this debug trace
143  to stderr or stdout, we don't display the alert about the data not
144  being shown as the data _is_ shown then just not via this
145  function */
146  if(!config->isatty || ((output != stderr) && (output != stdout))) {
147  if(!newl)
148  fprintf(output, "%s%s ", timebuf, s_infotype[type]);
149  fprintf(output, "[%zd bytes data]\n", size);
150  newl = FALSE;
151  traced_data = TRUE;
152  }
153  }
154  break;
155  default: /* nada */
156  newl = FALSE;
157  traced_data = FALSE;
158  break;
159  }
160 
161  return 0;
162  }
163 
164 #ifdef CURL_DOES_CONVERSIONS
165  /* Special processing is needed for CURLINFO_HEADER_OUT blocks
166  * if they contain both headers and data (separated by CRLFCRLF).
167  * We dump the header text and then switch type to CURLINFO_DATA_OUT.
168  */
169  if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
170  size_t i;
171  for(i = 0; i < size - 4; i++) {
172  if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
173  /* dump everything through the CRLFCRLF as a sent header */
174  text = "=> Send header";
175  dump(timebuf, text, output, (unsigned char *)data, i + 4,
176  config->tracetype, type);
177  data += i + 3;
178  size -= i + 4;
179  type = CURLINFO_DATA_OUT;
180  data += 1;
181  break;
182  }
183  }
184  }
185 #endif /* CURL_DOES_CONVERSIONS */
186 
187  switch(type) {
188  case CURLINFO_TEXT:
189  fprintf(output, "%s== Info: %s", timebuf, data);
190  /* FALLTHROUGH */
191  default: /* in case a new one is introduced to shock us */
192  return 0;
193 
194  case CURLINFO_HEADER_OUT:
195  text = "=> Send header";
196  break;
197  case CURLINFO_DATA_OUT:
198  text = "=> Send data";
199  break;
200  case CURLINFO_HEADER_IN:
201  text = "<= Recv header";
202  break;
203  case CURLINFO_DATA_IN:
204  text = "<= Recv data";
205  break;
207  text = "<= Recv SSL data";
208  break;
210  text = "=> Send SSL data";
211  break;
212  }
213 
214  dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype,
215  type);
216  return 0;
217 }
218 
219 static void dump(const char *timebuf, const char *text,
220  FILE *stream, const unsigned char *ptr, size_t size,
221  trace tracetype, curl_infotype infotype)
222 {
223  size_t i;
224  size_t c;
225 
226  unsigned int width = 0x10;
227 
228  if(tracetype == TRACE_ASCII)
229  /* without the hex output, we can fit more on screen */
230  width = 0x40;
231 
232  fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
233 
234  for(i = 0; i < size; i += width) {
235 
236  fprintf(stream, "%04zx: ", i);
237 
238  if(tracetype == TRACE_BIN) {
239  /* hex not disabled, show it */
240  for(c = 0; c < width; c++)
241  if(i + c < size)
242  fprintf(stream, "%02x ", ptr[i + c]);
243  else
244  fputs(" ", stream);
245  }
246 
247  for(c = 0; (c < width) && (i + c < size); c++) {
248  /* check for 0D0A; if found, skip past and start a new line of output */
249  if((tracetype == TRACE_ASCII) &&
250  (i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
251  (ptr[i + c + 1] == 0x0A)) {
252  i += (c + 2 - width);
253  break;
254  }
255 #ifdef CURL_DOES_CONVERSIONS
256  /* repeat the 0D0A check above but use the host encoding for CRLF */
257  if((tracetype == TRACE_ASCII) &&
258  (i + c + 1 < size) && (ptr[i + c] == '\r') &&
259  (ptr[i + c + 1] == '\n')) {
260  i += (c + 2 - width);
261  break;
262  }
263  /* convert to host encoding and print this character */
264  fprintf(stream, "%c", convert_char(infotype, ptr[i + c]));
265 #else
266  (void)infotype;
267  fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80)) ?
268  ptr[i + c] : UNPRINTABLE_CHAR);
269 #endif /* CURL_DOES_CONVERSIONS */
270  /* check again for 0D0A, to avoid an extra \n if it's at width */
271  if((tracetype == TRACE_ASCII) &&
272  (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
273  (ptr[i + c + 2] == 0x0A)) {
274  i += (c + 3 - width);
275  break;
276  }
277  }
278  fputc('\n', stream); /* newline */
279  }
280  fflush(stream);
281 }
282 
static struct timeval tvnow(void)
Definition: imap-multi.c:41
Definition: ws_ssl.c:25
UNITTEST_START char * ptr
Definition: unit1330.c:38
struct curltime now
Definition: unit1399.c:83
bool trace_fopened
Definition: tool_cfgable.h:268
struct GlobalConfig * global
Definition: tool_cfgable.h:251
unsigned int i
Definition: unit1303.c:79
FILE * trace_stream
Definition: tool_cfgable.h:267
trace
Definition: tool_sdecls.h:122
static time_t epoch_offset
Definition: testtrace.c:30
#define FOPEN_WRITETEXT
Definition: curl_setup.h:733
UNITTEST_START char * output
Definition: unit1302.c:50
#define FALSE
int tool_debug_cb(CURL *handle, curl_infotype type, char *data, size_t size, void *userdata)
Definition: tool_cb_dbg.c:44
int width
Definition: unit1398.c:34
static int known_offset
Definition: testtrace.c:31
#define UNPRINTABLE_CHAR
Definition: tool_setup.h:66
void CURL
Definition: curl.h:102
char * trace_dump
Definition: tool_cfgable.h:266
size_t size
Definition: unit1302.c:52
#define fprintf
Definition: curl_printf.h:41
#define snprintf
Definition: curl_printf.h:42
#define TRUE
curl_infotype
Definition: curl.h:429
void warnf(struct GlobalConfig *config, const char *fmt,...)
Definition: tool_msgs.c:95
size_t fwrite(const void *, size_t, size_t, FILE *)
Definition: debug.c:29
static void dump(const char *timebuf, const char *text, FILE *stream, const unsigned char *ptr, size_t size, trace tracetype, curl_infotype infotype)
Definition: tool_cb_dbg.c:219


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16