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