Made some variables const
[platform/upstream/curl.git] / lib / sendf.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2008, 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 http://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  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <errno.h>
30
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h> /* required for send() & recv() prototypes */
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <curl/curl.h>
40 #include "urldata.h"
41 #include "sendf.h"
42 #include "connect.h"
43 #include "sslgen.h"
44 #include "ssh.h"
45 #include "multiif.h"
46
47 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
48 #include <curl/mprintf.h>
49
50 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
51 #include "krb4.h"
52 #else
53 #define Curl_sec_send(a,b,c,d) -1
54 #define Curl_sec_read(a,b,c,d) -1
55 #endif
56
57 #include <string.h>
58 #include "memory.h"
59 #include "strerror.h"
60 #include "easyif.h" /* for the Curl_convert_from_network prototype */
61 /* The last #include file should be: */
62 #include "memdebug.h"
63
64 /* returns last node in linked list */
65 static struct curl_slist *slist_get_last(struct curl_slist *list)
66 {
67   struct curl_slist     *item;
68
69   /* if caller passed us a NULL, return now */
70   if(!list)
71     return NULL;
72
73   /* loop through to find the last item */
74   item = list;
75   while(item->next) {
76     item = item->next;
77   }
78   return item;
79 }
80
81 /*
82  * curl_slist_append() appends a string to the linked list. It always returns
83  * the address of the first record, so that you can use this function as an
84  * initialization function as well as an append function. If you find this
85  * bothersome, then simply create a separate _init function and call it
86  * appropriately from within the program.
87  */
88 struct curl_slist *curl_slist_append(struct curl_slist *list,
89                                      const char *data)
90 {
91   struct curl_slist     *last;
92   struct curl_slist     *new_item;
93
94   new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
95   if(new_item) {
96     char *dupdata = strdup(data);
97     if(dupdata) {
98       new_item->next = NULL;
99       new_item->data = dupdata;
100     }
101     else {
102       free(new_item);
103       return NULL;
104     }
105   }
106   else
107     return NULL;
108
109   if(list) {
110     last = slist_get_last(list);
111     last->next = new_item;
112     return list;
113   }
114
115   /* if this is the first item, then new_item *is* the list */
116   return new_item;
117 }
118
119 /* be nice and clean up resources */
120 void curl_slist_free_all(struct curl_slist *list)
121 {
122   struct curl_slist     *next;
123   struct curl_slist     *item;
124
125   if(!list)
126     return;
127
128   item = list;
129   do {
130     next = item->next;
131
132     if(item->data) {
133       free(item->data);
134     }
135     free(item);
136     item = next;
137   } while(next);
138 }
139
140 #ifdef CURL_DO_LINEEND_CONV
141 /*
142  * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
143  * (\n), with special processing for CRLF sequences that are split between two
144  * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
145  * size of the data is returned.
146  */
147 static size_t convert_lineends(struct SessionHandle *data,
148                                char *startPtr, size_t size)
149 {
150   char *inPtr, *outPtr;
151
152   /* sanity check */
153   if((startPtr == NULL) || (size < 1)) {
154     return(size);
155   }
156
157   if(data->state.prev_block_had_trailing_cr == TRUE) {
158     /* The previous block of incoming data
159        had a trailing CR, which was turned into a LF. */
160     if(*startPtr == '\n') {
161       /* This block of incoming data starts with the
162          previous block's LF so get rid of it */
163       memmove(startPtr, startPtr+1, size-1);
164       size--;
165       /* and it wasn't a bare CR but a CRLF conversion instead */
166       data->state.crlf_conversions++;
167     }
168     data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
169   }
170
171   /* find 1st CR, if any */
172   inPtr = outPtr = memchr(startPtr, '\r', size);
173   if(inPtr) {
174     /* at least one CR, now look for CRLF */
175     while(inPtr < (startPtr+size-1)) {
176       /* note that it's size-1, so we'll never look past the last byte */
177       if(memcmp(inPtr, "\r\n", 2) == 0) {
178         /* CRLF found, bump past the CR and copy the NL */
179         inPtr++;
180         *outPtr = *inPtr;
181         /* keep track of how many CRLFs we converted */
182         data->state.crlf_conversions++;
183       }
184       else {
185         if(*inPtr == '\r') {
186           /* lone CR, move LF instead */
187           *outPtr = '\n';
188         }
189         else {
190           /* not a CRLF nor a CR, just copy whatever it is */
191           *outPtr = *inPtr;
192         }
193       }
194       outPtr++;
195       inPtr++;
196     } /* end of while loop */
197
198     if(inPtr < startPtr+size) {
199       /* handle last byte */
200       if(*inPtr == '\r') {
201         /* deal with a CR at the end of the buffer */
202         *outPtr = '\n'; /* copy a NL instead */
203         /* note that a CRLF might be split across two blocks */
204         data->state.prev_block_had_trailing_cr = TRUE;
205       }
206       else {
207         /* copy last byte */
208         *outPtr = *inPtr;
209       }
210       outPtr++;
211       inPtr++;
212     }
213     if(outPtr < startPtr+size) {
214       /* tidy up by null terminating the now shorter data */
215       *outPtr = '\0';
216     }
217     return(outPtr - startPtr);
218   }
219   return(size);
220 }
221 #endif /* CURL_DO_LINEEND_CONV */
222
223 /* Curl_infof() is for info message along the way */
224
225 void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
226 {
227   if(data && data->set.verbose) {
228     va_list ap;
229     size_t len;
230     char print_buffer[1024 + 1];
231     va_start(ap, fmt);
232     vsnprintf(print_buffer, 1024, fmt, ap);
233     va_end(ap);
234     len = strlen(print_buffer);
235     Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
236   }
237 }
238
239 /* Curl_failf() is for messages stating why we failed.
240  * The message SHALL NOT include any LF or CR.
241  */
242
243 void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
244 {
245   va_list ap;
246   size_t len;
247   va_start(ap, fmt);
248
249   vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
250
251   if(data->set.errorbuffer && !data->state.errorbuf) {
252     snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
253     data->state.errorbuf = TRUE; /* wrote error string */
254   }
255   if(data->set.verbose) {
256     len = strlen(data->state.buffer);
257     if(len < BUFSIZE - 1) {
258       data->state.buffer[len] = '\n';
259       data->state.buffer[++len] = '\0';
260     }
261     Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
262   }
263
264   va_end(ap);
265 }
266
267 /* Curl_sendf() sends formated data to the server */
268 CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
269                     const char *fmt, ...)
270 {
271   struct SessionHandle *data = conn->data;
272   ssize_t bytes_written;
273   size_t write_len;
274   CURLcode res = CURLE_OK;
275   char *s;
276   char *sptr;
277   va_list ap;
278   va_start(ap, fmt);
279   s = vaprintf(fmt, ap); /* returns an allocated string */
280   va_end(ap);
281   if(!s)
282     return CURLE_OUT_OF_MEMORY; /* failure */
283
284   bytes_written=0;
285   write_len = strlen(s);
286   sptr = s;
287
288   while(1) {
289     /* Write the buffer to the socket */
290     res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
291
292     if(CURLE_OK != res)
293       break;
294
295     if(data->set.verbose)
296       Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
297
298     if((size_t)bytes_written != write_len) {
299       /* if not all was written at once, we must advance the pointer, decrease
300          the size left and try again! */
301       write_len -= bytes_written;
302       sptr += bytes_written;
303     }
304     else
305       break;
306   }
307
308   free(s); /* free the output string */
309
310   return res;
311 }
312
313 static ssize_t send_plain(struct connectdata *conn,
314                           int num,
315                           const void *mem,
316                           size_t len)
317 {
318   curl_socket_t sockfd = conn->sock[num];
319   ssize_t bytes_written = swrite(sockfd, mem, len);
320
321   if(-1 == bytes_written) {
322     int err = SOCKERRNO;
323
324     if(
325 #ifdef WSAEWOULDBLOCK
326       /* This is how Windows does it */
327       (WSAEWOULDBLOCK == err)
328 #else
329       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
330          due to its inability to send off data without blocking. We therefor
331          treat both error codes the same here */
332       (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
333 #endif
334       )
335       /* this is just a case of EWOULDBLOCK */
336       bytes_written=0;
337     else
338       failf(conn->data, "Send failure: %s",
339             Curl_strerror(conn, err));
340   }
341   return bytes_written;
342 }
343
344 /*
345  * Curl_write() is an internal write function that sends data to the
346  * server. Works with plain sockets, SCP, SSL or kerberos.
347  */
348 CURLcode Curl_write(struct connectdata *conn,
349                     curl_socket_t sockfd,
350                     const void *mem,
351                     size_t len,
352                     ssize_t *written)
353 {
354   ssize_t bytes_written;
355   CURLcode retcode;
356   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
357
358   if(conn->ssl[num].state == ssl_connection_complete)
359     bytes_written = Curl_ssl_send(conn, num, mem, len);
360   else if(Curl_ssh_enabled(conn, PROT_SCP))
361     bytes_written = Curl_scp_send(conn, num, mem, len);
362   else if(Curl_ssh_enabled(conn, PROT_SFTP))
363     bytes_written = Curl_sftp_send(conn, num, mem, len);
364   else if(conn->sec_complete)
365     bytes_written = Curl_sec_send(conn, num, mem, len);
366   else
367     bytes_written = send_plain(conn, num, mem, len);
368
369   *written = bytes_written;
370   retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
371
372   return retcode;
373 }
374
375 /*
376  * Curl_write_plain() is an internal write function that sends data to the
377  * server using plain sockets only. Otherwise meant to have the exact same
378  * proto as Curl_write()
379  */
380 CURLcode Curl_write_plain(struct connectdata *conn,
381                           curl_socket_t sockfd,
382                           const void *mem,
383                           size_t len,
384                           ssize_t *written)
385 {
386   ssize_t bytes_written;
387   CURLcode retcode;
388   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
389
390   bytes_written = send_plain(conn, num, mem, len);
391
392   *written = bytes_written;
393   retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
394
395   return retcode;
396 }
397
398 static CURLcode pausewrite(struct SessionHandle *data,
399                            int type, /* what type of data */
400                            const char *ptr,
401                            size_t len)
402 {
403   /* signalled to pause sending on this connection, but since we have data
404      we want to send we need to dup it to save a copy for when the sending
405      is again enabled */
406   struct SingleRequest *k = &data->req;
407   char *dupl = malloc(len);
408   if(!dupl)
409     return CURLE_OUT_OF_MEMORY;
410
411   memcpy(dupl, ptr, len);
412
413   /* store this information in the state struct for later use */
414   data->state.tempwrite = dupl;
415   data->state.tempwritesize = len;
416   data->state.tempwritetype = type;
417
418   /* mark the connection as RECV paused */
419   k->keepon |= KEEP_READ_PAUSE;
420
421   DEBUGF(infof(data, "Pausing with %d bytes in buffer for type %02x\n",
422                (int)len, type));
423
424   return CURLE_OK;
425 }
426
427
428 /* client_write() sends data to the write callback(s)
429
430    The bit pattern defines to what "streams" to write to. Body and/or header.
431    The defines are in sendf.h of course.
432
433    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
434    local character encoding.  This is a problem and should be changed in
435    the future to leave the original data alone.
436  */
437 CURLcode Curl_client_write(struct connectdata *conn,
438                            int type,
439                            char *ptr,
440                            size_t len)
441 {
442   struct SessionHandle *data = conn->data;
443   size_t wrote;
444
445   /* If reading is actually paused, we're forced to append this chunk of data
446      to the already held data, but only if it is the same type as otherwise it
447      can't work and it'll return error instead. */
448   if(data->req.keepon & KEEP_READ_PAUSE) {
449     size_t newlen;
450     char *newptr;
451     if(type != data->state.tempwritetype)
452       /* major internal confusion */
453       return CURLE_RECV_ERROR;
454
455     /* figure out the new size of the data to save */
456     newlen = len + data->state.tempwritesize;
457     /* allocate the new memory area */
458     newptr = malloc(newlen);
459     if(!newptr)
460       return CURLE_OUT_OF_MEMORY;
461     /* copy the previously held data to the new area */
462     memcpy(newptr, data->state.tempwrite, data->state.tempwritesize);
463     /* copy the new data to the end of the new area */
464     memcpy(newptr + data->state.tempwritesize, ptr, len);
465     /* free the old data */
466     free(data->state.tempwrite);
467     /* update the pointer and the size */
468     data->state.tempwrite = newptr;
469     data->state.tempwritesize = newlen;
470
471     return CURLE_OK;
472   }
473
474   if(0 == len)
475     len = strlen(ptr);
476
477   if(type & CLIENTWRITE_BODY) {
478     if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') {
479 #ifdef CURL_DOES_CONVERSIONS
480       /* convert from the network encoding */
481       size_t rc;
482       rc = Curl_convert_from_network(data, ptr, len);
483       /* Curl_convert_from_network calls failf if unsuccessful */
484       if(rc != CURLE_OK)
485         return rc;
486 #endif /* CURL_DOES_CONVERSIONS */
487
488 #ifdef CURL_DO_LINEEND_CONV
489       /* convert end-of-line markers */
490       len = convert_lineends(data, ptr, len);
491 #endif /* CURL_DO_LINEEND_CONV */
492     }
493     /* If the previous block of data ended with CR and this block of data is
494        just a NL, then the length might be zero */
495     if(len) {
496       wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);
497     }
498     else {
499       wrote = len;
500     }
501
502     if(CURL_WRITEFUNC_PAUSE == wrote)
503       return pausewrite(data, type, ptr, len);
504
505     if(wrote != len) {
506       failf(data, "Failed writing body (%d != %d)", (int)wrote, (int)len);
507       return CURLE_WRITE_ERROR;
508     }
509   }
510
511   if((type & CLIENTWRITE_HEADER) &&
512      (data->set.fwrite_header || data->set.writeheader) ) {
513     /*
514      * Write headers to the same callback or to the especially setup
515      * header callback function (added after version 7.7.1).
516      */
517     curl_write_callback writeit=
518       data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite_func;
519
520     /* Note: The header is in the host encoding
521        regardless of the ftp transfer mode (ASCII/Image) */
522
523     wrote = writeit(ptr, 1, len, data->set.writeheader);
524     if(CURL_WRITEFUNC_PAUSE == wrote)
525       /* here we pass in the HEADER bit only since if this was body as well
526          then it was passed already and clearly that didn't trigger the pause,
527          so this is saved for later with the HEADER bit only */
528       return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
529
530     if(wrote != len) {
531       failf (data, "Failed writing header");
532       return CURLE_WRITE_ERROR;
533     }
534   }
535
536   return CURLE_OK;
537 }
538
539 #ifndef MIN
540 #define MIN(a,b) ((a) < (b) ? (a) : (b))
541 #endif
542
543 /*
544  * Internal read-from-socket function. This is meant to deal with plain
545  * sockets, SSL sockets and kerberos sockets.
546  *
547  * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
548  * a regular CURLcode value.
549  */
550 int Curl_read(struct connectdata *conn, /* connection data */
551               curl_socket_t sockfd,     /* read from this socket */
552               char *buf,                /* store read data here */
553               size_t sizerequested,     /* max amount to read */
554               ssize_t *n)               /* amount bytes read */
555 {
556   ssize_t nread = 0;
557   size_t bytesfromsocket = 0;
558   char *buffertofill = NULL;
559   bool pipelining = (bool)(conn->data->multi &&
560                      Curl_multi_canPipeline(conn->data->multi));
561
562   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
563      If it is the second socket, we set num to 1. Otherwise to 0. This lets
564      us use the correct ssl handle. */
565   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
566
567   *n=0; /* reset amount to zero */
568
569   /* If session can pipeline, check connection buffer  */
570   if(pipelining) {
571     size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
572
573     /* Copy from our master buffer first if we have some unread data there*/
574     if(bytestocopy > 0) {
575       memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
576       conn->read_pos += bytestocopy;
577       conn->bits.stream_was_rewound = FALSE;
578
579       *n = (ssize_t)bytestocopy;
580       return CURLE_OK;
581     }
582     /* If we come here, it means that there is no data to read from the buffer,
583      * so we read from the socket */
584     bytesfromsocket = MIN(sizerequested, BUFSIZE * sizeof (char));
585     buffertofill = conn->master_buffer;
586   }
587   else {
588     bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ?
589                           conn->data->set.buffer_size : BUFSIZE);
590     buffertofill = buf;
591   }
592
593   if(conn->ssl[num].state == ssl_connection_complete) {
594     nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket);
595
596     if(nread == -1) {
597       return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
598     }
599   }
600   else if(Curl_ssh_enabled(conn, (PROT_SCP|PROT_SFTP))) {
601     if(conn->protocol & PROT_SCP)
602       nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket);
603     else if(conn->protocol & PROT_SFTP)
604       nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket);
605 #ifdef LIBSSH2CHANNEL_EAGAIN
606     if((nread == LIBSSH2CHANNEL_EAGAIN) || (nread == 0))
607       /* EWOULDBLOCK */
608       return -1;
609 #endif
610     if(nread < 0)
611       /* since it is negative and not EGAIN, it was a protocol-layer error */
612       return CURLE_RECV_ERROR;
613   }
614   else {
615     if(conn->sec_complete)
616       nread = Curl_sec_read(conn, sockfd, buffertofill,
617                             bytesfromsocket);
618     else
619       nread = sread(sockfd, buffertofill, bytesfromsocket);
620
621     if(-1 == nread) {
622       int err = SOCKERRNO;
623 #ifdef USE_WINSOCK
624       if(WSAEWOULDBLOCK == err)
625 #else
626       if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
627 #endif
628         return -1;
629     }
630   }
631
632   if(nread >= 0) {
633     if(pipelining) {
634       memcpy(buf, conn->master_buffer, nread);
635       conn->buf_len = nread;
636       conn->read_pos = nread;
637     }
638
639     *n += nread;
640   }
641
642   return CURLE_OK;
643 }
644
645 /* return 0 on success */
646 static int showit(struct SessionHandle *data, curl_infotype type,
647                   char *ptr, size_t size)
648 {
649   static const char * const s_infotype[CURLINFO_END] = {
650     "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
651
652 #ifdef CURL_DOES_CONVERSIONS
653   char buf[BUFSIZE+1];
654   size_t conv_size = 0;
655
656   switch(type) {
657   case CURLINFO_HEADER_OUT:
658     /* assume output headers are ASCII */
659     /* copy the data into my buffer so the original is unchanged */
660     if(size > BUFSIZE) {
661       size = BUFSIZE; /* truncate if necessary */
662       buf[BUFSIZE] = '\0';
663     }
664     conv_size = size;
665     memcpy(buf, ptr, size);
666     /* Special processing is needed for this block if it
667      * contains both headers and data (separated by CRLFCRLF).
668      * We want to convert just the headers, leaving the data as-is.
669      */
670     if(size > 4) {
671       size_t i;
672       for(i = 0; i < size-4; i++) {
673         if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
674           /* convert everthing through this CRLFCRLF but no further */
675           conv_size = i + 4;
676           break;
677         }
678       }
679     }
680
681     Curl_convert_from_network(data, buf, conv_size);
682     /* Curl_convert_from_network calls failf if unsuccessful */
683     /* we might as well continue even if it fails...   */
684     ptr = buf; /* switch pointer to use my buffer instead */
685     break;
686   default:
687     /* leave everything else as-is */
688     break;
689   }
690 #endif /* CURL_DOES_CONVERSIONS */
691
692   if(data->set.fdebug)
693     return (*data->set.fdebug)(data, type, ptr, size,
694                                data->set.debugdata);
695
696   switch(type) {
697   case CURLINFO_TEXT:
698   case CURLINFO_HEADER_OUT:
699   case CURLINFO_HEADER_IN:
700     fwrite(s_infotype[type], 2, 1, data->set.err);
701     fwrite(ptr, size, 1, data->set.err);
702 #ifdef CURL_DOES_CONVERSIONS
703     if(size != conv_size) {
704       /* we had untranslated data so we need an explicit newline */
705       fwrite("\n", 1, 1, data->set.err);
706     }
707 #endif
708     break;
709   default: /* nada */
710     break;
711   }
712   return 0;
713 }
714
715 int Curl_debug(struct SessionHandle *data, curl_infotype type,
716                char *ptr, size_t size,
717                struct connectdata *conn)
718 {
719   int rc;
720   if(data->set.printhost && conn && conn->host.dispname) {
721     char buffer[160];
722     const char *t=NULL;
723     const char *w="Data";
724     switch (type) {
725     case CURLINFO_HEADER_IN:
726       w = "Header";
727     case CURLINFO_DATA_IN:
728       t = "from";
729       break;
730     case CURLINFO_HEADER_OUT:
731       w = "Header";
732     case CURLINFO_DATA_OUT:
733       t = "to";
734       break;
735     default:
736       break;
737     }
738
739     if(t) {
740       snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
741                conn->host.dispname);
742       rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
743       if(rc)
744         return rc;
745     }
746   }
747   rc = showit(data, type, ptr, size);
748   return rc;
749 }