VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/sendf.c@ 85671

Last change on this file since 85671 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

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