• 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 "vtls/vtls.h"
44 #include "vssh/ssh.h"
45 #include "easyif.h"
46 #include "multiif.h"
47 #include "strerror.h"
48 #include "select.h"
49 #include "strdup.h"
50 #include "http2.h"
51 #include "headers.h"
52 #include "ws.h"
53 
54 /* The last 3 #include files should be in this order */
55 #include "curl_printf.h"
56 #include "curl_memory.h"
57 #include "memdebug.h"
58 
59 #if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
60 /*
61  * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
62  * (\n), with special processing for CRLF sequences that are split between two
63  * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
64  * size of the data is returned.
65  */
convert_lineends(struct Curl_easy * data,char * startPtr,size_t size)66 static size_t convert_lineends(struct Curl_easy *data,
67                                char *startPtr, size_t size)
68 {
69   char *inPtr, *outPtr;
70 
71   /* sanity check */
72   if(!startPtr || (size < 1)) {
73     return size;
74   }
75 
76   if(data->state.prev_block_had_trailing_cr) {
77     /* The previous block of incoming data
78        had a trailing CR, which was turned into a LF. */
79     if(*startPtr == '\n') {
80       /* This block of incoming data starts with the
81          previous block's LF so get rid of it */
82       memmove(startPtr, startPtr + 1, size-1);
83       size--;
84       /* and it wasn't a bare CR but a CRLF conversion instead */
85       data->state.crlf_conversions++;
86     }
87     data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
88   }
89 
90   /* find 1st CR, if any */
91   inPtr = outPtr = memchr(startPtr, '\r', size);
92   if(inPtr) {
93     /* at least one CR, now look for CRLF */
94     while(inPtr < (startPtr + size-1)) {
95       /* note that it's size-1, so we'll never look past the last byte */
96       if(memcmp(inPtr, "\r\n", 2) == 0) {
97         /* CRLF found, bump past the CR and copy the NL */
98         inPtr++;
99         *outPtr = *inPtr;
100         /* keep track of how many CRLFs we converted */
101         data->state.crlf_conversions++;
102       }
103       else {
104         if(*inPtr == '\r') {
105           /* lone CR, move LF instead */
106           *outPtr = '\n';
107         }
108         else {
109           /* not a CRLF nor a CR, just copy whatever it is */
110           *outPtr = *inPtr;
111         }
112       }
113       outPtr++;
114       inPtr++;
115     } /* end of while loop */
116 
117     if(inPtr < startPtr + size) {
118       /* handle last byte */
119       if(*inPtr == '\r') {
120         /* deal with a CR at the end of the buffer */
121         *outPtr = '\n'; /* copy a NL instead */
122         /* note that a CRLF might be split across two blocks */
123         data->state.prev_block_had_trailing_cr = TRUE;
124       }
125       else {
126         /* copy last byte */
127         *outPtr = *inPtr;
128       }
129       outPtr++;
130     }
131     if(outPtr < startPtr + size)
132       /* tidy up by null terminating the now shorter data */
133       *outPtr = '\0';
134 
135     return (outPtr - startPtr);
136   }
137   return size;
138 }
139 #endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
140 
141 /*
142  * Curl_write() is an internal write function that sends data to the
143  * server. Works with plain sockets, SCP, SSL or kerberos.
144  *
145  * If the write would block (CURLE_AGAIN), we return CURLE_OK and
146  * (*written == 0). Otherwise we return regular CURLcode value.
147  */
Curl_write(struct Curl_easy * data,curl_socket_t sockfd,const void * mem,size_t len,ssize_t * written)148 CURLcode Curl_write(struct Curl_easy *data,
149                     curl_socket_t sockfd,
150                     const void *mem,
151                     size_t len,
152                     ssize_t *written)
153 {
154   ssize_t bytes_written;
155   CURLcode result = CURLE_OK;
156   struct connectdata *conn;
157   int num;
158   DEBUGASSERT(data);
159   DEBUGASSERT(data->conn);
160   conn = data->conn;
161   num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
162 
163 #ifdef CURLDEBUG
164   {
165     /* Allow debug builds to override this logic to force short sends
166     */
167     char *p = getenv("CURL_SMALLSENDS");
168     if(p) {
169       size_t altsize = (size_t)strtoul(p, NULL, 10);
170       if(altsize)
171         len = CURLMIN(len, altsize);
172     }
173   }
174 #endif
175   bytes_written = conn->send[num](data, num, mem, len, &result);
176 
177   *written = bytes_written;
178   if(bytes_written >= 0)
179     /* we completely ignore the curlcode value when subzero is not returned */
180     return CURLE_OK;
181 
182   /* handle CURLE_AGAIN or a send failure */
183   switch(result) {
184   case CURLE_AGAIN:
185     *written = 0;
186     return CURLE_OK;
187 
188   case CURLE_OK:
189     /* general send failure */
190     return CURLE_SEND_ERROR;
191 
192   default:
193     /* we got a specific curlcode, forward it */
194     return result;
195   }
196 }
197 
pausewrite(struct Curl_easy * data,int type,const char * ptr,size_t len)198 static CURLcode pausewrite(struct Curl_easy *data,
199                            int type, /* what type of data */
200                            const char *ptr,
201                            size_t len)
202 {
203   /* signalled to pause sending on this connection, but since we have data
204      we want to send we need to dup it to save a copy for when the sending
205      is again enabled */
206   struct SingleRequest *k = &data->req;
207   struct UrlState *s = &data->state;
208   unsigned int i;
209   bool newtype = TRUE;
210 
211   Curl_conn_ev_data_pause(data, TRUE);
212 
213   if(s->tempcount) {
214     for(i = 0; i< s->tempcount; i++) {
215       if(s->tempwrite[i].type == type) {
216         /* data for this type exists */
217         newtype = FALSE;
218         break;
219       }
220     }
221     DEBUGASSERT(i < 3);
222     if(i >= 3)
223       /* There are more types to store than what fits: very bad */
224       return CURLE_OUT_OF_MEMORY;
225   }
226   else
227     i = 0;
228 
229   if(newtype) {
230     /* store this information in the state struct for later use */
231     Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
232     s->tempwrite[i].type = type;
233     s->tempcount++;
234   }
235 
236   if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
237     return CURLE_OUT_OF_MEMORY;
238 
239   /* mark the connection as RECV paused */
240   k->keepon |= KEEP_RECV_PAUSE;
241 
242   return CURLE_OK;
243 }
244 
245 
246 /* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
247  * client write callback(s) and takes care of pause requests from the
248  * callbacks.
249  */
chop_write(struct Curl_easy * data,int type,char * optr,size_t olen)250 static CURLcode chop_write(struct Curl_easy *data,
251                            int type,
252                            char *optr,
253                            size_t olen)
254 {
255   struct connectdata *conn = data->conn;
256   curl_write_callback writeheader = NULL;
257   curl_write_callback writebody = NULL;
258   char *ptr = optr;
259   size_t len = olen;
260   void *writebody_ptr = data->set.out;
261 
262   if(!len)
263     return CURLE_OK;
264 
265   /* If reading is paused, append this data to the already held data for this
266      type. */
267   if(data->req.keepon & KEEP_RECV_PAUSE)
268     return pausewrite(data, type, ptr, len);
269 
270   /* Determine the callback(s) to use. */
271   if(type & CLIENTWRITE_BODY) {
272 #ifdef USE_WEBSOCKETS
273     if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
274       struct HTTP *ws = data->req.p.http;
275       writebody = Curl_ws_writecb;
276       ws->ws.data = data;
277       writebody_ptr = ws;
278     }
279     else
280 #endif
281     writebody = data->set.fwrite_func;
282   }
283   if((type & CLIENTWRITE_HEADER) &&
284      (data->set.fwrite_header || data->set.writeheader)) {
285     /*
286      * Write headers to the same callback or to the especially setup
287      * header callback function (added after version 7.7.1).
288      */
289     writeheader =
290       data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
291   }
292 
293   /* Chop data, write chunks. */
294   while(len) {
295     size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
296 
297     if(writebody) {
298       size_t wrote;
299       Curl_set_in_callback(data, true);
300       wrote = writebody(ptr, 1, chunklen, writebody_ptr);
301       Curl_set_in_callback(data, false);
302 
303       if(CURL_WRITEFUNC_PAUSE == wrote) {
304         if(conn->handler->flags & PROTOPT_NONETWORK) {
305           /* Protocols that work without network cannot be paused. This is
306              actually only FILE:// just now, and it can't pause since the
307              transfer isn't done using the "normal" procedure. */
308           failf(data, "Write callback asked for PAUSE when not supported");
309           return CURLE_WRITE_ERROR;
310         }
311         return pausewrite(data, type, ptr, len);
312       }
313       if(wrote != chunklen) {
314         failf(data, "Failure writing output to destination");
315         return CURLE_WRITE_ERROR;
316       }
317     }
318 
319     ptr += chunklen;
320     len -= chunklen;
321   }
322 
323 #ifndef CURL_DISABLE_HTTP
324   /* HTTP header, but not status-line */
325   if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
326      (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
327     unsigned char htype = (unsigned char)
328       (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
329        (type & CLIENTWRITE_1XX ? CURLH_1XX :
330         (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
331          CURLH_HEADER)));
332     CURLcode result = Curl_headers_push(data, optr, htype);
333     if(result)
334       return result;
335   }
336 #endif
337 
338   if(writeheader) {
339     size_t wrote;
340 
341     Curl_set_in_callback(data, true);
342     wrote = writeheader(optr, 1, olen, data->set.writeheader);
343     Curl_set_in_callback(data, false);
344 
345     if(CURL_WRITEFUNC_PAUSE == wrote)
346       /* here we pass in the HEADER bit only since if this was body as well
347          then it was passed already and clearly that didn't trigger the
348          pause, so this is saved for later with the HEADER bit only */
349       return pausewrite(data, CLIENTWRITE_HEADER |
350                         (type & (CLIENTWRITE_STATUS|CLIENTWRITE_CONNECT|
351                                  CLIENTWRITE_1XX|CLIENTWRITE_TRAILER)),
352                         optr, olen);
353     if(wrote != olen) {
354       failf(data, "Failed writing header");
355       return CURLE_WRITE_ERROR;
356     }
357   }
358 
359   return CURLE_OK;
360 }
361 
362 
363 /* Curl_client_write() sends data to the write callback(s)
364 
365    The bit pattern defines to what "streams" to write to. Body and/or header.
366    The defines are in sendf.h of course.
367 
368    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
369    local character encoding.  This is a problem and should be changed in
370    the future to leave the original data alone.
371  */
Curl_client_write(struct Curl_easy * data,int type,char * ptr,size_t len)372 CURLcode Curl_client_write(struct Curl_easy *data,
373                            int type,
374                            char *ptr,
375                            size_t len)
376 {
377 #if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
378   /* FTP data may need conversion. */
379   if((type & CLIENTWRITE_BODY) &&
380      (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
381      data->conn->proto.ftpc.transfertype == 'A') {
382     /* convert end-of-line markers */
383     len = convert_lineends(data, ptr, len);
384   }
385 #endif
386   return chop_write(data, type, ptr, len);
387 }
388 
389 /*
390  * Internal read-from-socket function. This is meant to deal with plain
391  * sockets, SSL sockets and kerberos sockets.
392  *
393  * Returns a regular CURLcode value.
394  */
Curl_read(struct Curl_easy * data,curl_socket_t sockfd,char * buf,size_t sizerequested,ssize_t * n)395 CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
396                    curl_socket_t sockfd,     /* read from this socket */
397                    char *buf,                /* store read data here */
398                    size_t sizerequested,     /* max amount to read */
399                    ssize_t *n)               /* amount bytes read */
400 {
401   CURLcode result = CURLE_RECV_ERROR;
402   ssize_t nread = 0;
403   size_t bytesfromsocket = 0;
404   char *buffertofill = NULL;
405   struct connectdata *conn = data->conn;
406 
407   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
408      If it is the second socket, we set num to 1. Otherwise to 0. This lets
409      us use the correct ssl handle. */
410   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
411 
412   *n = 0; /* reset amount to zero */
413 
414   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
415   buffertofill = buf;
416 
417   nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
418   if(nread < 0)
419     goto out;
420 
421   *n += nread;
422   result = CURLE_OK;
423 out:
424   /* DEBUGF(infof(data, "Curl_read(handle=%p) -> %d, nread=%ld",
425         data, result, nread)); */
426   return result;
427 }
428 
429