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