• 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 "ws.h"
54 
55 /* The last 3 #include files should be in this order */
56 #include "curl_printf.h"
57 #include "curl_memory.h"
58 #include "memdebug.h"
59 
60 #if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
61 /*
62  * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
63  * (\n), with special processing for CRLF sequences that are split between two
64  * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
65  * size of the data is returned.
66  */
convert_lineends(struct Curl_easy * data,char * startPtr,size_t size)67 static size_t convert_lineends(struct Curl_easy *data,
68                                char *startPtr, size_t size)
69 {
70   char *inPtr, *outPtr;
71 
72   /* sanity check */
73   if(!startPtr || (size < 1)) {
74     return size;
75   }
76 
77   if(data->state.prev_block_had_trailing_cr) {
78     /* The previous block of incoming data
79        had a trailing CR, which was turned into a LF. */
80     if(*startPtr == '\n') {
81       /* This block of incoming data starts with the
82          previous block's LF so get rid of it */
83       memmove(startPtr, startPtr + 1, size-1);
84       size--;
85       /* and it wasn't a bare CR but a CRLF conversion instead */
86       data->state.crlf_conversions++;
87     }
88     data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
89   }
90 
91   /* find 1st CR, if any */
92   inPtr = outPtr = memchr(startPtr, '\r', size);
93   if(inPtr) {
94     /* at least one CR, now look for CRLF */
95     while(inPtr < (startPtr + size-1)) {
96       /* note that it's size-1, so we'll never look past the last byte */
97       if(memcmp(inPtr, "\r\n", 2) == 0) {
98         /* CRLF found, bump past the CR and copy the NL */
99         inPtr++;
100         *outPtr = *inPtr;
101         /* keep track of how many CRLFs we converted */
102         data->state.crlf_conversions++;
103       }
104       else {
105         if(*inPtr == '\r') {
106           /* lone CR, move LF instead */
107           *outPtr = '\n';
108         }
109         else {
110           /* not a CRLF nor a CR, just copy whatever it is */
111           *outPtr = *inPtr;
112         }
113       }
114       outPtr++;
115       inPtr++;
116     } /* end of while loop */
117 
118     if(inPtr < startPtr + size) {
119       /* handle last byte */
120       if(*inPtr == '\r') {
121         /* deal with a CR at the end of the buffer */
122         *outPtr = '\n'; /* copy a NL instead */
123         /* note that a CRLF might be split across two blocks */
124         data->state.prev_block_had_trailing_cr = TRUE;
125       }
126       else {
127         /* copy last byte */
128         *outPtr = *inPtr;
129       }
130       outPtr++;
131     }
132     if(outPtr < startPtr + size)
133       /* tidy up by null terminating the now shorter data */
134       *outPtr = '\0';
135 
136     return (outPtr - startPtr);
137   }
138   return size;
139 }
140 #endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
141 
142 /*
143  * Curl_nwrite() is an internal write function that sends data to the
144  * server. Works with a socket index for the connection.
145  *
146  * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
147  * (*nwritten == 0). Otherwise we return regular CURLcode value.
148  */
Curl_nwrite(struct Curl_easy * data,int sockindex,const void * buf,size_t blen,ssize_t * pnwritten)149 CURLcode Curl_nwrite(struct Curl_easy *data,
150                      int sockindex,
151                      const void *buf,
152                      size_t blen,
153                      ssize_t *pnwritten)
154 {
155   ssize_t nwritten;
156   CURLcode result = CURLE_OK;
157   struct connectdata *conn;
158 
159   DEBUGASSERT(sockindex >= 0 && sockindex < 2);
160   DEBUGASSERT(pnwritten);
161   DEBUGASSERT(data);
162   DEBUGASSERT(data->conn);
163   conn = data->conn;
164 #ifdef CURLDEBUG
165   {
166     /* Allow debug builds to override this logic to force short sends
167     */
168     char *p = getenv("CURL_SMALLSENDS");
169     if(p) {
170       size_t altsize = (size_t)strtoul(p, NULL, 10);
171       if(altsize)
172         blen = CURLMIN(blen, altsize);
173     }
174   }
175 #endif
176   nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
177   if(result == CURLE_AGAIN) {
178     nwritten = 0;
179     result = CURLE_OK;
180   }
181   else if(result) {
182     nwritten = -1; /* make sure */
183   }
184   else {
185     DEBUGASSERT(nwritten >= 0);
186   }
187 
188   *pnwritten = nwritten;
189   return result;
190 }
191 
192 /*
193  * Curl_write() is an internal write function that sends data to the
194  * server. Works with plain sockets, SCP, SSL or kerberos.
195  *
196  * If the write would block (CURLE_AGAIN), we return CURLE_OK and
197  * (*written == 0). Otherwise we return regular CURLcode value.
198  */
Curl_write(struct Curl_easy * data,curl_socket_t sockfd,const void * mem,size_t len,ssize_t * written)199 CURLcode Curl_write(struct Curl_easy *data,
200                     curl_socket_t sockfd,
201                     const void *mem,
202                     size_t len,
203                     ssize_t *written)
204 {
205   struct connectdata *conn;
206   int num;
207 
208   DEBUGASSERT(data);
209   DEBUGASSERT(data->conn);
210   conn = data->conn;
211   num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
212   return Curl_nwrite(data, num, mem, len, written);
213 }
214 
pausewrite(struct Curl_easy * data,int type,bool paused_body,const char * ptr,size_t len)215 static CURLcode pausewrite(struct Curl_easy *data,
216                            int type, /* what type of data */
217                            bool paused_body,
218                            const char *ptr,
219                            size_t len)
220 {
221   /* signalled to pause sending on this connection, but since we have data
222      we want to send we need to dup it to save a copy for when the sending
223      is again enabled */
224   struct SingleRequest *k = &data->req;
225   struct UrlState *s = &data->state;
226   unsigned int i;
227   bool newtype = TRUE;
228 
229   Curl_conn_ev_data_pause(data, TRUE);
230 
231   if(s->tempcount) {
232     for(i = 0; i< s->tempcount; i++) {
233       if(s->tempwrite[i].type == type &&
234          !!s->tempwrite[i].paused_body == !!paused_body) {
235         /* data for this type exists */
236         newtype = FALSE;
237         break;
238       }
239     }
240     DEBUGASSERT(i < 3);
241     if(i >= 3)
242       /* There are more types to store than what fits: very bad */
243       return CURLE_OUT_OF_MEMORY;
244   }
245   else
246     i = 0;
247 
248   if(newtype) {
249     /* store this information in the state struct for later use */
250     Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
251     s->tempwrite[i].type = type;
252     s->tempwrite[i].paused_body = paused_body;
253     s->tempcount++;
254   }
255 
256   if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
257     return CURLE_OUT_OF_MEMORY;
258 
259   /* mark the connection as RECV paused */
260   k->keepon |= KEEP_RECV_PAUSE;
261 
262   return CURLE_OK;
263 }
264 
265 
266 /* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
267  * client write callback(s) and takes care of pause requests from the
268  * callbacks.
269  */
chop_write(struct Curl_easy * data,int type,bool skip_body_write,char * optr,size_t olen)270 static CURLcode chop_write(struct Curl_easy *data,
271                            int type,
272                            bool skip_body_write,
273                            char *optr,
274                            size_t olen)
275 {
276   struct connectdata *conn = data->conn;
277   curl_write_callback writeheader = NULL;
278   curl_write_callback writebody = NULL;
279   char *ptr = optr;
280   size_t len = olen;
281   void *writebody_ptr = data->set.out;
282 
283   if(!len)
284     return CURLE_OK;
285 
286   /* If reading is paused, append this data to the already held data for this
287      type. */
288   if(data->req.keepon & KEEP_RECV_PAUSE)
289     return pausewrite(data, type, !skip_body_write, ptr, len);
290 
291   /* Determine the callback(s) to use. */
292   if(!skip_body_write &&
293      ((type & CLIENTWRITE_BODY) ||
294       ((type & CLIENTWRITE_HEADER) && data->set.include_header))) {
295 #ifdef USE_WEBSOCKETS
296     if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
297       writebody = Curl_ws_writecb;
298       writebody_ptr = data;
299     }
300     else
301 #endif
302     writebody = data->set.fwrite_func;
303   }
304   if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) &&
305      (data->set.fwrite_header || data->set.writeheader)) {
306     /*
307      * Write headers to the same callback or to the especially setup
308      * header callback function (added after version 7.7.1).
309      */
310     writeheader =
311       data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
312   }
313 
314   /* Chop data, write chunks. */
315   while(len) {
316     size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
317 
318     if(writebody) {
319       size_t wrote;
320       Curl_set_in_callback(data, true);
321       wrote = writebody(ptr, 1, chunklen, writebody_ptr);
322       Curl_set_in_callback(data, false);
323 
324       if(CURL_WRITEFUNC_PAUSE == wrote) {
325         if(conn->handler->flags & PROTOPT_NONETWORK) {
326           /* Protocols that work without network cannot be paused. This is
327              actually only FILE:// just now, and it can't pause since the
328              transfer isn't done using the "normal" procedure. */
329           failf(data, "Write callback asked for PAUSE when not supported");
330           return CURLE_WRITE_ERROR;
331         }
332         return pausewrite(data, type, TRUE, ptr, len);
333       }
334       if(wrote != chunklen) {
335         failf(data, "Failure writing output to destination");
336         return CURLE_WRITE_ERROR;
337       }
338     }
339 
340     ptr += chunklen;
341     len -= chunklen;
342   }
343 
344 #ifndef CURL_DISABLE_HTTP
345   /* HTTP header, but not status-line */
346   if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
347      (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
348     unsigned char htype = (unsigned char)
349       (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
350        (type & CLIENTWRITE_1XX ? CURLH_1XX :
351         (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
352          CURLH_HEADER)));
353     CURLcode result = Curl_headers_push(data, optr, htype);
354     if(result)
355       return result;
356   }
357 #endif
358 
359   if(writeheader) {
360     size_t wrote;
361 
362     Curl_set_in_callback(data, true);
363     wrote = writeheader(optr, 1, olen, data->set.writeheader);
364     Curl_set_in_callback(data, false);
365 
366     if(CURL_WRITEFUNC_PAUSE == wrote)
367       return pausewrite(data, type, FALSE, optr, olen);
368     if(wrote != olen) {
369       failf(data, "Failed writing header");
370       return CURLE_WRITE_ERROR;
371     }
372   }
373 
374   return CURLE_OK;
375 }
376 
377 
378 /* Curl_client_write() sends data to the write callback(s)
379 
380    The bit pattern defines to what "streams" to write to. Body and/or header.
381    The defines are in sendf.h of course.
382 
383    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
384    local character encoding.  This is a problem and should be changed in
385    the future to leave the original data alone.
386  */
Curl_client_write(struct Curl_easy * data,int type,char * ptr,size_t len)387 CURLcode Curl_client_write(struct Curl_easy *data,
388                            int type,
389                            char *ptr,
390                            size_t len)
391 {
392 #if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
393   /* FTP data may need conversion. */
394   if((type & CLIENTWRITE_BODY) &&
395      (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
396      data->conn->proto.ftpc.transfertype == 'A') {
397     /* convert end-of-line markers */
398     len = convert_lineends(data, ptr, len);
399   }
400 #endif
401   /* it is one of those, at least */
402   DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
403   /* BODY is only BODY */
404   DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY));
405   /* INFO is only INFO */
406   DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
407 
408   if(type == CLIENTWRITE_BODY) {
409     if(data->req.ignorebody)
410       return CURLE_OK;
411 
412     if(data->req.writer_stack && !data->set.http_ce_skip)
413       return Curl_unencode_write(data, data->req.writer_stack, ptr, len);
414   }
415   return chop_write(data, type, FALSE, ptr, len);
416 }
417 
Curl_client_unpause(struct Curl_easy * data)418 CURLcode Curl_client_unpause(struct Curl_easy *data)
419 {
420   CURLcode result = CURLE_OK;
421 
422   if(data->state.tempcount) {
423     /* there are buffers for sending that can be delivered as the receive
424        pausing is lifted! */
425     unsigned int i;
426     unsigned int count = data->state.tempcount;
427     struct tempbuf writebuf[3]; /* there can only be three */
428 
429     /* copy the structs to allow for immediate re-pausing */
430     for(i = 0; i < data->state.tempcount; i++) {
431       writebuf[i] = data->state.tempwrite[i];
432       Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER);
433     }
434     data->state.tempcount = 0;
435 
436     for(i = 0; i < count; i++) {
437       /* even if one function returns error, this loops through and frees
438          all buffers */
439       if(!result)
440         result = chop_write(data, writebuf[i].type,
441                             !writebuf[i].paused_body,
442                             Curl_dyn_ptr(&writebuf[i].b),
443                             Curl_dyn_len(&writebuf[i].b));
444       Curl_dyn_free(&writebuf[i].b);
445     }
446   }
447   return result;
448 }
449 
Curl_client_cleanup(struct Curl_easy * data)450 void Curl_client_cleanup(struct Curl_easy *data)
451 {
452   struct contenc_writer *writer = data->req.writer_stack;
453   size_t i;
454 
455   while(writer) {
456     data->req.writer_stack = writer->downstream;
457     writer->handler->close_writer(data, writer);
458     free(writer);
459     writer = data->req.writer_stack;
460   }
461 
462   for(i = 0; i < data->state.tempcount; i++) {
463     Curl_dyn_free(&data->state.tempwrite[i].b);
464   }
465   data->state.tempcount = 0;
466 
467 }
468 
469 /* Real client writer: no downstream. */
client_cew_init(struct Curl_easy * data,struct contenc_writer * writer)470 static CURLcode client_cew_init(struct Curl_easy *data,
471                                 struct contenc_writer *writer)
472 {
473   (void) data;
474   (void)writer;
475   return CURLE_OK;
476 }
477 
client_cew_write(struct Curl_easy * data,struct contenc_writer * writer,const char * buf,size_t nbytes)478 static CURLcode client_cew_write(struct Curl_easy *data,
479                                  struct contenc_writer *writer,
480                                  const char *buf, size_t nbytes)
481 {
482   (void)writer;
483   if(!nbytes || data->req.ignorebody)
484     return CURLE_OK;
485   return chop_write(data, CLIENTWRITE_BODY, FALSE, (char *)buf, nbytes);
486 }
487 
client_cew_close(struct Curl_easy * data,struct contenc_writer * writer)488 static void client_cew_close(struct Curl_easy *data,
489                              struct contenc_writer *writer)
490 {
491   (void) data;
492   (void) writer;
493 }
494 
495 static const struct content_encoding client_cew = {
496   NULL,
497   NULL,
498   client_cew_init,
499   client_cew_write,
500   client_cew_close,
501   sizeof(struct contenc_writer)
502 };
503 
504 /* Create an unencoding writer stage using the given handler. */
Curl_client_create_writer(struct contenc_writer ** pwriter,struct Curl_easy * data,const struct content_encoding * ce_handler,int order)505 CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
506                                    struct Curl_easy *data,
507                                    const struct content_encoding *ce_handler,
508                                    int order)
509 {
510   struct contenc_writer *writer;
511   CURLcode result = CURLE_OUT_OF_MEMORY;
512 
513   DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer));
514   writer = (struct contenc_writer *) calloc(1, ce_handler->writersize);
515   if(!writer)
516     goto out;
517 
518   writer->handler = ce_handler;
519   writer->order = order;
520   result = ce_handler->init_writer(data, writer);
521 
522 out:
523   *pwriter = result? NULL : writer;
524   if(result)
525     free(writer);
526   return result;
527 }
528 
Curl_client_free_writer(struct Curl_easy * data,struct contenc_writer * writer)529 void Curl_client_free_writer(struct Curl_easy *data,
530                              struct contenc_writer *writer)
531 {
532   if(writer) {
533     writer->handler->close_writer(data, writer);
534     free(writer);
535   }
536 }
537 
538 /* allow no more than 5 "chained" compression steps */
539 #define MAX_ENCODE_STACK 5
540 
541 
init_writer_stack(struct Curl_easy * data)542 static CURLcode init_writer_stack(struct Curl_easy *data)
543 {
544   DEBUGASSERT(!data->req.writer_stack);
545   return Curl_client_create_writer(&data->req.writer_stack,
546                                    data, &client_cew, 0);
547 }
548 
Curl_client_add_writer(struct Curl_easy * data,struct contenc_writer * writer)549 CURLcode Curl_client_add_writer(struct Curl_easy *data,
550                                 struct contenc_writer *writer)
551 {
552   CURLcode result;
553 
554   if(!data->req.writer_stack) {
555     result = init_writer_stack(data);
556     if(result)
557       return result;
558   }
559 
560   if(data->req.writer_stack_depth++ >= MAX_ENCODE_STACK) {
561     failf(data, "Reject response due to more than %u content encodings",
562           MAX_ENCODE_STACK);
563     return CURLE_BAD_CONTENT_ENCODING;
564   }
565 
566   /* Stack the unencoding stage. */
567   if(writer->order >= data->req.writer_stack->order) {
568     writer->downstream = data->req.writer_stack;
569     data->req.writer_stack = writer;
570   }
571   else {
572     struct contenc_writer *w = data->req.writer_stack;
573     while(w->downstream && writer->order < w->downstream->order)
574       w = w->downstream;
575     writer->downstream = w->downstream;
576     w->downstream = writer;
577   }
578   return CURLE_OK;
579 }
580 
581 
582 /*
583  * Internal read-from-socket function. This is meant to deal with plain
584  * sockets, SSL sockets and kerberos sockets.
585  *
586  * Returns a regular CURLcode value.
587  */
Curl_read(struct Curl_easy * data,curl_socket_t sockfd,char * buf,size_t sizerequested,ssize_t * n)588 CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
589                    curl_socket_t sockfd,     /* read from this socket */
590                    char *buf,                /* store read data here */
591                    size_t sizerequested,     /* max amount to read */
592                    ssize_t *n)               /* amount bytes read */
593 {
594   CURLcode result = CURLE_RECV_ERROR;
595   ssize_t nread = 0;
596   size_t bytesfromsocket = 0;
597   char *buffertofill = NULL;
598   struct connectdata *conn = data->conn;
599 
600   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
601      If it is the second socket, we set num to 1. Otherwise to 0. This lets
602      us use the correct ssl handle. */
603   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
604 
605   *n = 0; /* reset amount to zero */
606 
607   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
608   buffertofill = buf;
609 
610   nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
611   if(nread < 0)
612     goto out;
613 
614   *n += nread;
615   result = CURLE_OK;
616 out:
617   return result;
618 }
619