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 */
convert_lineends(struct Curl_easy * data,char * startPtr,size_t size)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
Curl_recv_has_postponed_data(struct connectdata * conn,int sockindex)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
pre_receive_plain(struct Curl_easy * data,struct connectdata * conn,int num)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
get_pre_recved(struct connectdata * conn,int num,char * buf,size_t len)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 */
Curl_recv_has_postponed_data(struct connectdata * conn,int sockindex)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
Curl_infof(struct Curl_easy * data,const char * fmt,...)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
Curl_failf(struct Curl_easy * data,const char * fmt,...)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 */
Curl_write(struct Curl_easy * data,curl_socket_t sockfd,const void * mem,size_t len,ssize_t * written)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
Curl_send_plain(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)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 */
Curl_write_plain(struct Curl_easy * data,curl_socket_t sockfd,const void * mem,size_t len,ssize_t * written)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
Curl_recv_plain(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)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
pausewrite(struct Curl_easy * data,int type,const char * ptr,size_t len)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 */
chop_write(struct Curl_easy * data,int type,char * optr,size_t olen)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 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.
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 */
Curl_client_write(struct Curl_easy * data,int type,char * ptr,size_t len)617 CURLcode 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(!(type & ~CLIENTWRITE_BOTH));
625
626 if(!len)
627 return CURLE_OK;
628
629 /* FTP data may need conversion. */
630 if((type & CLIENTWRITE_BODY) &&
631 (conn->handler->protocol & PROTO_FAMILY_FTP) &&
632 conn->proto.ftpc.transfertype == 'A') {
633 /* convert from the network encoding */
634 CURLcode result = Curl_convert_from_network(data, ptr, len);
635 /* Curl_convert_from_network calls failf if unsuccessful */
636 if(result)
637 return result;
638
639 #ifdef CURL_DO_LINEEND_CONV
640 /* convert end-of-line markers */
641 len = convert_lineends(data, ptr, len);
642 #endif /* CURL_DO_LINEEND_CONV */
643 }
644
645 return chop_write(data, type, ptr, len);
646 }
647
Curl_read_plain(curl_socket_t sockfd,char * buf,size_t bytesfromsocket,ssize_t * n)648 CURLcode Curl_read_plain(curl_socket_t sockfd,
649 char *buf,
650 size_t bytesfromsocket,
651 ssize_t *n)
652 {
653 ssize_t nread = sread(sockfd, buf, bytesfromsocket);
654
655 if(-1 == nread) {
656 const int err = SOCKERRNO;
657 const bool return_error =
658 #ifdef USE_WINSOCK
659 WSAEWOULDBLOCK == err
660 #else
661 EWOULDBLOCK == err || EAGAIN == err || EINTR == err
662 #endif
663 ;
664 *n = 0; /* no data returned */
665 if(return_error)
666 return CURLE_AGAIN;
667 return CURLE_RECV_ERROR;
668 }
669
670 *n = nread;
671 return CURLE_OK;
672 }
673
674 /*
675 * Internal read-from-socket function. This is meant to deal with plain
676 * sockets, SSL sockets and kerberos sockets.
677 *
678 * Returns a regular CURLcode value.
679 */
Curl_read(struct Curl_easy * data,curl_socket_t sockfd,char * buf,size_t sizerequested,ssize_t * n)680 CURLcode Curl_read(struct Curl_easy *data, /* transfer */
681 curl_socket_t sockfd, /* read from this socket */
682 char *buf, /* store read data here */
683 size_t sizerequested, /* max amount to read */
684 ssize_t *n) /* amount bytes read */
685 {
686 CURLcode result = CURLE_RECV_ERROR;
687 ssize_t nread = 0;
688 size_t bytesfromsocket = 0;
689 char *buffertofill = NULL;
690 struct connectdata *conn = data->conn;
691
692 /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
693 If it is the second socket, we set num to 1. Otherwise to 0. This lets
694 us use the correct ssl handle. */
695 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
696
697 *n = 0; /* reset amount to zero */
698
699 bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
700 buffertofill = buf;
701
702 nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
703 if(nread < 0)
704 return result;
705
706 *n += nread;
707
708 return CURLE_OK;
709 }
710
711 /* return 0 on success */
Curl_debug(struct Curl_easy * data,curl_infotype type,char * ptr,size_t size)712 int Curl_debug(struct Curl_easy *data, curl_infotype type,
713 char *ptr, size_t size)
714 {
715 int rc = 0;
716 if(data->set.verbose) {
717 static const char s_infotype[CURLINFO_END][3] = {
718 "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
719
720 #ifdef CURL_DOES_CONVERSIONS
721 char *buf = NULL;
722 size_t conv_size = 0;
723
724 switch(type) {
725 case CURLINFO_HEADER_OUT:
726 buf = Curl_memdup(ptr, size);
727 if(!buf)
728 return 1;
729 conv_size = size;
730
731 /* Special processing is needed for this block if it
732 * contains both headers and data (separated by CRLFCRLF).
733 * We want to convert just the headers, leaving the data as-is.
734 */
735 if(size > 4) {
736 size_t i;
737 for(i = 0; i < size-4; i++) {
738 if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
739 /* convert everything through this CRLFCRLF but no further */
740 conv_size = i + 4;
741 break;
742 }
743 }
744 }
745
746 Curl_convert_from_network(data, buf, conv_size);
747 /* Curl_convert_from_network calls failf if unsuccessful */
748 /* we might as well continue even if it fails... */
749 ptr = buf; /* switch pointer to use my buffer instead */
750 break;
751 default:
752 /* leave everything else as-is */
753 break;
754 }
755 #endif /* CURL_DOES_CONVERSIONS */
756
757 if(data->set.fdebug) {
758 Curl_set_in_callback(data, true);
759 rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
760 Curl_set_in_callback(data, false);
761 }
762 else {
763 switch(type) {
764 case CURLINFO_TEXT:
765 case CURLINFO_HEADER_OUT:
766 case CURLINFO_HEADER_IN:
767 fwrite(s_infotype[type], 2, 1, data->set.err);
768 fwrite(ptr, size, 1, data->set.err);
769 #ifdef CURL_DOES_CONVERSIONS
770 if(size != conv_size) {
771 /* we had untranslated data so we need an explicit newline */
772 fwrite("\n", 1, 1, data->set.err);
773 }
774 #endif
775 break;
776 default: /* nada */
777 break;
778 }
779 }
780 #ifdef CURL_DOES_CONVERSIONS
781 free(buf);
782 #endif
783 }
784 return rc;
785 }
786