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