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 */
67static 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 */
149CURLcode 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 */
199CURLcode 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, sockindex: num, buf: mem, blen: len, pnwritten: written);
213}
214
215static 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: &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: &s->tempwrite[i].b, mem: (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 */
270static 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, paused_body: !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, fmt: "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, fmt: "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, header: optr, type: 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, ptr: optr, len: olen);
368 if(wrote != olen) {
369 failf(data, fmt: "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 */
387CURLcode 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, writer: data->req.writer_stack, buf: ptr, nbytes: len);
414 }
415 return chop_write(data, type, FALSE, optr: ptr, olen: len);
416}
417
418CURLcode 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(s: &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, type: writebuf[i].type,
441 skip_body_write: !writebuf[i].paused_body,
442 optr: Curl_dyn_ptr(s: &writebuf[i].b),
443 olen: Curl_dyn_len(s: &writebuf[i].b));
444 Curl_dyn_free(s: &writebuf[i].b);
445 }
446 }
447 return result;
448}
449
450void 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(s: &data->state.tempwrite[i].b);
464 }
465 data->state.tempcount = 0;
466
467}
468
469/* Real client writer: no downstream. */
470static 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
478static 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, optr: (char *)buf, olen: nbytes);
486}
487
488static void client_cew_close(struct Curl_easy *data,
489 struct contenc_writer *writer)
490{
491 (void) data;
492 (void) writer;
493}
494
495static 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. */
505CURLcode 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
522out:
523 *pwriter = result? NULL : writer;
524 if(result)
525 free(writer);
526 return result;
527}
528
529void 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
542static CURLcode init_writer_stack(struct Curl_easy *data)
543{
544 DEBUGASSERT(!data->req.writer_stack);
545 return Curl_client_create_writer(pwriter: &data->req.writer_stack,
546 data, ce_handler: &client_cew, order: 0);
547}
548
549CURLcode 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, fmt: "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 */
588CURLcode 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;
616out:
617 return result;
618}
619