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 "cw-out.h"
45 #include "vtls/vtls.h"
46 #include "vssh/ssh.h"
47 #include "easyif.h"
48 #include "multiif.h"
49 #include "strerror.h"
50 #include "select.h"
51 #include "strdup.h"
52 #include "http2.h"
53 #include "progress.h"
54 #include "warnless.h"
55 #include "ws.h"
56
57 /* The last 3 #include files should be in this order */
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 #include "memdebug.h"
61
62
63 static CURLcode do_init_writer_stack(struct Curl_easy *data);
64
65 /* Curl_client_write() sends data to the write callback(s)
66
67 The bit pattern defines to what "streams" to write to. Body and/or header.
68 The defines are in sendf.h of course.
69 */
Curl_client_write(struct Curl_easy * data,int type,const char * buf,size_t blen)70 CURLcode Curl_client_write(struct Curl_easy *data,
71 int type, const char *buf, size_t blen)
72 {
73 CURLcode result;
74
75 /* it is one of those, at least */
76 DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
77 /* BODY is only BODY (with optional EOS) */
78 DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
79 ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
80 /* INFO is only INFO (with optional EOS) */
81 DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
82 ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
83
84 if(!data->req.writer_stack) {
85 result = do_init_writer_stack(data);
86 if(result)
87 return result;
88 DEBUGASSERT(data->req.writer_stack);
89 }
90
91 result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
92 CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
93 type, blen, result);
94 return result;
95 }
96
cl_reset_writer(struct Curl_easy * data)97 static void cl_reset_writer(struct Curl_easy *data)
98 {
99 struct Curl_cwriter *writer = data->req.writer_stack;
100 while(writer) {
101 data->req.writer_stack = writer->next;
102 writer->cwt->do_close(data, writer);
103 free(writer);
104 writer = data->req.writer_stack;
105 }
106 }
107
cl_reset_reader(struct Curl_easy * data)108 static void cl_reset_reader(struct Curl_easy *data)
109 {
110 struct Curl_creader *reader = data->req.reader_stack;
111 while(reader) {
112 data->req.reader_stack = reader->next;
113 reader->crt->do_close(data, reader);
114 free(reader);
115 reader = data->req.reader_stack;
116 }
117 }
118
Curl_client_cleanup(struct Curl_easy * data)119 void Curl_client_cleanup(struct Curl_easy *data)
120 {
121 cl_reset_reader(data);
122 cl_reset_writer(data);
123
124 data->req.bytecount = 0;
125 data->req.headerline = 0;
126 }
127
Curl_client_reset(struct Curl_easy * data)128 void Curl_client_reset(struct Curl_easy *data)
129 {
130 if(data->req.rewind_read) {
131 /* already requested */
132 CURL_TRC_READ(data, "client_reset, will rewind reader");
133 }
134 else {
135 CURL_TRC_READ(data, "client_reset, clear readers");
136 cl_reset_reader(data);
137 }
138 cl_reset_writer(data);
139
140 data->req.bytecount = 0;
141 data->req.headerline = 0;
142 }
143
Curl_client_start(struct Curl_easy * data)144 CURLcode Curl_client_start(struct Curl_easy *data)
145 {
146 if(data->req.rewind_read) {
147 struct Curl_creader *r = data->req.reader_stack;
148 CURLcode result = CURLE_OK;
149
150 CURL_TRC_READ(data, "client start, rewind readers");
151 while(r) {
152 result = r->crt->rewind(data, r);
153 if(result) {
154 failf(data, "rewind of client reader '%s' failed: %d",
155 r->crt->name, result);
156 return result;
157 }
158 r = r->next;
159 }
160 data->req.rewind_read = FALSE;
161 cl_reset_reader(data);
162 }
163 return CURLE_OK;
164 }
165
Curl_creader_will_rewind(struct Curl_easy * data)166 bool Curl_creader_will_rewind(struct Curl_easy *data)
167 {
168 return data->req.rewind_read;
169 }
170
Curl_creader_set_rewind(struct Curl_easy * data,bool enable)171 void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
172 {
173 data->req.rewind_read = !!enable;
174 }
175
176 /* Write data using an unencoding writer stack. */
Curl_cwriter_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)177 CURLcode Curl_cwriter_write(struct Curl_easy *data,
178 struct Curl_cwriter *writer, int type,
179 const char *buf, size_t nbytes)
180 {
181 if(!writer)
182 return CURLE_WRITE_ERROR;
183 return writer->cwt->do_write(data, writer, type, buf, nbytes);
184 }
185
Curl_cwriter_def_init(struct Curl_easy * data,struct Curl_cwriter * writer)186 CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
187 struct Curl_cwriter *writer)
188 {
189 (void)data;
190 (void)writer;
191 return CURLE_OK;
192 }
193
Curl_cwriter_def_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)194 CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
195 struct Curl_cwriter *writer, int type,
196 const char *buf, size_t nbytes)
197 {
198 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
199 }
200
Curl_cwriter_def_close(struct Curl_easy * data,struct Curl_cwriter * writer)201 void Curl_cwriter_def_close(struct Curl_easy *data,
202 struct Curl_cwriter *writer)
203 {
204 (void) data;
205 (void) writer;
206 }
207
get_max_body_write_len(struct Curl_easy * data,curl_off_t limit)208 static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
209 {
210 if(limit != -1) {
211 /* How much more are we allowed to write? */
212 curl_off_t remain_diff;
213 remain_diff = limit - data->req.bytecount;
214 if(remain_diff < 0) {
215 /* already written too much! */
216 return 0;
217 }
218 #if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
219 else if(remain_diff > SSIZE_T_MAX) {
220 return SIZE_T_MAX;
221 }
222 #endif
223 else {
224 return (size_t)remain_diff;
225 }
226 }
227 return SIZE_T_MAX;
228 }
229
230 struct cw_download_ctx {
231 struct Curl_cwriter super;
232 BIT(started_response);
233 };
234 /* Download client writer in phase CURL_CW_PROTOCOL that
235 * 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)236 static CURLcode cw_download_write(struct Curl_easy *data,
237 struct Curl_cwriter *writer, int type,
238 const char *buf, size_t nbytes)
239 {
240 struct cw_download_ctx *ctx = writer->ctx;
241 CURLcode result;
242 size_t nwrite, excess_len = 0;
243 bool is_connect = !!(type & CLIENTWRITE_CONNECT);
244
245 if(!is_connect && !ctx->started_response) {
246 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
247 ctx->started_response = TRUE;
248 }
249
250 if(!(type & CLIENTWRITE_BODY)) {
251 if(is_connect && data->set.suppress_connect_headers)
252 return CURLE_OK;
253 result = Curl_cwriter_write(data, writer->next, type, buf, nbytes);
254 CURL_TRC_WRITE(data, "download_write header(type=%x, blen=%zu) -> %d",
255 type, nbytes, result);
256 return result;
257 }
258
259 /* Here, we deal with REAL BODY bytes. All filtering and transfer
260 * encodings have been applied and only the true content, e.g. BODY,
261 * bytes are passed here.
262 * This allows us to check sizes, update stats, etc. independent
263 * from the protocol in play. */
264
265 if(data->req.no_body && nbytes > 0) {
266 /* BODY arrives although we want none, bail out */
267 streamclose(data->conn, "ignoring body");
268 CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu), "
269 "did not want a BODY", type, nbytes);
270 data->req.download_done = TRUE;
271 if(data->info.header_size)
272 /* if headers have been received, this is fine */
273 return CURLE_OK;
274 return CURLE_WEIRD_SERVER_REPLY;
275 }
276
277 /* Determine if we see any bytes in excess to what is allowed.
278 * We write the allowed bytes and handle excess further below.
279 * This gives deterministic BODY writes on varying buffer receive
280 * lengths. */
281 nwrite = nbytes;
282 if(-1 != data->req.maxdownload) {
283 size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
284 if(nwrite > wmax) {
285 excess_len = nbytes - wmax;
286 nwrite = wmax;
287 }
288
289 if(nwrite == wmax) {
290 data->req.download_done = TRUE;
291 }
292
293 if((type & CLIENTWRITE_EOS) && !data->req.no_body &&
294 (data->req.maxdownload > data->req.bytecount)) {
295 failf(data, "end of response with %" FMT_OFF_T " bytes missing",
296 data->req.maxdownload - data->req.bytecount);
297 return CURLE_PARTIAL_FILE;
298 }
299 }
300
301 /* Error on too large filesize is handled below, after writing
302 * the permitted bytes */
303 if(data->set.max_filesize && !data->req.ignorebody) {
304 size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
305 if(nwrite > wmax) {
306 nwrite = wmax;
307 }
308 }
309
310 if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
311 result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
312 CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
313 type, nbytes, result);
314 if(result)
315 return result;
316 }
317 /* Update stats, write and report progress */
318 data->req.bytecount += nwrite;
319 result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
320 if(result)
321 return result;
322
323 if(excess_len) {
324 if(!data->req.ignorebody) {
325 infof(data,
326 "Excess found writing body:"
327 " excess = %zu"
328 ", size = %" FMT_OFF_T
329 ", maxdownload = %" FMT_OFF_T
330 ", bytecount = %" FMT_OFF_T,
331 excess_len, data->req.size, data->req.maxdownload,
332 data->req.bytecount);
333 connclose(data->conn, "excess found in a read");
334 }
335 }
336 else if((nwrite < nbytes) && !data->req.ignorebody) {
337 failf(data, "Exceeded the maximum allowed file size "
338 "(%" FMT_OFF_T ") with %" FMT_OFF_T " bytes",
339 data->set.max_filesize, data->req.bytecount);
340 return CURLE_FILESIZE_EXCEEDED;
341 }
342
343 return CURLE_OK;
344 }
345
346 static const struct Curl_cwtype cw_download = {
347 "protocol",
348 NULL,
349 Curl_cwriter_def_init,
350 cw_download_write,
351 Curl_cwriter_def_close,
352 sizeof(struct cw_download_ctx)
353 };
354
355 /* RAW client writer in phase CURL_CW_RAW that
356 * enabled tracing of raw data. */
cw_raw_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)357 static CURLcode cw_raw_write(struct Curl_easy *data,
358 struct Curl_cwriter *writer, int type,
359 const char *buf, size_t nbytes)
360 {
361 if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
362 Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
363 }
364 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
365 }
366
367 static const struct Curl_cwtype cw_raw = {
368 "raw",
369 NULL,
370 Curl_cwriter_def_init,
371 cw_raw_write,
372 Curl_cwriter_def_close,
373 sizeof(struct Curl_cwriter)
374 };
375
376 /* 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)377 CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
378 struct Curl_easy *data,
379 const struct Curl_cwtype *cwt,
380 Curl_cwriter_phase phase)
381 {
382 struct Curl_cwriter *writer = NULL;
383 CURLcode result = CURLE_OUT_OF_MEMORY;
384 void *p;
385
386 DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
387 p = calloc(1, cwt->cwriter_size);
388 if(!p)
389 goto out;
390
391 writer = (struct Curl_cwriter *)p;
392 writer->cwt = cwt;
393 writer->ctx = p;
394 writer->phase = phase;
395 result = cwt->do_init(data, writer);
396
397 out:
398 *pwriter = result ? NULL : writer;
399 if(result)
400 free(writer);
401 return result;
402 }
403
Curl_cwriter_free(struct Curl_easy * data,struct Curl_cwriter * writer)404 void Curl_cwriter_free(struct Curl_easy *data,
405 struct Curl_cwriter *writer)
406 {
407 if(writer) {
408 writer->cwt->do_close(data, writer);
409 free(writer);
410 }
411 }
412
Curl_cwriter_count(struct Curl_easy * data,Curl_cwriter_phase phase)413 size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
414 {
415 struct Curl_cwriter *w;
416 size_t n = 0;
417
418 for(w = data->req.writer_stack; w; w = w->next) {
419 if(w->phase == phase)
420 ++n;
421 }
422 return n;
423 }
424
do_init_writer_stack(struct Curl_easy * data)425 static CURLcode do_init_writer_stack(struct Curl_easy *data)
426 {
427 struct Curl_cwriter *writer;
428 CURLcode result;
429
430 DEBUGASSERT(!data->req.writer_stack);
431 result = Curl_cwriter_create(&data->req.writer_stack,
432 data, &Curl_cwt_out, CURL_CW_CLIENT);
433 if(result)
434 return result;
435
436 result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
437 if(result)
438 return result;
439 result = Curl_cwriter_add(data, writer);
440 if(result) {
441 Curl_cwriter_free(data, writer);
442 }
443
444 result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
445 if(result)
446 return result;
447 result = Curl_cwriter_add(data, writer);
448 if(result) {
449 Curl_cwriter_free(data, writer);
450 }
451 return result;
452 }
453
Curl_cwriter_add(struct Curl_easy * data,struct Curl_cwriter * writer)454 CURLcode Curl_cwriter_add(struct Curl_easy *data,
455 struct Curl_cwriter *writer)
456 {
457 CURLcode result;
458 struct Curl_cwriter **anchor = &data->req.writer_stack;
459
460 if(!*anchor) {
461 result = do_init_writer_stack(data);
462 if(result)
463 return result;
464 }
465
466 /* Insert the writer as first in its phase.
467 * Skip existing writers of lower phases. */
468 while(*anchor && (*anchor)->phase < writer->phase)
469 anchor = &((*anchor)->next);
470 writer->next = *anchor;
471 *anchor = writer;
472 return CURLE_OK;
473 }
474
Curl_cwriter_get_by_name(struct Curl_easy * data,const char * name)475 struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
476 const char *name)
477 {
478 struct Curl_cwriter *writer;
479 for(writer = data->req.writer_stack; writer; writer = writer->next) {
480 if(!strcmp(name, writer->cwt->name))
481 return writer;
482 }
483 return NULL;
484 }
485
Curl_cwriter_get_by_type(struct Curl_easy * data,const struct Curl_cwtype * cwt)486 struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
487 const struct Curl_cwtype *cwt)
488 {
489 struct Curl_cwriter *writer;
490 for(writer = data->req.writer_stack; writer; writer = writer->next) {
491 if(writer->cwt == cwt)
492 return writer;
493 }
494 return NULL;
495 }
496
Curl_cwriter_is_paused(struct Curl_easy * data)497 bool Curl_cwriter_is_paused(struct Curl_easy *data)
498 {
499 return Curl_cw_out_is_paused(data);
500 }
501
Curl_cwriter_unpause(struct Curl_easy * data)502 CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
503 {
504 return Curl_cw_out_unpause(data);
505 }
506
Curl_creader_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)507 CURLcode Curl_creader_read(struct Curl_easy *data,
508 struct Curl_creader *reader,
509 char *buf, size_t blen, size_t *nread, bool *eos)
510 {
511 *nread = 0;
512 *eos = FALSE;
513 if(!reader)
514 return CURLE_READ_ERROR;
515 return reader->crt->do_read(data, reader, buf, blen, nread, eos);
516 }
517
Curl_creader_def_init(struct Curl_easy * data,struct Curl_creader * reader)518 CURLcode Curl_creader_def_init(struct Curl_easy *data,
519 struct Curl_creader *reader)
520 {
521 (void)data;
522 (void)reader;
523 return CURLE_OK;
524 }
525
Curl_creader_def_close(struct Curl_easy * data,struct Curl_creader * reader)526 void Curl_creader_def_close(struct Curl_easy *data,
527 struct Curl_creader *reader)
528 {
529 (void)data;
530 (void)reader;
531 }
532
Curl_creader_def_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)533 CURLcode Curl_creader_def_read(struct Curl_easy *data,
534 struct Curl_creader *reader,
535 char *buf, size_t blen,
536 size_t *nread, bool *eos)
537 {
538 if(reader->next)
539 return reader->next->crt->do_read(data, reader->next, buf, blen,
540 nread, eos);
541 else {
542 *nread = 0;
543 *eos = FALSE;
544 return CURLE_READ_ERROR;
545 }
546 }
547
Curl_creader_def_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)548 bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
549 struct Curl_creader *reader)
550 {
551 (void)data;
552 (void)reader;
553 return FALSE;
554 }
555
Curl_creader_def_total_length(struct Curl_easy * data,struct Curl_creader * reader)556 curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
557 struct Curl_creader *reader)
558 {
559 return reader->next ?
560 reader->next->crt->total_length(data, reader->next) : -1;
561 }
562
Curl_creader_def_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)563 CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
564 struct Curl_creader *reader,
565 curl_off_t offset)
566 {
567 (void)data;
568 (void)reader;
569 (void)offset;
570 return CURLE_READ_ERROR;
571 }
572
Curl_creader_def_rewind(struct Curl_easy * data,struct Curl_creader * reader)573 CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
574 struct Curl_creader *reader)
575 {
576 (void)data;
577 (void)reader;
578 return CURLE_OK;
579 }
580
Curl_creader_def_unpause(struct Curl_easy * data,struct Curl_creader * reader)581 CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
582 struct Curl_creader *reader)
583 {
584 (void)data;
585 (void)reader;
586 return CURLE_OK;
587 }
588
Curl_creader_def_is_paused(struct Curl_easy * data,struct Curl_creader * reader)589 bool Curl_creader_def_is_paused(struct Curl_easy *data,
590 struct Curl_creader *reader)
591 {
592 (void)data;
593 (void)reader;
594 return FALSE;
595 }
596
Curl_creader_def_done(struct Curl_easy * data,struct Curl_creader * reader,int premature)597 void Curl_creader_def_done(struct Curl_easy *data,
598 struct Curl_creader *reader, int premature)
599 {
600 (void)data;
601 (void)reader;
602 (void)premature;
603 }
604
605 struct cr_in_ctx {
606 struct Curl_creader super;
607 curl_read_callback read_cb;
608 void *cb_user_data;
609 curl_off_t total_len;
610 curl_off_t read_len;
611 CURLcode error_result;
612 BIT(seen_eos);
613 BIT(errored);
614 BIT(has_used_cb);
615 BIT(is_paused);
616 };
617
cr_in_init(struct Curl_easy * data,struct Curl_creader * reader)618 static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
619 {
620 struct cr_in_ctx *ctx = reader->ctx;
621 (void)data;
622 ctx->read_cb = data->state.fread_func;
623 ctx->cb_user_data = data->state.in;
624 ctx->total_len = -1;
625 ctx->read_len = 0;
626 return CURLE_OK;
627 }
628
629 /* Real client reader to installed client callbacks. */
cr_in_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)630 static CURLcode cr_in_read(struct Curl_easy *data,
631 struct Curl_creader *reader,
632 char *buf, size_t blen,
633 size_t *pnread, bool *peos)
634 {
635 struct cr_in_ctx *ctx = reader->ctx;
636 size_t nread;
637
638 ctx->is_paused = FALSE;
639
640 /* Once we have errored, we will return the same error forever */
641 if(ctx->errored) {
642 *pnread = 0;
643 *peos = FALSE;
644 return ctx->error_result;
645 }
646 if(ctx->seen_eos) {
647 *pnread = 0;
648 *peos = TRUE;
649 return CURLE_OK;
650 }
651 /* respect length limitations */
652 if(ctx->total_len >= 0) {
653 curl_off_t remain = ctx->total_len - ctx->read_len;
654 if(remain <= 0)
655 blen = 0;
656 else if(remain < (curl_off_t)blen)
657 blen = (size_t)remain;
658 }
659 nread = 0;
660 if(ctx->read_cb && blen) {
661 Curl_set_in_callback(data, TRUE);
662 nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
663 Curl_set_in_callback(data, FALSE);
664 ctx->has_used_cb = TRUE;
665 }
666
667 switch(nread) {
668 case 0:
669 if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
670 failf(data, "client read function EOF fail, "
671 "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read",
672 ctx->read_len, ctx->total_len);
673 return CURLE_READ_ERROR;
674 }
675 *pnread = 0;
676 *peos = TRUE;
677 ctx->seen_eos = TRUE;
678 break;
679
680 case CURL_READFUNC_ABORT:
681 failf(data, "operation aborted by callback");
682 *pnread = 0;
683 *peos = FALSE;
684 ctx->errored = TRUE;
685 ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
686 return CURLE_ABORTED_BY_CALLBACK;
687
688 case CURL_READFUNC_PAUSE:
689 if(data->conn->handler->flags & PROTOPT_NONETWORK) {
690 /* protocols that work without network cannot be paused. This is
691 actually only FILE:// just now, and it cannot pause since the transfer
692 is not done using the "normal" procedure. */
693 failf(data, "Read callback asked for PAUSE when not supported");
694 return CURLE_READ_ERROR;
695 }
696 /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
697 CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
698 ctx->is_paused = TRUE;
699 data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
700 *pnread = 0;
701 *peos = FALSE;
702 break; /* nothing was read */
703
704 default:
705 if(nread > blen) {
706 /* the read function returned a too large value */
707 failf(data, "read function returned funny value");
708 *pnread = 0;
709 *peos = FALSE;
710 ctx->errored = TRUE;
711 ctx->error_result = CURLE_READ_ERROR;
712 return CURLE_READ_ERROR;
713 }
714 ctx->read_len += nread;
715 if(ctx->total_len >= 0)
716 ctx->seen_eos = (ctx->read_len >= ctx->total_len);
717 *pnread = nread;
718 *peos = ctx->seen_eos;
719 break;
720 }
721 CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T
722 ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d",
723 blen, ctx->total_len, ctx->read_len, CURLE_OK,
724 *pnread, *peos);
725 return CURLE_OK;
726 }
727
cr_in_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)728 static bool cr_in_needs_rewind(struct Curl_easy *data,
729 struct Curl_creader *reader)
730 {
731 struct cr_in_ctx *ctx = reader->ctx;
732 (void)data;
733 return ctx->has_used_cb;
734 }
735
cr_in_total_length(struct Curl_easy * data,struct Curl_creader * reader)736 static curl_off_t cr_in_total_length(struct Curl_easy *data,
737 struct Curl_creader *reader)
738 {
739 struct cr_in_ctx *ctx = reader->ctx;
740 (void)data;
741 return ctx->total_len;
742 }
743
cr_in_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)744 static CURLcode cr_in_resume_from(struct Curl_easy *data,
745 struct Curl_creader *reader,
746 curl_off_t offset)
747 {
748 struct cr_in_ctx *ctx = reader->ctx;
749 int seekerr = CURL_SEEKFUNC_CANTSEEK;
750
751 DEBUGASSERT(data->conn);
752 /* already started reading? */
753 if(ctx->read_len)
754 return CURLE_READ_ERROR;
755
756 if(data->set.seek_func) {
757 Curl_set_in_callback(data, TRUE);
758 seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
759 Curl_set_in_callback(data, FALSE);
760 }
761
762 if(seekerr != CURL_SEEKFUNC_OK) {
763 curl_off_t passed = 0;
764
765 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
766 failf(data, "Could not seek stream");
767 return CURLE_READ_ERROR;
768 }
769 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
770 do {
771 char scratch[4*1024];
772 size_t readthisamountnow =
773 (offset - passed > (curl_off_t)sizeof(scratch)) ?
774 sizeof(scratch) :
775 curlx_sotouz(offset - passed);
776 size_t actuallyread;
777
778 Curl_set_in_callback(data, TRUE);
779 actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
780 ctx->cb_user_data);
781 Curl_set_in_callback(data, FALSE);
782
783 passed += actuallyread;
784 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
785 /* this checks for greater-than only to make sure that the
786 CURL_READFUNC_ABORT return code still aborts */
787 failf(data, "Could only read %" FMT_OFF_T " bytes from the input",
788 passed);
789 return CURLE_READ_ERROR;
790 }
791 } while(passed < offset);
792 }
793
794 /* now, decrease the size of the read */
795 if(ctx->total_len > 0) {
796 ctx->total_len -= offset;
797
798 if(ctx->total_len <= 0) {
799 failf(data, "File already completely uploaded");
800 return CURLE_PARTIAL_FILE;
801 }
802 }
803 /* we have passed, proceed as normal */
804 return CURLE_OK;
805 }
806
cr_in_rewind(struct Curl_easy * data,struct Curl_creader * reader)807 static CURLcode cr_in_rewind(struct Curl_easy *data,
808 struct Curl_creader *reader)
809 {
810 struct cr_in_ctx *ctx = reader->ctx;
811
812 /* If we never invoked the callback, there is noting to rewind */
813 if(!ctx->has_used_cb)
814 return CURLE_OK;
815
816 if(data->set.seek_func) {
817 int err;
818
819 Curl_set_in_callback(data, TRUE);
820 err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
821 Curl_set_in_callback(data, FALSE);
822 CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
823 if(err) {
824 failf(data, "seek callback returned error %d", (int)err);
825 return CURLE_SEND_FAIL_REWIND;
826 }
827 }
828 else if(data->set.ioctl_func) {
829 curlioerr err;
830
831 Curl_set_in_callback(data, TRUE);
832 err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
833 data->set.ioctl_client);
834 Curl_set_in_callback(data, FALSE);
835 CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
836 if(err) {
837 failf(data, "ioctl callback returned error %d", (int)err);
838 return CURLE_SEND_FAIL_REWIND;
839 }
840 }
841 else {
842 /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
843 given FILE * stream and we can actually attempt to rewind that
844 ourselves with fseek() */
845 if(data->state.fread_func == (curl_read_callback)fread) {
846 int err = fseek(data->state.in, 0, SEEK_SET);
847 CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)",
848 (int)err, (int)errno);
849 if(-1 != err)
850 /* successful rewind */
851 return CURLE_OK;
852 }
853
854 /* no callback set or failure above, makes us fail at once */
855 failf(data, "necessary data rewind was not possible");
856 return CURLE_SEND_FAIL_REWIND;
857 }
858 return CURLE_OK;
859 }
860
cr_in_unpause(struct Curl_easy * data,struct Curl_creader * reader)861 static CURLcode cr_in_unpause(struct Curl_easy *data,
862 struct Curl_creader *reader)
863 {
864 struct cr_in_ctx *ctx = reader->ctx;
865 (void)data;
866 ctx->is_paused = FALSE;
867 return CURLE_OK;
868 }
869
cr_in_is_paused(struct Curl_easy * data,struct Curl_creader * reader)870 static bool cr_in_is_paused(struct Curl_easy *data,
871 struct Curl_creader *reader)
872 {
873 struct cr_in_ctx *ctx = reader->ctx;
874 (void)data;
875 return ctx->is_paused;
876 }
877
878 static const struct Curl_crtype cr_in = {
879 "cr-in",
880 cr_in_init,
881 cr_in_read,
882 Curl_creader_def_close,
883 cr_in_needs_rewind,
884 cr_in_total_length,
885 cr_in_resume_from,
886 cr_in_rewind,
887 cr_in_unpause,
888 cr_in_is_paused,
889 Curl_creader_def_done,
890 sizeof(struct cr_in_ctx)
891 };
892
Curl_creader_create(struct Curl_creader ** preader,struct Curl_easy * data,const struct Curl_crtype * crt,Curl_creader_phase phase)893 CURLcode Curl_creader_create(struct Curl_creader **preader,
894 struct Curl_easy *data,
895 const struct Curl_crtype *crt,
896 Curl_creader_phase phase)
897 {
898 struct Curl_creader *reader = NULL;
899 CURLcode result = CURLE_OUT_OF_MEMORY;
900 void *p;
901
902 DEBUGASSERT(crt->creader_size >= sizeof(struct Curl_creader));
903 p = calloc(1, crt->creader_size);
904 if(!p)
905 goto out;
906
907 reader = (struct Curl_creader *)p;
908 reader->crt = crt;
909 reader->ctx = p;
910 reader->phase = phase;
911 result = crt->do_init(data, reader);
912
913 out:
914 *preader = result ? NULL : reader;
915 if(result)
916 free(reader);
917 return result;
918 }
919
Curl_creader_free(struct Curl_easy * data,struct Curl_creader * reader)920 void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader)
921 {
922 if(reader) {
923 reader->crt->do_close(data, reader);
924 free(reader);
925 }
926 }
927
928 struct cr_lc_ctx {
929 struct Curl_creader super;
930 struct bufq buf;
931 BIT(read_eos); /* we read an EOS from the next reader */
932 BIT(eos); /* we have returned an EOS */
933 BIT(prev_cr); /* the last byte was a CR */
934 };
935
cr_lc_init(struct Curl_easy * data,struct Curl_creader * reader)936 static CURLcode cr_lc_init(struct Curl_easy *data, struct Curl_creader *reader)
937 {
938 struct cr_lc_ctx *ctx = reader->ctx;
939 (void)data;
940 Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
941 return CURLE_OK;
942 }
943
cr_lc_close(struct Curl_easy * data,struct Curl_creader * reader)944 static void cr_lc_close(struct Curl_easy *data, struct Curl_creader *reader)
945 {
946 struct cr_lc_ctx *ctx = reader->ctx;
947 (void)data;
948 Curl_bufq_free(&ctx->buf);
949 }
950
951 /* client reader doing line end conversions. */
cr_lc_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)952 static CURLcode cr_lc_read(struct Curl_easy *data,
953 struct Curl_creader *reader,
954 char *buf, size_t blen,
955 size_t *pnread, bool *peos)
956 {
957 struct cr_lc_ctx *ctx = reader->ctx;
958 CURLcode result;
959 size_t nread, i, start, n;
960 bool eos;
961
962 if(ctx->eos) {
963 *pnread = 0;
964 *peos = TRUE;
965 return CURLE_OK;
966 }
967
968 if(Curl_bufq_is_empty(&ctx->buf)) {
969 if(ctx->read_eos) {
970 ctx->eos = TRUE;
971 *pnread = 0;
972 *peos = TRUE;
973 return CURLE_OK;
974 }
975 /* Still getting data form the next reader, ctx->buf is empty */
976 result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
977 if(result)
978 return result;
979 ctx->read_eos = eos;
980
981 if(!nread || !memchr(buf, '\n', nread)) {
982 /* nothing to convert, return this right away */
983 if(ctx->read_eos)
984 ctx->eos = TRUE;
985 *pnread = nread;
986 *peos = ctx->eos;
987 goto out;
988 }
989
990 /* at least one \n might need conversion to '\r\n', place into ctx->buf */
991 for(i = start = 0; i < nread; ++i) {
992 /* if this byte is not an LF character, or if the preceding character is
993 a CR (meaning this already is a CRLF pair), go to next */
994 if((buf[i] != '\n') || ctx->prev_cr) {
995 ctx->prev_cr = (buf[i] == '\r');
996 continue;
997 }
998 ctx->prev_cr = FALSE;
999 /* on a soft limit bufq, we do not need to check length */
1000 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1001 if(!result)
1002 result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
1003 if(result)
1004 return result;
1005 start = i + 1;
1006 if(!data->set.crlf && (data->state.infilesize != -1)) {
1007 /* we are here only because FTP is in ASCII mode...
1008 bump infilesize for the LF we just added */
1009 data->state.infilesize++;
1010 /* comment: this might work for FTP, but in HTTP we could not change
1011 * the content length after having started the request... */
1012 }
1013 }
1014
1015 if(start < i) { /* leftover */
1016 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1017 if(result)
1018 return result;
1019 }
1020 }
1021
1022 DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
1023 *peos = FALSE;
1024 result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
1025 if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
1026 /* no more data, read all, done. */
1027 ctx->eos = TRUE;
1028 *peos = TRUE;
1029 }
1030
1031 out:
1032 CURL_TRC_READ(data, "cr_lc_read(len=%zu) -> %d, nread=%zu, eos=%d",
1033 blen, result, *pnread, *peos);
1034 return result;
1035 }
1036
cr_lc_total_length(struct Curl_easy * data,struct Curl_creader * reader)1037 static curl_off_t cr_lc_total_length(struct Curl_easy *data,
1038 struct Curl_creader *reader)
1039 {
1040 /* this reader changes length depending on input */
1041 (void)data;
1042 (void)reader;
1043 return -1;
1044 }
1045
1046 static const struct Curl_crtype cr_lc = {
1047 "cr-lineconv",
1048 cr_lc_init,
1049 cr_lc_read,
1050 cr_lc_close,
1051 Curl_creader_def_needs_rewind,
1052 cr_lc_total_length,
1053 Curl_creader_def_resume_from,
1054 Curl_creader_def_rewind,
1055 Curl_creader_def_unpause,
1056 Curl_creader_def_is_paused,
1057 Curl_creader_def_done,
1058 sizeof(struct cr_lc_ctx)
1059 };
1060
cr_lc_add(struct Curl_easy * data)1061 static CURLcode cr_lc_add(struct Curl_easy *data)
1062 {
1063 struct Curl_creader *reader = NULL;
1064 CURLcode result;
1065
1066 result = Curl_creader_create(&reader, data, &cr_lc,
1067 CURL_CR_CONTENT_ENCODE);
1068 if(!result)
1069 result = Curl_creader_add(data, reader);
1070
1071 if(result && reader)
1072 Curl_creader_free(data, reader);
1073 return result;
1074 }
1075
do_init_reader_stack(struct Curl_easy * data,struct Curl_creader * r)1076 static CURLcode do_init_reader_stack(struct Curl_easy *data,
1077 struct Curl_creader *r)
1078 {
1079 CURLcode result = CURLE_OK;
1080 curl_off_t clen;
1081
1082 DEBUGASSERT(r);
1083 DEBUGASSERT(r->crt);
1084 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1085 DEBUGASSERT(!data->req.reader_stack);
1086
1087 data->req.reader_stack = r;
1088 clen = r->crt->total_length(data, r);
1089 /* if we do not have 0 length init, and crlf conversion is wanted,
1090 * add the reader for it */
1091 if(clen && (data->set.crlf
1092 #ifdef CURL_PREFER_LF_LINEENDS
1093 || data->state.prefer_ascii
1094 #endif
1095 )) {
1096 result = cr_lc_add(data);
1097 if(result)
1098 return result;
1099 }
1100
1101 return result;
1102 }
1103
Curl_creader_set_fread(struct Curl_easy * data,curl_off_t len)1104 CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
1105 {
1106 CURLcode result;
1107 struct Curl_creader *r;
1108 struct cr_in_ctx *ctx;
1109
1110 result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
1111 if(result)
1112 goto out;
1113 ctx = r->ctx;
1114 ctx->total_len = len;
1115
1116 cl_reset_reader(data);
1117 result = do_init_reader_stack(data, r);
1118 out:
1119 CURL_TRC_READ(data, "add fread reader, len=%"FMT_OFF_T " -> %d",
1120 len, result);
1121 return result;
1122 }
1123
Curl_creader_add(struct Curl_easy * data,struct Curl_creader * reader)1124 CURLcode Curl_creader_add(struct Curl_easy *data,
1125 struct Curl_creader *reader)
1126 {
1127 CURLcode result;
1128 struct Curl_creader **anchor = &data->req.reader_stack;
1129
1130 if(!*anchor) {
1131 result = Curl_creader_set_fread(data, data->state.infilesize);
1132 if(result)
1133 return result;
1134 }
1135
1136 /* Insert the writer as first in its phase.
1137 * Skip existing readers of lower phases. */
1138 while(*anchor && (*anchor)->phase < reader->phase)
1139 anchor = &((*anchor)->next);
1140 reader->next = *anchor;
1141 *anchor = reader;
1142 return CURLE_OK;
1143 }
1144
Curl_creader_set(struct Curl_easy * data,struct Curl_creader * r)1145 CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
1146 {
1147 CURLcode result;
1148
1149 DEBUGASSERT(r);
1150 DEBUGASSERT(r->crt);
1151 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1152
1153 cl_reset_reader(data);
1154 result = do_init_reader_stack(data, r);
1155 if(result)
1156 Curl_creader_free(data, r);
1157 return result;
1158 }
1159
Curl_client_read(struct Curl_easy * data,char * buf,size_t blen,size_t * nread,bool * eos)1160 CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
1161 size_t *nread, bool *eos)
1162 {
1163 CURLcode result;
1164
1165 DEBUGASSERT(buf);
1166 DEBUGASSERT(blen);
1167 DEBUGASSERT(nread);
1168 DEBUGASSERT(eos);
1169
1170 if(!data->req.reader_stack) {
1171 result = Curl_creader_set_fread(data, data->state.infilesize);
1172 if(result)
1173 return result;
1174 DEBUGASSERT(data->req.reader_stack);
1175 }
1176
1177 result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
1178 nread, eos);
1179 CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",
1180 blen, result, *nread, *eos);
1181 return result;
1182 }
1183
Curl_creader_needs_rewind(struct Curl_easy * data)1184 bool Curl_creader_needs_rewind(struct Curl_easy *data)
1185 {
1186 struct Curl_creader *reader = data->req.reader_stack;
1187 while(reader) {
1188 if(reader->crt->needs_rewind(data, reader)) {
1189 CURL_TRC_READ(data, "client reader needs rewind before next request");
1190 return TRUE;
1191 }
1192 reader = reader->next;
1193 }
1194 return FALSE;
1195 }
1196
cr_null_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)1197 static CURLcode cr_null_read(struct Curl_easy *data,
1198 struct Curl_creader *reader,
1199 char *buf, size_t blen,
1200 size_t *pnread, bool *peos)
1201 {
1202 (void)data;
1203 (void)reader;
1204 (void)buf;
1205 (void)blen;
1206 *pnread = 0;
1207 *peos = TRUE;
1208 return CURLE_OK;
1209 }
1210
cr_null_total_length(struct Curl_easy * data,struct Curl_creader * reader)1211 static curl_off_t cr_null_total_length(struct Curl_easy *data,
1212 struct Curl_creader *reader)
1213 {
1214 /* this reader changes length depending on input */
1215 (void)data;
1216 (void)reader;
1217 return 0;
1218 }
1219
1220 static const struct Curl_crtype cr_null = {
1221 "cr-null",
1222 Curl_creader_def_init,
1223 cr_null_read,
1224 Curl_creader_def_close,
1225 Curl_creader_def_needs_rewind,
1226 cr_null_total_length,
1227 Curl_creader_def_resume_from,
1228 Curl_creader_def_rewind,
1229 Curl_creader_def_unpause,
1230 Curl_creader_def_is_paused,
1231 Curl_creader_def_done,
1232 sizeof(struct Curl_creader)
1233 };
1234
Curl_creader_set_null(struct Curl_easy * data)1235 CURLcode Curl_creader_set_null(struct Curl_easy *data)
1236 {
1237 struct Curl_creader *r;
1238 CURLcode result;
1239
1240 result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
1241 if(result)
1242 return result;
1243
1244 cl_reset_reader(data);
1245 return do_init_reader_stack(data, r);
1246 }
1247
1248 struct cr_buf_ctx {
1249 struct Curl_creader super;
1250 const char *buf;
1251 size_t blen;
1252 size_t index;
1253 };
1254
cr_buf_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)1255 static CURLcode cr_buf_read(struct Curl_easy *data,
1256 struct Curl_creader *reader,
1257 char *buf, size_t blen,
1258 size_t *pnread, bool *peos)
1259 {
1260 struct cr_buf_ctx *ctx = reader->ctx;
1261 size_t nread = ctx->blen - ctx->index;
1262
1263 (void)data;
1264 if(!nread || !ctx->buf) {
1265 *pnread = 0;
1266 *peos = TRUE;
1267 }
1268 else {
1269 if(nread > blen)
1270 nread = blen;
1271 memcpy(buf, ctx->buf + ctx->index, nread);
1272 *pnread = nread;
1273 ctx->index += nread;
1274 *peos = (ctx->index == ctx->blen);
1275 }
1276 CURL_TRC_READ(data, "cr_buf_read(len=%zu) -> 0, nread=%zu, eos=%d",
1277 blen, *pnread, *peos);
1278 return CURLE_OK;
1279 }
1280
cr_buf_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)1281 static bool cr_buf_needs_rewind(struct Curl_easy *data,
1282 struct Curl_creader *reader)
1283 {
1284 struct cr_buf_ctx *ctx = reader->ctx;
1285 (void)data;
1286 return ctx->index > 0;
1287 }
1288
cr_buf_total_length(struct Curl_easy * data,struct Curl_creader * reader)1289 static curl_off_t cr_buf_total_length(struct Curl_easy *data,
1290 struct Curl_creader *reader)
1291 {
1292 struct cr_buf_ctx *ctx = reader->ctx;
1293 (void)data;
1294 return (curl_off_t)ctx->blen;
1295 }
1296
cr_buf_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)1297 static CURLcode cr_buf_resume_from(struct Curl_easy *data,
1298 struct Curl_creader *reader,
1299 curl_off_t offset)
1300 {
1301 struct cr_buf_ctx *ctx = reader->ctx;
1302 size_t boffset;
1303
1304 (void)data;
1305 DEBUGASSERT(data->conn);
1306 /* already started reading? */
1307 if(ctx->index)
1308 return CURLE_READ_ERROR;
1309 if(offset <= 0)
1310 return CURLE_OK;
1311 boffset = (size_t)offset;
1312 if(boffset > ctx->blen)
1313 return CURLE_READ_ERROR;
1314
1315 ctx->buf += boffset;
1316 ctx->blen -= boffset;
1317 return CURLE_OK;
1318 }
1319
1320 static const struct Curl_crtype cr_buf = {
1321 "cr-buf",
1322 Curl_creader_def_init,
1323 cr_buf_read,
1324 Curl_creader_def_close,
1325 cr_buf_needs_rewind,
1326 cr_buf_total_length,
1327 cr_buf_resume_from,
1328 Curl_creader_def_rewind,
1329 Curl_creader_def_unpause,
1330 Curl_creader_def_is_paused,
1331 Curl_creader_def_done,
1332 sizeof(struct cr_buf_ctx)
1333 };
1334
Curl_creader_set_buf(struct Curl_easy * data,const char * buf,size_t blen)1335 CURLcode Curl_creader_set_buf(struct Curl_easy *data,
1336 const char *buf, size_t blen)
1337 {
1338 CURLcode result;
1339 struct Curl_creader *r;
1340 struct cr_buf_ctx *ctx;
1341
1342 result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
1343 if(result)
1344 goto out;
1345 ctx = r->ctx;
1346 ctx->buf = buf;
1347 ctx->blen = blen;
1348 ctx->index = 0;
1349
1350 cl_reset_reader(data);
1351 result = do_init_reader_stack(data, r);
1352 out:
1353 CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
1354 return result;
1355 }
1356
Curl_creader_total_length(struct Curl_easy * data)1357 curl_off_t Curl_creader_total_length(struct Curl_easy *data)
1358 {
1359 struct Curl_creader *r = data->req.reader_stack;
1360 return r ? r->crt->total_length(data, r) : -1;
1361 }
1362
Curl_creader_client_length(struct Curl_easy * data)1363 curl_off_t Curl_creader_client_length(struct Curl_easy *data)
1364 {
1365 struct Curl_creader *r = data->req.reader_stack;
1366 while(r && r->phase != CURL_CR_CLIENT)
1367 r = r->next;
1368 return r ? r->crt->total_length(data, r) : -1;
1369 }
1370
Curl_creader_resume_from(struct Curl_easy * data,curl_off_t offset)1371 CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
1372 {
1373 struct Curl_creader *r = data->req.reader_stack;
1374 while(r && r->phase != CURL_CR_CLIENT)
1375 r = r->next;
1376 return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
1377 }
1378
Curl_creader_unpause(struct Curl_easy * data)1379 CURLcode Curl_creader_unpause(struct Curl_easy *data)
1380 {
1381 struct Curl_creader *reader = data->req.reader_stack;
1382 CURLcode result = CURLE_OK;
1383
1384 while(reader) {
1385 result = reader->crt->unpause(data, reader);
1386 if(result)
1387 break;
1388 reader = reader->next;
1389 }
1390 return result;
1391 }
1392
Curl_creader_is_paused(struct Curl_easy * data)1393 bool Curl_creader_is_paused(struct Curl_easy *data)
1394 {
1395 struct Curl_creader *reader = data->req.reader_stack;
1396
1397 while(reader) {
1398 if(reader->crt->is_paused(data, reader))
1399 return TRUE;
1400 reader = reader->next;
1401 }
1402 return FALSE;
1403 }
1404
Curl_creader_done(struct Curl_easy * data,int premature)1405 void Curl_creader_done(struct Curl_easy *data, int premature)
1406 {
1407 struct Curl_creader *reader = data->req.reader_stack;
1408 while(reader) {
1409 reader->crt->done(data, reader, premature);
1410 reader = reader->next;
1411 }
1412 }
1413
Curl_creader_get_by_type(struct Curl_easy * data,const struct Curl_crtype * crt)1414 struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
1415 const struct Curl_crtype *crt)
1416 {
1417 struct Curl_creader *r;
1418 for(r = data->req.reader_stack; r; r = r->next) {
1419 if(r->crt == crt)
1420 return r;
1421 }
1422 return NULL;
1423
1424 }
1425