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