• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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