d7d4d8abd463057abb98e8dde38b8bc57271ebc6
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / sendf.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, 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 "strerror.h"
45 #include "select.h"
46 #include "strdup.h"
47 #include "http2.h"
48 #include "headers.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  */
62 static 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
138 bool 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
145 static 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
191 static 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 */
228 bool 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
241 void 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
261 void 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  */
289 CURLcode 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
339 ssize_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  */
406 CURLcode 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
423 ssize_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
472 static 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  */
522 static 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   /* HTTP header, but not status-line */
585   if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
586      (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
587     CURLcode result =
588       Curl_headers_push(data, optr,
589                         type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
590                         (type & CLIENTWRITE_1XX ? CURLH_1XX :
591                          (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
592                           CURLH_HEADER)));
593     if(result)
594       return result;
595   }
596
597   if(writeheader) {
598     size_t wrote;
599
600     Curl_set_in_callback(data, true);
601     wrote = writeheader(optr, 1, olen, data->set.writeheader);
602     Curl_set_in_callback(data, false);
603
604     if(CURL_WRITEFUNC_PAUSE == wrote)
605       /* here we pass in the HEADER bit only since if this was body as well
606          then it was passed already and clearly that didn't trigger the
607          pause, so this is saved for later with the HEADER bit only */
608       return pausewrite(data, CLIENTWRITE_HEADER, optr, olen);
609
610     if(wrote != olen) {
611       failf(data, "Failed writing header");
612       return CURLE_WRITE_ERROR;
613     }
614   }
615
616   return CURLE_OK;
617 }
618
619
620 /* Curl_client_write() sends data to the write callback(s)
621
622    The bit pattern defines to what "streams" to write to. Body and/or header.
623    The defines are in sendf.h of course.
624
625    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
626    local character encoding.  This is a problem and should be changed in
627    the future to leave the original data alone.
628  */
629 CURLcode Curl_client_write(struct Curl_easy *data,
630                            int type,
631                            char *ptr,
632                            size_t len)
633 {
634   struct connectdata *conn = data->conn;
635
636   if(!len)
637     return CURLE_OK;
638
639   /* FTP data may need conversion. */
640   if((type & CLIENTWRITE_BODY) &&
641      (conn->handler->protocol & PROTO_FAMILY_FTP) &&
642      conn->proto.ftpc.transfertype == 'A') {
643
644 #ifdef CURL_DO_LINEEND_CONV
645     /* convert end-of-line markers */
646     len = convert_lineends(data, ptr, len);
647 #endif /* CURL_DO_LINEEND_CONV */
648   }
649
650   return chop_write(data, type, ptr, len);
651 }
652
653 CURLcode Curl_read_plain(curl_socket_t sockfd,
654                          char *buf,
655                          size_t bytesfromsocket,
656                          ssize_t *n)
657 {
658   ssize_t nread = sread(sockfd, buf, bytesfromsocket);
659
660   if(-1 == nread) {
661     const int err = SOCKERRNO;
662     const bool return_error =
663 #ifdef USE_WINSOCK
664       WSAEWOULDBLOCK == err
665 #else
666       EWOULDBLOCK == err || EAGAIN == err || EINTR == err
667 #endif
668       ;
669     *n = 0; /* no data returned */
670     if(return_error)
671       return CURLE_AGAIN;
672     return CURLE_RECV_ERROR;
673   }
674
675   *n = nread;
676   return CURLE_OK;
677 }
678
679 /*
680  * Internal read-from-socket function. This is meant to deal with plain
681  * sockets, SSL sockets and kerberos sockets.
682  *
683  * Returns a regular CURLcode value.
684  */
685 CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
686                    curl_socket_t sockfd,     /* read from this socket */
687                    char *buf,                /* store read data here */
688                    size_t sizerequested,     /* max amount to read */
689                    ssize_t *n)               /* amount bytes read */
690 {
691   CURLcode result = CURLE_RECV_ERROR;
692   ssize_t nread = 0;
693   size_t bytesfromsocket = 0;
694   char *buffertofill = NULL;
695   struct connectdata *conn = data->conn;
696
697   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
698      If it is the second socket, we set num to 1. Otherwise to 0. This lets
699      us use the correct ssl handle. */
700   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
701
702   *n = 0; /* reset amount to zero */
703
704   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
705   buffertofill = buf;
706
707   nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
708   if(nread < 0)
709     return result;
710
711   *n += nread;
712
713   return CURLE_OK;
714 }
715
716 /* return 0 on success */
717 int Curl_debug(struct Curl_easy *data, curl_infotype type,
718                char *ptr, size_t size)
719 {
720   int rc = 0;
721   if(data->set.verbose) {
722     static const char s_infotype[CURLINFO_END][3] = {
723       "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
724     if(data->set.fdebug) {
725       Curl_set_in_callback(data, true);
726       rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
727       Curl_set_in_callback(data, false);
728     }
729     else {
730       switch(type) {
731       case CURLINFO_TEXT:
732       case CURLINFO_HEADER_OUT:
733       case CURLINFO_HEADER_IN:
734         fwrite(s_infotype[type], 2, 1, data->set.err);
735         fwrite(ptr, size, 1, data->set.err);
736         break;
737       default: /* nada */
738         break;
739       }
740     }
741   }
742   return rc;
743 }