VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/sendf.c@ 98334

Last change on this file since 98334 was 98326, checked in by vboxsync, 2 years ago

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • Property svn:eol-style set to native
File size: 23.6 KB
Line 
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 "cfilters.h"
42#include "connect.h"
43#include "vtls/vtls.h"
44#include "vssh/ssh.h"
45#include "easyif.h"
46#include "multiif.h"
47#include "strerror.h"
48#include "select.h"
49#include "strdup.h"
50#include "http2.h"
51#include "headers.h"
52#include "ws.h"
53
54/* The last 3 #include files should be in this order */
55#include "curl_printf.h"
56#include "curl_memory.h"
57#include "memdebug.h"
58
59#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
60/*
61 * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
62 * (\n), with special processing for CRLF sequences that are split between two
63 * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
64 * size of the data is returned.
65 */
66static size_t convert_lineends(struct Curl_easy *data,
67 char *startPtr, size_t size)
68{
69 char *inPtr, *outPtr;
70
71 /* sanity check */
72 if(!startPtr || (size < 1)) {
73 return size;
74 }
75
76 if(data->state.prev_block_had_trailing_cr) {
77 /* The previous block of incoming data
78 had a trailing CR, which was turned into a LF. */
79 if(*startPtr == '\n') {
80 /* This block of incoming data starts with the
81 previous block's LF so get rid of it */
82 memmove(startPtr, startPtr + 1, size-1);
83 size--;
84 /* and it wasn't a bare CR but a CRLF conversion instead */
85 data->state.crlf_conversions++;
86 }
87 data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
88 }
89
90 /* find 1st CR, if any */
91 inPtr = outPtr = memchr(startPtr, '\r', size);
92 if(inPtr) {
93 /* at least one CR, now look for CRLF */
94 while(inPtr < (startPtr + size-1)) {
95 /* note that it's size-1, so we'll never look past the last byte */
96 if(memcmp(inPtr, "\r\n", 2) == 0) {
97 /* CRLF found, bump past the CR and copy the NL */
98 inPtr++;
99 *outPtr = *inPtr;
100 /* keep track of how many CRLFs we converted */
101 data->state.crlf_conversions++;
102 }
103 else {
104 if(*inPtr == '\r') {
105 /* lone CR, move LF instead */
106 *outPtr = '\n';
107 }
108 else {
109 /* not a CRLF nor a CR, just copy whatever it is */
110 *outPtr = *inPtr;
111 }
112 }
113 outPtr++;
114 inPtr++;
115 } /* end of while loop */
116
117 if(inPtr < startPtr + size) {
118 /* handle last byte */
119 if(*inPtr == '\r') {
120 /* deal with a CR at the end of the buffer */
121 *outPtr = '\n'; /* copy a NL instead */
122 /* note that a CRLF might be split across two blocks */
123 data->state.prev_block_had_trailing_cr = TRUE;
124 }
125 else {
126 /* copy last byte */
127 *outPtr = *inPtr;
128 }
129 outPtr++;
130 }
131 if(outPtr < startPtr + size)
132 /* tidy up by null terminating the now shorter data */
133 *outPtr = '\0';
134
135 return (outPtr - startPtr);
136 }
137 return size;
138}
139#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
140
141#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
142bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
143{
144 struct postponed_data * const psnd = &(conn->postponed[sockindex]);
145 return psnd->buffer && psnd->allocated_size &&
146 psnd->recv_size > psnd->recv_processed;
147}
148
149static CURLcode pre_receive_plain(struct Curl_easy *data,
150 struct connectdata *conn, int num)
151{
152 const curl_socket_t sockfd = conn->sock[num];
153 struct postponed_data * const psnd = &(conn->postponed[num]);
154 size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
155 ssize_t recvedbytes;
156
157 /* WinSock will destroy unread received data if send() is
158 failed.
159 To avoid lossage of received data, recv() must be
160 performed before every send() if any incoming data is
161 available. However, skip this, if buffer is already full. */
162 if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
163 conn->recv[num] == Curl_conn_recv &&
164 (!psnd->buffer || bytestorecv)) {
165 const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
166 CURL_SOCKET_BAD, 0);
167 if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
168 /* Have some incoming data */
169 if(!psnd->buffer) {
170 /* Use buffer double default size for intermediate buffer */
171 psnd->allocated_size = 2 * data->set.buffer_size;
172 psnd->buffer = malloc(psnd->allocated_size);
173 if(!psnd->buffer)
174 return CURLE_OUT_OF_MEMORY;
175 psnd->recv_size = 0;
176 psnd->recv_processed = 0;
177#ifdef DEBUGBUILD
178 psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
179#endif /* DEBUGBUILD */
180 bytestorecv = psnd->allocated_size;
181 }
182
183 DEBUGASSERT(psnd->bindsock == sockfd);
184 recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
185 bytestorecv);
186 if(recvedbytes > 0)
187 psnd->recv_size += recvedbytes;
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
341/* Curl_send_plain sends raw data without a size restriction on 'len'. */
342ssize_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 *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 *
408 * This function wraps Curl_send_plain(). The only difference besides the
409 * prototype is '*written' (bytes written) is set to 0 on error.
410 * 'sockfd' must be one of the connection's two main sockets and the value of
411 * 'len' must not be changed.
412 */
413CURLcode Curl_write_plain(struct Curl_easy *data,
414 curl_socket_t sockfd,
415 const void *mem,
416 size_t len,
417 ssize_t *written)
418{
419 CURLcode result;
420 struct connectdata *conn = data->conn;
421 int num;
422 DEBUGASSERT(conn);
423 DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
424 sockfd == conn->sock[SECONDARYSOCKET]);
425 if(sockfd != conn->sock[FIRSTSOCKET] &&
426 sockfd != conn->sock[SECONDARYSOCKET])
427 return CURLE_BAD_FUNCTION_ARGUMENT;
428
429 num = (sockfd == conn->sock[SECONDARYSOCKET]);
430
431 *written = Curl_send_plain(data, num, mem, len, &result);
432 if(*written == -1)
433 *written = 0;
434
435 return result;
436}
437
438/* Curl_recv_plain receives raw data without a size restriction on 'len'. */
439ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
440 size_t len, CURLcode *code)
441{
442 struct connectdata *conn;
443 curl_socket_t sockfd;
444 ssize_t nread;
445 DEBUGASSERT(data);
446 DEBUGASSERT(data->conn);
447 conn = data->conn;
448 sockfd = conn->sock[num];
449 /* Check and return data that already received and storied in internal
450 intermediate buffer */
451 nread = get_pre_recved(conn, num, buf, len);
452 if(nread > 0) {
453 *code = CURLE_OK;
454 return nread;
455 }
456
457 nread = sread(sockfd, buf, len);
458
459 *code = CURLE_OK;
460 if(-1 == nread) {
461 int err = SOCKERRNO;
462
463 if(
464#ifdef WSAEWOULDBLOCK
465 /* This is how Windows does it */
466 (WSAEWOULDBLOCK == err)
467#else
468 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
469 due to its inability to send off data without blocking. We therefore
470 treat both error codes the same here */
471 (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
472#endif
473 ) {
474 /* this is just a case of EWOULDBLOCK */
475 *code = CURLE_AGAIN;
476 }
477 else {
478 char buffer[STRERROR_LEN];
479 failf(data, "Recv failure: %s",
480 Curl_strerror(err, buffer, sizeof(buffer)));
481 data->state.os_errno = err;
482 *code = CURLE_RECV_ERROR;
483 }
484 }
485 return nread;
486}
487
488static CURLcode pausewrite(struct Curl_easy *data,
489 int type, /* what type of data */
490 const char *ptr,
491 size_t len)
492{
493 /* signalled to pause sending on this connection, but since we have data
494 we want to send we need to dup it to save a copy for when the sending
495 is again enabled */
496 struct SingleRequest *k = &data->req;
497 struct UrlState *s = &data->state;
498 unsigned int i;
499 bool newtype = TRUE;
500
501 /* If this transfers over HTTP/2, pause the stream! */
502 Curl_http2_stream_pause(data, TRUE);
503
504 if(s->tempcount) {
505 for(i = 0; i< s->tempcount; i++) {
506 if(s->tempwrite[i].type == type) {
507 /* data for this type exists */
508 newtype = FALSE;
509 break;
510 }
511 }
512 DEBUGASSERT(i < 3);
513 if(i >= 3)
514 /* There are more types to store than what fits: very bad */
515 return CURLE_OUT_OF_MEMORY;
516 }
517 else
518 i = 0;
519
520 if(newtype) {
521 /* store this information in the state struct for later use */
522 Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
523 s->tempwrite[i].type = type;
524 s->tempcount++;
525 }
526
527 if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
528 return CURLE_OUT_OF_MEMORY;
529
530 /* mark the connection as RECV paused */
531 k->keepon |= KEEP_RECV_PAUSE;
532
533 return CURLE_OK;
534}
535
536
537/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
538 * client write callback(s) and takes care of pause requests from the
539 * callbacks.
540 */
541static CURLcode chop_write(struct Curl_easy *data,
542 int type,
543 char *optr,
544 size_t olen)
545{
546 struct connectdata *conn = data->conn;
547 curl_write_callback writeheader = NULL;
548 curl_write_callback writebody = NULL;
549 char *ptr = optr;
550 size_t len = olen;
551 void *writebody_ptr = data->set.out;
552
553 if(!len)
554 return CURLE_OK;
555
556 /* If reading is paused, append this data to the already held data for this
557 type. */
558 if(data->req.keepon & KEEP_RECV_PAUSE)
559 return pausewrite(data, type, ptr, len);
560
561 /* Determine the callback(s) to use. */
562 if(type & CLIENTWRITE_BODY) {
563#ifdef USE_WEBSOCKETS
564 if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
565 struct HTTP *ws = data->req.p.http;
566 writebody = Curl_ws_writecb;
567 ws->ws.data = data;
568 writebody_ptr = ws;
569 }
570 else
571#endif
572 writebody = data->set.fwrite_func;
573 }
574 if((type & CLIENTWRITE_HEADER) &&
575 (data->set.fwrite_header || data->set.writeheader)) {
576 /*
577 * Write headers to the same callback or to the especially setup
578 * header callback function (added after version 7.7.1).
579 */
580 writeheader =
581 data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
582 }
583
584 /* Chop data, write chunks. */
585 while(len) {
586 size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
587
588 if(writebody) {
589 size_t wrote;
590 Curl_set_in_callback(data, true);
591 wrote = writebody(ptr, 1, chunklen, writebody_ptr);
592 Curl_set_in_callback(data, false);
593
594 if(CURL_WRITEFUNC_PAUSE == wrote) {
595 if(conn->handler->flags & PROTOPT_NONETWORK) {
596 /* Protocols that work without network cannot be paused. This is
597 actually only FILE:// just now, and it can't pause since the
598 transfer isn't done using the "normal" procedure. */
599 failf(data, "Write callback asked for PAUSE when not supported");
600 return CURLE_WRITE_ERROR;
601 }
602 return pausewrite(data, type, ptr, len);
603 }
604 if(wrote != chunklen) {
605 failf(data, "Failure writing output to destination");
606 return CURLE_WRITE_ERROR;
607 }
608 }
609
610 ptr += chunklen;
611 len -= chunklen;
612 }
613
614#ifndef CURL_DISABLE_HTTP
615 /* HTTP header, but not status-line */
616 if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
617 (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
618 unsigned char htype = (unsigned char)
619 (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
620 (type & CLIENTWRITE_1XX ? CURLH_1XX :
621 (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
622 CURLH_HEADER)));
623 CURLcode result = Curl_headers_push(data, optr, htype);
624 if(result)
625 return result;
626 }
627#endif
628
629 if(writeheader) {
630 size_t wrote;
631
632 Curl_set_in_callback(data, true);
633 wrote = writeheader(optr, 1, olen, data->set.writeheader);
634 Curl_set_in_callback(data, false);
635
636 if(CURL_WRITEFUNC_PAUSE == wrote)
637 /* here we pass in the HEADER bit only since if this was body as well
638 then it was passed already and clearly that didn't trigger the
639 pause, so this is saved for later with the HEADER bit only */
640 return pausewrite(data, CLIENTWRITE_HEADER |
641 (type & (CLIENTWRITE_STATUS|CLIENTWRITE_CONNECT|
642 CLIENTWRITE_1XX|CLIENTWRITE_TRAILER)),
643 optr, olen);
644 if(wrote != olen) {
645 failf(data, "Failed writing header");
646 return CURLE_WRITE_ERROR;
647 }
648 }
649
650 return CURLE_OK;
651}
652
653
654/* Curl_client_write() sends data to the write callback(s)
655
656 The bit pattern defines to what "streams" to write to. Body and/or header.
657 The defines are in sendf.h of course.
658
659 If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
660 local character encoding. This is a problem and should be changed in
661 the future to leave the original data alone.
662 */
663CURLcode Curl_client_write(struct Curl_easy *data,
664 int type,
665 char *ptr,
666 size_t len)
667{
668#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
669 /* FTP data may need conversion. */
670 if((type & CLIENTWRITE_BODY) &&
671 (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
672 data->conn->proto.ftpc.transfertype == 'A') {
673 /* convert end-of-line markers */
674 len = convert_lineends(data, ptr, len);
675 }
676#endif
677 return chop_write(data, type, ptr, len);
678}
679
680/*
681 * Curl_read_plain() is an internal read function that reads data from the
682 * server using plain sockets only. Otherwise meant to have the exact same
683 * proto as Curl_read().
684 *
685 * This function wraps Curl_recv_plain(). The only difference besides the
686 * prototype is '*n' (bytes read) is set to 0 on error.
687 * 'sockfd' must be one of the connection's two main sockets and the value of
688 * 'sizerequested' must not be changed.
689 */
690CURLcode Curl_read_plain(struct Curl_easy *data, /* transfer */
691 curl_socket_t sockfd, /* read from this socket */
692 char *buf, /* store read data here */
693 size_t sizerequested, /* max amount to read */
694 ssize_t *n) /* amount bytes read */
695{
696 CURLcode result;
697 struct connectdata *conn = data->conn;
698 int num;
699 DEBUGASSERT(conn);
700 DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
701 sockfd == conn->sock[SECONDARYSOCKET]);
702 if(sockfd != conn->sock[FIRSTSOCKET] &&
703 sockfd != conn->sock[SECONDARYSOCKET])
704 return CURLE_BAD_FUNCTION_ARGUMENT;
705
706 num = (sockfd == conn->sock[SECONDARYSOCKET]);
707
708 *n = Curl_recv_plain(data, num, buf, sizerequested, &result);
709 if(*n == -1)
710 *n = 0;
711
712 return result;
713}
714
715/*
716 * Internal read-from-socket function. This is meant to deal with plain
717 * sockets, SSL sockets and kerberos sockets.
718 *
719 * Returns a regular CURLcode value.
720 */
721CURLcode Curl_read(struct Curl_easy *data, /* transfer */
722 curl_socket_t sockfd, /* read from this socket */
723 char *buf, /* store read data here */
724 size_t sizerequested, /* max amount to read */
725 ssize_t *n) /* amount bytes read */
726{
727 CURLcode result = CURLE_RECV_ERROR;
728 ssize_t nread = 0;
729 size_t bytesfromsocket = 0;
730 char *buffertofill = NULL;
731 struct connectdata *conn = data->conn;
732
733 /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
734 If it is the second socket, we set num to 1. Otherwise to 0. This lets
735 us use the correct ssl handle. */
736 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
737
738 *n = 0; /* reset amount to zero */
739
740 bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
741 buffertofill = buf;
742
743 nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
744 if(nread < 0)
745 goto out;
746
747 *n += nread;
748 result = CURLE_OK;
749out:
750 /* DEBUGF(infof(data, "Curl_read(handle=%p) -> %d, nread=%ld",
751 data, result, nread)); */
752 return result;
753}
754
755/* return 0 on success */
756void Curl_debug(struct Curl_easy *data, curl_infotype type,
757 char *ptr, size_t size)
758{
759 if(data->set.verbose) {
760 static const char s_infotype[CURLINFO_END][3] = {
761 "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
762 if(data->set.fdebug) {
763 bool inCallback = Curl_is_in_callback(data);
764 Curl_set_in_callback(data, true);
765 (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
766 Curl_set_in_callback(data, inCallback);
767 }
768 else {
769 switch(type) {
770 case CURLINFO_TEXT:
771 case CURLINFO_HEADER_OUT:
772 case CURLINFO_HEADER_IN:
773 fwrite(s_infotype[type], 2, 1, data->set.err);
774 fwrite(ptr, size, 1, data->set.err);
775 break;
776 default: /* nada */
777 break;
778 }
779 }
780 }
781}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette