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