1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 "cfilters.h"
42 #include "connect.h"
43 #include "content_encoding.h"
44 #include "vtls/vtls.h"
45 #include "vssh/ssh.h"
46 #include "easyif.h"
47 #include "multiif.h"
48 #include "strerror.h"
49 #include "select.h"
50 #include "strdup.h"
51 #include "http2.h"
52 #include "headers.h"
53 #include "progress.h"
54 #include "ws.h"
55
56 /* The last 3 #include files should be in this order */
57 #include "curl_printf.h"
58 #include "curl_memory.h"
59 #include "memdebug.h"
60
61
62 static CURLcode do_init_stack(struct Curl_easy *data);
63
64 #if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
65 /*
66 * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
67 * (\n), with special processing for CRLF sequences that are split between two
68 * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
69 * size of the data is returned.
70 */
convert_lineends(struct Curl_easy * data,char * startPtr,size_t size)71 static size_t convert_lineends(struct Curl_easy *data,
72 char *startPtr, size_t size)
73 {
74 char *inPtr, *outPtr;
75
76 /* sanity check */
77 if(!startPtr || (size < 1)) {
78 return size;
79 }
80
81 if(data->state.prev_block_had_trailing_cr) {
82 /* The previous block of incoming data
83 had a trailing CR, which was turned into a LF. */
84 if(*startPtr == '\n') {
85 /* This block of incoming data starts with the
86 previous block's LF so get rid of it */
87 memmove(startPtr, startPtr + 1, size-1);
88 size--;
89 /* and it wasn't a bare CR but a CRLF conversion instead */
90 data->state.crlf_conversions++;
91 }
92 data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
93 }
94
95 /* find 1st CR, if any */
96 inPtr = outPtr = memchr(startPtr, '\r', size);
97 if(inPtr) {
98 /* at least one CR, now look for CRLF */
99 while(inPtr < (startPtr + size-1)) {
100 /* note that it's size-1, so we'll never look past the last byte */
101 if(memcmp(inPtr, "\r\n", 2) == 0) {
102 /* CRLF found, bump past the CR and copy the NL */
103 inPtr++;
104 *outPtr = *inPtr;
105 /* keep track of how many CRLFs we converted */
106 data->state.crlf_conversions++;
107 }
108 else {
109 if(*inPtr == '\r') {
110 /* lone CR, move LF instead */
111 *outPtr = '\n';
112 }
113 else {
114 /* not a CRLF nor a CR, just copy whatever it is */
115 *outPtr = *inPtr;
116 }
117 }
118 outPtr++;
119 inPtr++;
120 } /* end of while loop */
121
122 if(inPtr < startPtr + size) {
123 /* handle last byte */
124 if(*inPtr == '\r') {
125 /* deal with a CR at the end of the buffer */
126 *outPtr = '\n'; /* copy a NL instead */
127 /* note that a CRLF might be split across two blocks */
128 data->state.prev_block_had_trailing_cr = TRUE;
129 }
130 else {
131 /* copy last byte */
132 *outPtr = *inPtr;
133 }
134 outPtr++;
135 }
136 if(outPtr < startPtr + size)
137 /* tidy up by null terminating the now shorter data */
138 *outPtr = '\0';
139
140 return (outPtr - startPtr);
141 }
142 return size;
143 }
144 #endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
145
146 /*
147 * Curl_nwrite() is an internal write function that sends data to the
148 * server. Works with a socket index for the connection.
149 *
150 * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
151 * (*nwritten == 0). Otherwise we return regular CURLcode value.
152 */
Curl_nwrite(struct Curl_easy * data,int sockindex,const void * buf,size_t blen,ssize_t * pnwritten)153 CURLcode Curl_nwrite(struct Curl_easy *data,
154 int sockindex,
155 const void *buf,
156 size_t blen,
157 ssize_t *pnwritten)
158 {
159 ssize_t nwritten;
160 CURLcode result = CURLE_OK;
161 struct connectdata *conn;
162
163 DEBUGASSERT(sockindex >= 0 && sockindex < 2);
164 DEBUGASSERT(pnwritten);
165 DEBUGASSERT(data);
166 DEBUGASSERT(data->conn);
167 conn = data->conn;
168 #ifdef CURLDEBUG
169 {
170 /* Allow debug builds to override this logic to force short sends
171 */
172 char *p = getenv("CURL_SMALLSENDS");
173 if(p) {
174 size_t altsize = (size_t)strtoul(p, NULL, 10);
175 if(altsize)
176 blen = CURLMIN(blen, altsize);
177 }
178 }
179 #endif
180 nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
181 if(result == CURLE_AGAIN) {
182 nwritten = 0;
183 result = CURLE_OK;
184 }
185 else if(result) {
186 nwritten = -1; /* make sure */
187 }
188 else {
189 DEBUGASSERT(nwritten >= 0);
190 }
191
192 *pnwritten = nwritten;
193 return result;
194 }
195
196 /*
197 * Curl_write() is an internal write function that sends data to the
198 * server. Works with plain sockets, SCP, SSL or kerberos.
199 *
200 * If the write would block (CURLE_AGAIN), we return CURLE_OK and
201 * (*written == 0). Otherwise we return regular CURLcode value.
202 */
Curl_write(struct Curl_easy * data,curl_socket_t sockfd,const void * mem,size_t len,ssize_t * written)203 CURLcode Curl_write(struct Curl_easy *data,
204 curl_socket_t sockfd,
205 const void *mem,
206 size_t len,
207 ssize_t *written)
208 {
209 struct connectdata *conn;
210 int num;
211
212 DEBUGASSERT(data);
213 DEBUGASSERT(data->conn);
214 conn = data->conn;
215 num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
216 return Curl_nwrite(data, num, mem, len, written);
217 }
218
pausewrite(struct Curl_easy * data,int type,bool paused_body,const char * ptr,size_t len)219 static CURLcode pausewrite(struct Curl_easy *data,
220 int type, /* what type of data */
221 bool paused_body,
222 const char *ptr,
223 size_t len)
224 {
225 /* signalled to pause sending on this connection, but since we have data
226 we want to send we need to dup it to save a copy for when the sending
227 is again enabled */
228 struct SingleRequest *k = &data->req;
229 struct UrlState *s = &data->state;
230 unsigned int i;
231 bool newtype = TRUE;
232
233 Curl_conn_ev_data_pause(data, TRUE);
234
235 if(s->tempcount) {
236 for(i = 0; i< s->tempcount; i++) {
237 if(s->tempwrite[i].type == type &&
238 !!s->tempwrite[i].paused_body == !!paused_body) {
239 /* data for this type exists */
240 newtype = FALSE;
241 break;
242 }
243 }
244 DEBUGASSERT(i < 3);
245 if(i >= 3)
246 /* There are more types to store than what fits: very bad */
247 return CURLE_OUT_OF_MEMORY;
248 }
249 else
250 i = 0;
251
252 if(newtype) {
253 /* store this information in the state struct for later use */
254 Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
255 s->tempwrite[i].type = type;
256 s->tempwrite[i].paused_body = paused_body;
257 s->tempcount++;
258 }
259
260 if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
261 return CURLE_OUT_OF_MEMORY;
262
263 /* mark the connection as RECV paused */
264 k->keepon |= KEEP_RECV_PAUSE;
265
266 return CURLE_OK;
267 }
268
269
270 /* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
271 * client write callback(s) and takes care of pause requests from the
272 * callbacks.
273 */
chop_write(struct Curl_easy * data,int type,bool skip_body_write,char * optr,size_t olen)274 static CURLcode chop_write(struct Curl_easy *data,
275 int type,
276 bool skip_body_write,
277 char *optr,
278 size_t olen)
279 {
280 struct connectdata *conn = data->conn;
281 curl_write_callback writeheader = NULL;
282 curl_write_callback writebody = NULL;
283 char *ptr = optr;
284 size_t len = olen;
285 void *writebody_ptr = data->set.out;
286
287 if(!len)
288 return CURLE_OK;
289
290 /* If reading is paused, append this data to the already held data for this
291 type. */
292 if(data->req.keepon & KEEP_RECV_PAUSE)
293 return pausewrite(data, type, !skip_body_write, ptr, len);
294
295 /* Determine the callback(s) to use. */
296 if(!skip_body_write &&
297 ((type & CLIENTWRITE_BODY) ||
298 ((type & CLIENTWRITE_HEADER) && data->set.include_header))) {
299 writebody = data->set.fwrite_func;
300 }
301 if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) &&
302 (data->set.fwrite_header || data->set.writeheader)) {
303 /*
304 * Write headers to the same callback or to the especially setup
305 * header callback function (added after version 7.7.1).
306 */
307 writeheader =
308 data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
309 }
310
311 /* Chop data, write chunks. */
312 while(len) {
313 size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
314
315 if(writebody) {
316 size_t wrote;
317 Curl_set_in_callback(data, true);
318 wrote = writebody(ptr, 1, chunklen, writebody_ptr);
319 Curl_set_in_callback(data, false);
320
321 if(CURL_WRITEFUNC_PAUSE == wrote) {
322 if(conn->handler->flags & PROTOPT_NONETWORK) {
323 /* Protocols that work without network cannot be paused. This is
324 actually only FILE:// just now, and it can't pause since the
325 transfer isn't done using the "normal" procedure. */
326 failf(data, "Write callback asked for PAUSE when not supported");
327 return CURLE_WRITE_ERROR;
328 }
329 return pausewrite(data, type, TRUE, ptr, len);
330 }
331 if(wrote != chunklen) {
332 failf(data, "Failure writing output to destination");
333 return CURLE_WRITE_ERROR;
334 }
335 }
336
337 ptr += chunklen;
338 len -= chunklen;
339 }
340
341 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
342 /* HTTP header, but not status-line */
343 if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
344 (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
345 unsigned char htype = (unsigned char)
346 (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
347 (type & CLIENTWRITE_1XX ? CURLH_1XX :
348 (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
349 CURLH_HEADER)));
350 CURLcode result = Curl_headers_push(data, optr, htype);
351 if(result)
352 return result;
353 }
354 #endif
355
356 if(writeheader) {
357 size_t wrote;
358
359 Curl_set_in_callback(data, true);
360 wrote = writeheader(optr, 1, olen, data->set.writeheader);
361 Curl_set_in_callback(data, false);
362
363 if(CURL_WRITEFUNC_PAUSE == wrote)
364 return pausewrite(data, type, FALSE, optr, olen);
365 if(wrote != olen) {
366 failf(data, "Failed writing header");
367 return CURLE_WRITE_ERROR;
368 }
369 }
370
371 return CURLE_OK;
372 }
373
374
375 /* Curl_client_write() sends data to the write callback(s)
376
377 The bit pattern defines to what "streams" to write to. Body and/or header.
378 The defines are in sendf.h of course.
379
380 If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
381 local character encoding. This is a problem and should be changed in
382 the future to leave the original data alone.
383 */
Curl_client_write(struct Curl_easy * data,int type,char * buf,size_t blen)384 CURLcode Curl_client_write(struct Curl_easy *data,
385 int type, char *buf, size_t blen)
386 {
387 CURLcode result;
388
389 #if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
390 /* FTP data may need conversion. */
391 if((type & CLIENTWRITE_BODY) &&
392 (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
393 data->conn->proto.ftpc.transfertype == 'A') {
394 /* convert end-of-line markers */
395 blen = convert_lineends(data, buf, blen);
396 }
397 #endif
398 /* it is one of those, at least */
399 DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
400 /* BODY is only BODY (with optional EOS) */
401 DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
402 ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
403 /* INFO is only INFO (with optional EOS) */
404 DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
405 ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
406
407 if(!data->req.writer_stack) {
408 result = do_init_stack(data);
409 if(result)
410 return result;
411 DEBUGASSERT(data->req.writer_stack);
412 }
413
414 return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
415 }
416
Curl_client_unpause(struct Curl_easy * data)417 CURLcode Curl_client_unpause(struct Curl_easy *data)
418 {
419 CURLcode result = CURLE_OK;
420
421 if(data->state.tempcount) {
422 /* there are buffers for sending that can be delivered as the receive
423 pausing is lifted! */
424 unsigned int i;
425 unsigned int count = data->state.tempcount;
426 struct tempbuf writebuf[3]; /* there can only be three */
427
428 /* copy the structs to allow for immediate re-pausing */
429 for(i = 0; i < data->state.tempcount; i++) {
430 writebuf[i] = data->state.tempwrite[i];
431 Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER);
432 }
433 data->state.tempcount = 0;
434
435 for(i = 0; i < count; i++) {
436 /* even if one function returns error, this loops through and frees
437 all buffers */
438 if(!result)
439 result = chop_write(data, writebuf[i].type,
440 !writebuf[i].paused_body,
441 Curl_dyn_ptr(&writebuf[i].b),
442 Curl_dyn_len(&writebuf[i].b));
443 Curl_dyn_free(&writebuf[i].b);
444 }
445 }
446 return result;
447 }
448
Curl_client_cleanup(struct Curl_easy * data)449 void Curl_client_cleanup(struct Curl_easy *data)
450 {
451 struct Curl_cwriter *writer = data->req.writer_stack;
452 size_t i;
453
454 while(writer) {
455 data->req.writer_stack = writer->next;
456 writer->cwt->do_close(data, writer);
457 free(writer);
458 writer = data->req.writer_stack;
459 }
460
461 for(i = 0; i < data->state.tempcount; i++) {
462 Curl_dyn_free(&data->state.tempwrite[i].b);
463 }
464 data->state.tempcount = 0;
465 data->req.bytecount = 0;
466 data->req.headerline = 0;
467 }
468
469 /* Write data using an unencoding writer stack. "nbytes" is not
470 allowed to be 0. */
Curl_cwriter_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)471 CURLcode Curl_cwriter_write(struct Curl_easy *data,
472 struct Curl_cwriter *writer, int type,
473 const char *buf, size_t nbytes)
474 {
475 if(!writer)
476 return CURLE_WRITE_ERROR;
477 return writer->cwt->do_write(data, writer, type, buf, nbytes);
478 }
479
Curl_cwriter_def_init(struct Curl_easy * data,struct Curl_cwriter * writer)480 CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
481 struct Curl_cwriter *writer)
482 {
483 (void)data;
484 (void)writer;
485 return CURLE_OK;
486 }
487
Curl_cwriter_def_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)488 CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
489 struct Curl_cwriter *writer, int type,
490 const char *buf, size_t nbytes)
491 {
492 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
493 }
494
Curl_cwriter_def_close(struct Curl_easy * data,struct Curl_cwriter * writer)495 void Curl_cwriter_def_close(struct Curl_easy *data,
496 struct Curl_cwriter *writer)
497 {
498 (void) data;
499 (void) writer;
500 }
501
502 /* Real client writer to installed callbacks. */
cw_client_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)503 static CURLcode cw_client_write(struct Curl_easy *data,
504 struct Curl_cwriter *writer, int type,
505 const char *buf, size_t nbytes)
506 {
507 (void)writer;
508 if(!nbytes)
509 return CURLE_OK;
510 return chop_write(data, type, FALSE, (char *)buf, nbytes);
511 }
512
513 static const struct Curl_cwtype cw_client = {
514 "client",
515 NULL,
516 Curl_cwriter_def_init,
517 cw_client_write,
518 Curl_cwriter_def_close,
519 sizeof(struct Curl_cwriter)
520 };
521
get_max_body_write_len(struct Curl_easy * data,curl_off_t limit)522 static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
523 {
524 if(limit != -1) {
525 /* How much more are we allowed to write? */
526 curl_off_t remain_diff;
527 remain_diff = limit - data->req.bytecount;
528 if(remain_diff < 0) {
529 /* already written too much! */
530 return 0;
531 }
532 #if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
533 else if(remain_diff > SSIZE_T_MAX) {
534 return SIZE_T_MAX;
535 }
536 #endif
537 else {
538 return (size_t)remain_diff;
539 }
540 }
541 return SIZE_T_MAX;
542 }
543
544 /* Download client writer in phase CURL_CW_PROTOCOL that
545 * sees the "real" download body data. */
cw_download_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)546 static CURLcode cw_download_write(struct Curl_easy *data,
547 struct Curl_cwriter *writer, int type,
548 const char *buf, size_t nbytes)
549 {
550 CURLcode result;
551 size_t nwrite, excess_len = 0;
552
553 if(!(type & CLIENTWRITE_BODY)) {
554 if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
555 return CURLE_OK;
556 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
557 }
558
559 if(!data->req.bytecount) {
560 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
561 if(data->req.exp100 > EXP100_SEND_DATA)
562 /* set time stamp to compare with when waiting for the 100 */
563 data->req.start100 = Curl_now();
564 }
565
566 /* Here, we deal with REAL BODY bytes. All filtering and transfer
567 * encodings have been applied and only the true content, e.g. BODY,
568 * bytes are passed here.
569 * This allows us to check sizes, update stats, etc. independent
570 * from the protocol in play. */
571
572 if(data->req.no_body && nbytes > 0) {
573 /* BODY arrives although we want none, bail out */
574 streamclose(data->conn, "ignoring body");
575 DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
576 nbytes));
577 data->req.download_done = TRUE;
578 return CURLE_WEIRD_SERVER_REPLY;
579 }
580
581 /* Determine if we see any bytes in excess to what is allowed.
582 * We write the allowed bytes and handle excess further below.
583 * This gives deterministic BODY writes on varying buffer receive
584 * lengths. */
585 nwrite = nbytes;
586 if(-1 != data->req.maxdownload) {
587 size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
588 if(nwrite > wmax) {
589 excess_len = nbytes - wmax;
590 nwrite = wmax;
591 }
592
593 if(nwrite == wmax) {
594 data->req.download_done = TRUE;
595 }
596 }
597
598 /* Error on too large filesize is handled below, after writing
599 * the permitted bytes */
600 if(data->set.max_filesize) {
601 size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
602 if(nwrite > wmax) {
603 nwrite = wmax;
604 }
605 }
606
607 /* Update stats, write and report progress */
608 data->req.bytecount += nwrite;
609 ++data->req.bodywrites;
610 if(!data->req.ignorebody && nwrite) {
611 result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
612 if(result)
613 return result;
614 }
615 result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
616 if(result)
617 return result;
618
619 if(excess_len) {
620 if(!data->req.ignorebody) {
621 infof(data,
622 "Excess found writing body:"
623 " excess = %zu"
624 ", size = %" CURL_FORMAT_CURL_OFF_T
625 ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
626 ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
627 excess_len, data->req.size, data->req.maxdownload,
628 data->req.bytecount);
629 connclose(data->conn, "excess found in a read");
630 }
631 }
632 else if(nwrite < nbytes) {
633 failf(data, "Exceeded the maximum allowed file size "
634 "(%" CURL_FORMAT_CURL_OFF_T ") with %"
635 CURL_FORMAT_CURL_OFF_T " bytes",
636 data->set.max_filesize, data->req.bytecount);
637 return CURLE_FILESIZE_EXCEEDED;
638 }
639
640 return CURLE_OK;
641 }
642
643 static const struct Curl_cwtype cw_download = {
644 "download",
645 NULL,
646 Curl_cwriter_def_init,
647 cw_download_write,
648 Curl_cwriter_def_close,
649 sizeof(struct Curl_cwriter)
650 };
651
652 /* RAW client writer in phase CURL_CW_RAW that
653 * enabled tracing of raw data. */
cw_raw_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)654 static CURLcode cw_raw_write(struct Curl_easy *data,
655 struct Curl_cwriter *writer, int type,
656 const char *buf, size_t nbytes)
657 {
658 if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
659 Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
660 }
661 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
662 }
663
664 static const struct Curl_cwtype cw_raw = {
665 "raw",
666 NULL,
667 Curl_cwriter_def_init,
668 cw_raw_write,
669 Curl_cwriter_def_close,
670 sizeof(struct Curl_cwriter)
671 };
672
673 /* Create an unencoding writer stage using the given handler. */
Curl_cwriter_create(struct Curl_cwriter ** pwriter,struct Curl_easy * data,const struct Curl_cwtype * cwt,Curl_cwriter_phase phase)674 CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
675 struct Curl_easy *data,
676 const struct Curl_cwtype *cwt,
677 Curl_cwriter_phase phase)
678 {
679 struct Curl_cwriter *writer;
680 CURLcode result = CURLE_OUT_OF_MEMORY;
681
682 DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
683 writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size);
684 if(!writer)
685 goto out;
686
687 writer->cwt = cwt;
688 writer->phase = phase;
689 result = cwt->do_init(data, writer);
690
691 out:
692 *pwriter = result? NULL : writer;
693 if(result)
694 free(writer);
695 return result;
696 }
697
Curl_cwriter_free(struct Curl_easy * data,struct Curl_cwriter * writer)698 void Curl_cwriter_free(struct Curl_easy *data,
699 struct Curl_cwriter *writer)
700 {
701 if(writer) {
702 writer->cwt->do_close(data, writer);
703 free(writer);
704 }
705 }
706
Curl_cwriter_count(struct Curl_easy * data,Curl_cwriter_phase phase)707 size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
708 {
709 struct Curl_cwriter *w;
710 size_t n = 0;
711
712 for(w = data->req.writer_stack; w; w = w->next) {
713 if(w->phase == phase)
714 ++n;
715 }
716 return n;
717 }
718
do_init_stack(struct Curl_easy * data)719 static CURLcode do_init_stack(struct Curl_easy *data)
720 {
721 struct Curl_cwriter *writer;
722 CURLcode result;
723
724 DEBUGASSERT(!data->req.writer_stack);
725 result = Curl_cwriter_create(&data->req.writer_stack,
726 data, &cw_client, CURL_CW_CLIENT);
727 if(result)
728 return result;
729
730 result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
731 if(result)
732 return result;
733 result = Curl_cwriter_add(data, writer);
734 if(result) {
735 Curl_cwriter_free(data, writer);
736 }
737
738 result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
739 if(result)
740 return result;
741 result = Curl_cwriter_add(data, writer);
742 if(result) {
743 Curl_cwriter_free(data, writer);
744 }
745 return result;
746 }
747
Curl_cwriter_add(struct Curl_easy * data,struct Curl_cwriter * writer)748 CURLcode Curl_cwriter_add(struct Curl_easy *data,
749 struct Curl_cwriter *writer)
750 {
751 CURLcode result;
752 struct Curl_cwriter **anchor = &data->req.writer_stack;
753
754 if(!*anchor) {
755 result = do_init_stack(data);
756 if(result)
757 return result;
758 }
759
760 /* Insert the writer as first in its phase.
761 * Skip existing writers of lower phases. */
762 while(*anchor && (*anchor)->phase < writer->phase)
763 anchor = &((*anchor)->next);
764 writer->next = *anchor;
765 *anchor = writer;
766 return CURLE_OK;
767 }
768
Curl_cwriter_remove_by_name(struct Curl_easy * data,const char * name)769 void Curl_cwriter_remove_by_name(struct Curl_easy *data,
770 const char *name)
771 {
772 struct Curl_cwriter **anchor = &data->req.writer_stack;
773
774 while(*anchor) {
775 if(!strcmp(name, (*anchor)->cwt->name)) {
776 struct Curl_cwriter *w = (*anchor);
777 *anchor = w->next;
778 Curl_cwriter_free(data, w);
779 continue;
780 }
781 anchor = &((*anchor)->next);
782 }
783 }
784
785 /*
786 * Internal read-from-socket function. This is meant to deal with plain
787 * sockets, SSL sockets and kerberos sockets.
788 *
789 * Returns a regular CURLcode value.
790 */
Curl_read(struct Curl_easy * data,curl_socket_t sockfd,char * buf,size_t sizerequested,ssize_t * n)791 CURLcode Curl_read(struct Curl_easy *data, /* transfer */
792 curl_socket_t sockfd, /* read from this socket */
793 char *buf, /* store read data here */
794 size_t sizerequested, /* max amount to read */
795 ssize_t *n) /* amount bytes read */
796 {
797 CURLcode result = CURLE_RECV_ERROR;
798 ssize_t nread = 0;
799 size_t bytesfromsocket = 0;
800 char *buffertofill = NULL;
801 struct connectdata *conn = data->conn;
802
803 /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
804 If it is the second socket, we set num to 1. Otherwise to 0. This lets
805 us use the correct ssl handle. */
806 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
807
808 *n = 0; /* reset amount to zero */
809
810 bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
811 buffertofill = buf;
812
813 nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
814 if(nread < 0)
815 goto out;
816
817 *n += nread;
818 result = CURLE_OK;
819 out:
820 return result;
821 }
822