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