1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.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#ifdef HAVE_NETINET_IN_H
26#include <netinet/in.h>
27#endif
28
29#ifdef HAVE_LINUX_TCP_H
30#include <linux/tcp.h>
31#elif defined(HAVE_NETINET_TCP_H)
32#include <netinet/tcp.h>
33#endif
34
35#include <curl/curl.h>
36
37#include "urldata.h"
38#include "sendf.h"
39#include "connect.h"
40#include "vtls/vtls.h"
41#include "vssh/ssh.h"
42#include "easyif.h"
43#include "multiif.h"
44#include "non-ascii.h"
45#include "strerror.h"
46#include "select.h"
47#include "strdup.h"
48#include "http2.h"
49
50/* The last 3 #include files should be in this order */
51#include "curl_printf.h"
52#include "curl_memory.h"
53#include "memdebug.h"
54
55#ifdef CURL_DO_LINEEND_CONV
56/*
57 * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
58 * (\n), with special processing for CRLF sequences that are split between two
59 * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
60 * size of the data is returned.
61 */
62static size_t convert_lineends(struct Curl_easy *data,
63 char *startPtr, size_t size)
64{
65 char *inPtr, *outPtr;
66
67 /* sanity check */
68 if(!startPtr || (size < 1)) {
69 return size;
70 }
71
72 if(data->state.prev_block_had_trailing_cr) {
73 /* The previous block of incoming data
74 had a trailing CR, which was turned into a LF. */
75 if(*startPtr == '\n') {
76 /* This block of incoming data starts with the
77 previous block's LF so get rid of it */
78 memmove(startPtr, startPtr + 1, size-1);
79 size--;
80 /* and it wasn't a bare CR but a CRLF conversion instead */
81 data->state.crlf_conversions++;
82 }
83 data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
84 }
85
86 /* find 1st CR, if any */
87 inPtr = outPtr = memchr(startPtr, '\r', size);
88 if(inPtr) {
89 /* at least one CR, now look for CRLF */
90 while(inPtr < (startPtr + size-1)) {
91 /* note that it's size-1, so we'll never look past the last byte */
92 if(memcmp(inPtr, "\r\n", 2) == 0) {
93 /* CRLF found, bump past the CR and copy the NL */
94 inPtr++;
95 *outPtr = *inPtr;
96 /* keep track of how many CRLFs we converted */
97 data->state.crlf_conversions++;
98 }
99 else {
100 if(*inPtr == '\r') {
101 /* lone CR, move LF instead */
102 *outPtr = '\n';
103 }
104 else {
105 /* not a CRLF nor a CR, just copy whatever it is */
106 *outPtr = *inPtr;
107 }
108 }
109 outPtr++;
110 inPtr++;
111 } /* end of while loop */
112
113 if(inPtr < startPtr + size) {
114 /* handle last byte */
115 if(*inPtr == '\r') {
116 /* deal with a CR at the end of the buffer */
117 *outPtr = '\n'; /* copy a NL instead */
118 /* note that a CRLF might be split across two blocks */
119 data->state.prev_block_had_trailing_cr = TRUE;
120 }
121 else {
122 /* copy last byte */
123 *outPtr = *inPtr;
124 }
125 outPtr++;
126 }
127 if(outPtr < startPtr + size)
128 /* tidy up by null terminating the now shorter data */
129 *outPtr = '\0';
130
131 return (outPtr - startPtr);
132 }
133 return size;
134}
135#endif /* CURL_DO_LINEEND_CONV */
136
137#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
138bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
139{
140 struct postponed_data * const psnd = &(conn->postponed[sockindex]);
141 return psnd->buffer && psnd->allocated_size &&
142 psnd->recv_size > psnd->recv_processed;
143}
144
145static CURLcode pre_receive_plain(struct Curl_easy *data,
146 struct connectdata *conn, int num)
147{
148 const curl_socket_t sockfd = conn->sock[num];
149 struct postponed_data * const psnd = &(conn->postponed[num]);
150 size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
151 /* WinSock will destroy unread received data if send() is
152 failed.
153 To avoid lossage of received data, recv() must be
154 performed before every send() if any incoming data is
155 available. However, skip this, if buffer is already full. */
156 if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
157 conn->recv[num] == Curl_recv_plain &&
158 (!psnd->buffer || bytestorecv)) {
159 const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
160 CURL_SOCKET_BAD, 0);
161 if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
162 /* Have some incoming data */
163 if(!psnd->buffer) {
164 /* Use buffer double default size for intermediate buffer */
165 psnd->allocated_size = 2 * data->set.buffer_size;
166 psnd->buffer = malloc(psnd->allocated_size);
167 if(!psnd->buffer)
168 return CURLE_OUT_OF_MEMORY;
169 psnd->recv_size = 0;
170 psnd->recv_processed = 0;
171#ifdef DEBUGBUILD
172 psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
173#endif /* DEBUGBUILD */
174 bytestorecv = psnd->allocated_size;
175 }
176 if(psnd->buffer) {
177 ssize_t recvedbytes;
178 DEBUGASSERT(psnd->bindsock == sockfd);
179 recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
180 bytestorecv);
181 if(recvedbytes > 0)
182 psnd->recv_size += recvedbytes;
183 }
184 else
185 psnd->allocated_size = 0;
186 }
187 }
188 return CURLE_OK;
189}
190
191static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
192 size_t len)
193{
194 struct postponed_data * const psnd = &(conn->postponed[num]);
195 size_t copysize;
196 if(!psnd->buffer)
197 return 0;
198
199 DEBUGASSERT(psnd->allocated_size > 0);
200 DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
201 DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
202 /* Check and process data that already received and storied in internal
203 intermediate buffer */
204 if(psnd->recv_size > psnd->recv_processed) {
205 DEBUGASSERT(psnd->bindsock == conn->sock[num]);
206 copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
207 memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
208 psnd->recv_processed += copysize;
209 }
210 else
211 copysize = 0; /* buffer was allocated, but nothing was received */
212
213 /* Free intermediate buffer if it has no unprocessed data */
214 if(psnd->recv_processed == psnd->recv_size) {
215 free(psnd->buffer);
216 psnd->buffer = NULL;
217 psnd->allocated_size = 0;
218 psnd->recv_size = 0;
219 psnd->recv_processed = 0;
220#ifdef DEBUGBUILD
221 psnd->bindsock = CURL_SOCKET_BAD;
222#endif /* DEBUGBUILD */
223 }
224 return (ssize_t)copysize;
225}
226#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
227/* Use "do-nothing" macros instead of functions when workaround not used */
228bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
229{
230 (void)conn;
231 (void)sockindex;
232 return false;
233}
234#define pre_receive_plain(d,c,n) CURLE_OK
235#define get_pre_recved(c,n,b,l) 0
236#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
237
238/* Curl_infof() is for info message along the way */
239#define MAXINFO 2048
240
241void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
242{
243 DEBUGASSERT(!strchr(fmt, '\n'));
244 if(data && data->set.verbose) {
245 va_list ap;
246 size_t len;
247 char buffer[MAXINFO + 2];
248 va_start(ap, fmt);
249 len = mvsnprintf(buffer, MAXINFO, fmt, ap);
250 va_end(ap);
251 buffer[len++] = '\n';
252 buffer[len] = '\0';
253 Curl_debug(data, CURLINFO_TEXT, buffer, len);
254 }
255}
256
257/* Curl_failf() is for messages stating why we failed.
258 * The message SHALL NOT include any LF or CR.
259 */
260
261void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
262{
263 DEBUGASSERT(!strchr(fmt, '\n'));
264 if(data->set.verbose || data->set.errorbuffer) {
265 va_list ap;
266 size_t len;
267 char error[CURL_ERROR_SIZE + 2];
268 va_start(ap, fmt);
269 len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
270
271 if(data->set.errorbuffer && !data->state.errorbuf) {
272 strcpy(data->set.errorbuffer, error);
273 data->state.errorbuf = TRUE; /* wrote error string */
274 }
275 error[len++] = '\n';
276 error[len] = '\0';
277 Curl_debug(data, CURLINFO_TEXT, error, len);
278 va_end(ap);
279 }
280}
281
282/*
283 * Curl_write() is an internal write function that sends data to the
284 * server. Works with plain sockets, SCP, SSL or kerberos.
285 *
286 * If the write would block (CURLE_AGAIN), we return CURLE_OK and
287 * (*written == 0). Otherwise we return regular CURLcode value.
288 */
289CURLcode Curl_write(struct Curl_easy *data,
290 curl_socket_t sockfd,
291 const void *mem,
292 size_t len,
293 ssize_t *written)
294{
295 ssize_t bytes_written;
296 CURLcode result = CURLE_OK;
297 struct connectdata *conn;
298 int num;
299 DEBUGASSERT(data);
300 DEBUGASSERT(data->conn);
301 conn = data->conn;
302 num = (sockfd == conn->sock[SECONDARYSOCKET]);
303
304#ifdef CURLDEBUG
305 {
306 /* Allow debug builds to override this logic to force short sends
307 */
308 char *p = getenv("CURL_SMALLSENDS");
309 if(p) {
310 size_t altsize = (size_t)strtoul(p, NULL, 10);
311 if(altsize)
312 len = CURLMIN(len, altsize);
313 }
314 }
315#endif
316 bytes_written = conn->send[num](data, num, mem, len, &result);
317
318 *written = bytes_written;
319 if(bytes_written >= 0)
320 /* we completely ignore the curlcode value when subzero is not returned */
321 return CURLE_OK;
322
323 /* handle CURLE_AGAIN or a send failure */
324 switch(result) {
325 case CURLE_AGAIN:
326 *written = 0;
327 return CURLE_OK;
328
329 case CURLE_OK:
330 /* general send failure */
331 return CURLE_SEND_ERROR;
332
333 default:
334 /* we got a specific curlcode, forward it */
335 return result;
336 }
337}
338
339ssize_t Curl_send_plain(struct Curl_easy *data, int num,
340 const void *mem, size_t len, CURLcode *code)
341{
342 struct connectdata *conn;
343 curl_socket_t sockfd;
344 ssize_t bytes_written;
345
346 DEBUGASSERT(data);
347 DEBUGASSERT(data->conn);
348 conn = data->conn;
349 sockfd = conn->sock[num];
350 /* WinSock will destroy unread received data if send() is
351 failed.
352 To avoid lossage of received data, recv() must be
353 performed before every send() if any incoming data is
354 available. */
355 if(pre_receive_plain(data, conn, num)) {
356 *code = CURLE_OUT_OF_MEMORY;
357 return -1;
358 }
359
360#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
361 if(conn->bits.tcp_fastopen) {
362 bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
363 conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
364 conn->bits.tcp_fastopen = FALSE;
365 }
366 else
367#endif
368 bytes_written = swrite(sockfd, mem, len);
369
370 *code = CURLE_OK;
371 if(-1 == bytes_written) {
372 int err = SOCKERRNO;
373
374 if(
375#ifdef WSAEWOULDBLOCK
376 /* This is how Windows does it */
377 (WSAEWOULDBLOCK == err)
378#else
379 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
380 due to its inability to send off data without blocking. We therefore
381 treat both error codes the same here */
382 (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
383 (EINPROGRESS == err)
384#endif
385 ) {
386 /* this is just a case of EWOULDBLOCK */
387 bytes_written = 0;
388 *code = CURLE_AGAIN;
389 }
390 else {
391 char buffer[STRERROR_LEN];
392 failf(data, "Send failure: %s",
393 Curl_strerror(err, buffer, sizeof(buffer)));
394 data->state.os_errno = err;
395 *code = CURLE_SEND_ERROR;
396 }
397 }
398 return bytes_written;
399}
400
401/*
402 * Curl_write_plain() is an internal write function that sends data to the
403 * server using plain sockets only. Otherwise meant to have the exact same
404 * proto as Curl_write()
405 */
406CURLcode Curl_write_plain(struct Curl_easy *data,
407 curl_socket_t sockfd,
408 const void *mem,
409 size_t len,
410 ssize_t *written)
411{
412 CURLcode result;
413 struct connectdata *conn = data->conn;
414 int num;
415 DEBUGASSERT(conn);
416 num = (sockfd == conn->sock[SECONDARYSOCKET]);
417
418 *written = Curl_send_plain(data, num, mem, len, &result);
419
420 return result;
421}
422
423ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
424 size_t len, CURLcode *code)
425{
426 struct connectdata *conn;
427 curl_socket_t sockfd;
428 ssize_t nread;
429 DEBUGASSERT(data);
430 DEBUGASSERT(data->conn);
431 conn = data->conn;
432 sockfd = conn->sock[num];
433 /* Check and return data that already received and storied in internal
434 intermediate buffer */
435 nread = get_pre_recved(conn, num, buf, len);
436 if(nread > 0) {
437 *code = CURLE_OK;
438 return nread;
439 }
440
441 nread = sread(sockfd, buf, len);
442
443 *code = CURLE_OK;
444 if(-1 == nread) {
445 int err = SOCKERRNO;
446
447 if(
448#ifdef WSAEWOULDBLOCK
449 /* This is how Windows does it */
450 (WSAEWOULDBLOCK == err)
451#else
452 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
453 due to its inability to send off data without blocking. We therefore
454 treat both error codes the same here */
455 (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
456#endif
457 ) {
458 /* this is just a case of EWOULDBLOCK */
459 *code = CURLE_AGAIN;
460 }
461 else {
462 char buffer[STRERROR_LEN];
463 failf(data, "Recv failure: %s",
464 Curl_strerror(err, buffer, sizeof(buffer)));
465 data->state.os_errno = err;
466 *code = CURLE_RECV_ERROR;
467 }
468 }
469 return nread;
470}
471
472static CURLcode pausewrite(struct Curl_easy *data,
473 int type, /* what type of data */
474 const char *ptr,
475 size_t len)
476{
477 /* signalled to pause sending on this connection, but since we have data
478 we want to send we need to dup it to save a copy for when the sending
479 is again enabled */
480 struct SingleRequest *k = &data->req;
481 struct UrlState *s = &data->state;
482 unsigned int i;
483 bool newtype = TRUE;
484
485 /* If this transfers over HTTP/2, pause the stream! */
486 Curl_http2_stream_pause(data, TRUE);
487
488 if(s->tempcount) {
489 for(i = 0; i< s->tempcount; i++) {
490 if(s->tempwrite[i].type == type) {
491 /* data for this type exists */
492 newtype = FALSE;
493 break;
494 }
495 }
496 DEBUGASSERT(i < 3);
497 }
498 else
499 i = 0;
500
501 if(newtype) {
502 /* store this information in the state struct for later use */
503 Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
504 s->tempwrite[i].type = type;
505 s->tempcount++;
506 }
507
508 if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
509 return CURLE_OUT_OF_MEMORY;
510
511 /* mark the connection as RECV paused */
512 k->keepon |= KEEP_RECV_PAUSE;
513
514 return CURLE_OK;
515}
516
517
518/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
519 * client write callback(s) and takes care of pause requests from the
520 * callbacks.
521 */
522static CURLcode chop_write(struct Curl_easy *data,
523 int type,
524 char *optr,
525 size_t olen)
526{
527 struct connectdata *conn = data->conn;
528 curl_write_callback writeheader = NULL;
529 curl_write_callback writebody = NULL;
530 char *ptr = optr;
531 size_t len = olen;
532
533 if(!len)
534 return CURLE_OK;
535
536 /* If reading is paused, append this data to the already held data for this
537 type. */
538 if(data->req.keepon & KEEP_RECV_PAUSE)
539 return pausewrite(data, type, ptr, len);
540
541 /* Determine the callback(s) to use. */
542 if(type & CLIENTWRITE_BODY)
543 writebody = data->set.fwrite_func;
544 if((type & CLIENTWRITE_HEADER) &&
545 (data->set.fwrite_header || data->set.writeheader)) {
546 /*
547 * Write headers to the same callback or to the especially setup
548 * header callback function (added after version 7.7.1).
549 */
550 writeheader =
551 data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
552 }
553
554 /* Chop data, write chunks. */
555 while(len) {
556 size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
557
558 if(writebody) {
559 size_t wrote;
560 Curl_set_in_callback(data, true);
561 wrote = writebody(ptr, 1, chunklen, data->set.out);
562 Curl_set_in_callback(data, false);
563
564 if(CURL_WRITEFUNC_PAUSE == wrote) {
565 if(conn->handler->flags & PROTOPT_NONETWORK) {
566 /* Protocols that work without network cannot be paused. This is
567 actually only FILE:// just now, and it can't pause since the
568 transfer isn't done using the "normal" procedure. */
569 failf(data, "Write callback asked for PAUSE when not supported!");
570 return CURLE_WRITE_ERROR;
571 }
572 return pausewrite(data, type, ptr, len);
573 }
574 if(wrote != chunklen) {
575 failf(data, "Failure writing output to destination");
576 return CURLE_WRITE_ERROR;
577 }
578 }
579
580 ptr += chunklen;
581 len -= chunklen;
582 }
583
584 if(writeheader) {
585 size_t wrote;
586 ptr = optr;
587 len = olen;
588 Curl_set_in_callback(data, true);
589 wrote = writeheader(ptr, 1, len, data->set.writeheader);
590 Curl_set_in_callback(data, false);
591
592 if(CURL_WRITEFUNC_PAUSE == wrote)
593 /* here we pass in the HEADER bit only since if this was body as well
594 then it was passed already and clearly that didn't trigger the
595 pause, so this is saved for later with the HEADER bit only */
596 return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
597
598 if(wrote != len) {
599 failf(data, "Failed writing header");
600 return CURLE_WRITE_ERROR;
601 }
602 }
603
604 return CURLE_OK;
605}
606
607
608/* Curl_client_write() sends data to the write callback(s)
609
610 The bit pattern defines to what "streams" to write to. Body and/or header.
611 The defines are in sendf.h of course. "len" is not allowed to be 0.
612
613 If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
614 local character encoding. This is a problem and should be changed in
615 the future to leave the original data alone.
616 */
617CURLcode Curl_client_write(struct Curl_easy *data,
618 int type,
619 char *ptr,
620 size_t len)
621{
622 struct connectdata *conn = data->conn;
623
624 DEBUGASSERT(len);
625 DEBUGASSERT(type <= 3);
626
627 /* FTP data may need conversion. */
628 if((type & CLIENTWRITE_BODY) &&
629 (conn->handler->protocol & PROTO_FAMILY_FTP) &&
630 conn->proto.ftpc.transfertype == 'A') {
631 /* convert from the network encoding */
632 CURLcode result = Curl_convert_from_network(data, ptr, len);
633 /* Curl_convert_from_network calls failf if unsuccessful */
634 if(result)
635 return result;
636
637#ifdef CURL_DO_LINEEND_CONV
638 /* convert end-of-line markers */
639 len = convert_lineends(data, ptr, len);
640#endif /* CURL_DO_LINEEND_CONV */
641 }
642
643 return chop_write(data, type, ptr, len);
644}
645
646CURLcode Curl_read_plain(curl_socket_t sockfd,
647 char *buf,
648 size_t bytesfromsocket,
649 ssize_t *n)
650{
651 ssize_t nread = sread(sockfd, buf, bytesfromsocket);
652
653 if(-1 == nread) {
654 const int err = SOCKERRNO;
655 const bool return_error =
656#ifdef USE_WINSOCK
657 WSAEWOULDBLOCK == err
658#else
659 EWOULDBLOCK == err || EAGAIN == err || EINTR == err
660#endif
661 ;
662 *n = 0; /* no data returned */
663 if(return_error)
664 return CURLE_AGAIN;
665 return CURLE_RECV_ERROR;
666 }
667
668 *n = nread;
669 return CURLE_OK;
670}
671
672/*
673 * Internal read-from-socket function. This is meant to deal with plain
674 * sockets, SSL sockets and kerberos sockets.
675 *
676 * Returns a regular CURLcode value.
677 */
678CURLcode Curl_read(struct Curl_easy *data, /* transfer */
679 curl_socket_t sockfd, /* read from this socket */
680 char *buf, /* store read data here */
681 size_t sizerequested, /* max amount to read */
682 ssize_t *n) /* amount bytes read */
683{
684 CURLcode result = CURLE_RECV_ERROR;
685 ssize_t nread = 0;
686 size_t bytesfromsocket = 0;
687 char *buffertofill = NULL;
688 struct connectdata *conn = data->conn;
689
690 /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
691 If it is the second socket, we set num to 1. Otherwise to 0. This lets
692 us use the correct ssl handle. */
693 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
694
695 *n = 0; /* reset amount to zero */
696
697 bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
698 buffertofill = buf;
699
700 nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
701 if(nread < 0)
702 return result;
703
704 *n += nread;
705
706 return CURLE_OK;
707}
708
709/* return 0 on success */
710int Curl_debug(struct Curl_easy *data, curl_infotype type,
711 char *ptr, size_t size)
712{
713 int rc = 0;
714 if(data->set.verbose) {
715 static const char s_infotype[CURLINFO_END][3] = {
716 "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
717
718#ifdef CURL_DOES_CONVERSIONS
719 char *buf = NULL;
720 size_t conv_size = 0;
721
722 switch(type) {
723 case CURLINFO_HEADER_OUT:
724 buf = Curl_memdup(ptr, size);
725 if(!buf)
726 return 1;
727 conv_size = size;
728
729 /* Special processing is needed for this block if it
730 * contains both headers and data (separated by CRLFCRLF).
731 * We want to convert just the headers, leaving the data as-is.
732 */
733 if(size > 4) {
734 size_t i;
735 for(i = 0; i < size-4; i++) {
736 if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
737 /* convert everything through this CRLFCRLF but no further */
738 conv_size = i + 4;
739 break;
740 }
741 }
742 }
743
744 Curl_convert_from_network(data, buf, conv_size);
745 /* Curl_convert_from_network calls failf if unsuccessful */
746 /* we might as well continue even if it fails... */
747 ptr = buf; /* switch pointer to use my buffer instead */
748 break;
749 default:
750 /* leave everything else as-is */
751 break;
752 }
753#endif /* CURL_DOES_CONVERSIONS */
754
755 if(data->set.fdebug) {
756 Curl_set_in_callback(data, true);
757 rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
758 Curl_set_in_callback(data, false);
759 }
760 else {
761 switch(type) {
762 case CURLINFO_TEXT:
763 case CURLINFO_HEADER_OUT:
764 case CURLINFO_HEADER_IN:
765 fwrite(s_infotype[type], 2, 1, data->set.err);
766 fwrite(ptr, size, 1, data->set.err);
767#ifdef CURL_DOES_CONVERSIONS
768 if(size != conv_size) {
769 /* we had untranslated data so we need an explicit newline */
770 fwrite("\n", 1, 1, data->set.err);
771 }
772#endif
773 break;
774 default: /* nada */
775 break;
776 }
777 }
778#ifdef CURL_DOES_CONVERSIONS
779 free(buf);
780#endif
781 }
782 return rc;
783}
784