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 #ifdef USE_HYPER
320 data->req.bodywritten = TRUE;
321 #endif
322 result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
323 if(result)
324 return result;
325
326 if(excess_len) {
327 if(!data->req.ignorebody) {
328 infof(data,
329 "Excess found writing body:"
330 " excess = %zu"
331 ", size = %" FMT_OFF_T
332 ", maxdownload = %" FMT_OFF_T
333 ", bytecount = %" FMT_OFF_T,
334 excess_len, data->req.size, data->req.maxdownload,
335 data->req.bytecount);
336 connclose(data->conn, "excess found in a read");
337 }
338 }
339 else if((nwrite < nbytes) && !data->req.ignorebody) {
340 failf(data, "Exceeded the maximum allowed file size "
341 "(%" FMT_OFF_T ") with %" FMT_OFF_T " bytes",
342 data->set.max_filesize, data->req.bytecount);
343 return CURLE_FILESIZE_EXCEEDED;
344 }
345
346 return CURLE_OK;
347 }
348
349 static const struct Curl_cwtype cw_download = {
350 "protocol",
351 NULL,
352 Curl_cwriter_def_init,
353 cw_download_write,
354 Curl_cwriter_def_close,
355 sizeof(struct cw_download_ctx)
356 };
357
358 /* RAW client writer in phase CURL_CW_RAW that
359 * enabled tracing of raw data. */
cw_raw_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t nbytes)360 static CURLcode cw_raw_write(struct Curl_easy *data,
361 struct Curl_cwriter *writer, int type,
362 const char *buf, size_t nbytes)
363 {
364 if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
365 Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
366 }
367 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
368 }
369
370 static const struct Curl_cwtype cw_raw = {
371 "raw",
372 NULL,
373 Curl_cwriter_def_init,
374 cw_raw_write,
375 Curl_cwriter_def_close,
376 sizeof(struct Curl_cwriter)
377 };
378
379 /* 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)380 CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
381 struct Curl_easy *data,
382 const struct Curl_cwtype *cwt,
383 Curl_cwriter_phase phase)
384 {
385 struct Curl_cwriter *writer = NULL;
386 CURLcode result = CURLE_OUT_OF_MEMORY;
387 void *p;
388
389 DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
390 p = calloc(1, cwt->cwriter_size);
391 if(!p)
392 goto out;
393
394 writer = (struct Curl_cwriter *)p;
395 writer->cwt = cwt;
396 writer->ctx = p;
397 writer->phase = phase;
398 result = cwt->do_init(data, writer);
399
400 out:
401 *pwriter = result ? NULL : writer;
402 if(result)
403 free(writer);
404 return result;
405 }
406
Curl_cwriter_free(struct Curl_easy * data,struct Curl_cwriter * writer)407 void Curl_cwriter_free(struct Curl_easy *data,
408 struct Curl_cwriter *writer)
409 {
410 if(writer) {
411 writer->cwt->do_close(data, writer);
412 free(writer);
413 }
414 }
415
Curl_cwriter_count(struct Curl_easy * data,Curl_cwriter_phase phase)416 size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
417 {
418 struct Curl_cwriter *w;
419 size_t n = 0;
420
421 for(w = data->req.writer_stack; w; w = w->next) {
422 if(w->phase == phase)
423 ++n;
424 }
425 return n;
426 }
427
do_init_writer_stack(struct Curl_easy * data)428 static CURLcode do_init_writer_stack(struct Curl_easy *data)
429 {
430 struct Curl_cwriter *writer;
431 CURLcode result;
432
433 DEBUGASSERT(!data->req.writer_stack);
434 result = Curl_cwriter_create(&data->req.writer_stack,
435 data, &Curl_cwt_out, CURL_CW_CLIENT);
436 if(result)
437 return result;
438
439 result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
440 if(result)
441 return result;
442 result = Curl_cwriter_add(data, writer);
443 if(result) {
444 Curl_cwriter_free(data, writer);
445 }
446
447 result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
448 if(result)
449 return result;
450 result = Curl_cwriter_add(data, writer);
451 if(result) {
452 Curl_cwriter_free(data, writer);
453 }
454 return result;
455 }
456
Curl_cwriter_add(struct Curl_easy * data,struct Curl_cwriter * writer)457 CURLcode Curl_cwriter_add(struct Curl_easy *data,
458 struct Curl_cwriter *writer)
459 {
460 CURLcode result;
461 struct Curl_cwriter **anchor = &data->req.writer_stack;
462
463 if(!*anchor) {
464 result = do_init_writer_stack(data);
465 if(result)
466 return result;
467 }
468
469 /* Insert the writer as first in its phase.
470 * Skip existing writers of lower phases. */
471 while(*anchor && (*anchor)->phase < writer->phase)
472 anchor = &((*anchor)->next);
473 writer->next = *anchor;
474 *anchor = writer;
475 return CURLE_OK;
476 }
477
Curl_cwriter_get_by_name(struct Curl_easy * data,const char * name)478 struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
479 const char *name)
480 {
481 struct Curl_cwriter *writer;
482 for(writer = data->req.writer_stack; writer; writer = writer->next) {
483 if(!strcmp(name, writer->cwt->name))
484 return writer;
485 }
486 return NULL;
487 }
488
Curl_cwriter_get_by_type(struct Curl_easy * data,const struct Curl_cwtype * cwt)489 struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
490 const struct Curl_cwtype *cwt)
491 {
492 struct Curl_cwriter *writer;
493 for(writer = data->req.writer_stack; writer; writer = writer->next) {
494 if(writer->cwt == cwt)
495 return writer;
496 }
497 return NULL;
498 }
499
Curl_cwriter_remove_by_name(struct Curl_easy * data,const char * name)500 void Curl_cwriter_remove_by_name(struct Curl_easy *data,
501 const char *name)
502 {
503 struct Curl_cwriter **anchor = &data->req.writer_stack;
504
505 while(*anchor) {
506 if(!strcmp(name, (*anchor)->cwt->name)) {
507 struct Curl_cwriter *w = (*anchor);
508 *anchor = w->next;
509 Curl_cwriter_free(data, w);
510 continue;
511 }
512 anchor = &((*anchor)->next);
513 }
514 }
515
Curl_cwriter_is_paused(struct Curl_easy * data)516 bool Curl_cwriter_is_paused(struct Curl_easy *data)
517 {
518 return Curl_cw_out_is_paused(data);
519 }
520
Curl_cwriter_unpause(struct Curl_easy * data)521 CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
522 {
523 return Curl_cw_out_unpause(data);
524 }
525
Curl_creader_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)526 CURLcode Curl_creader_read(struct Curl_easy *data,
527 struct Curl_creader *reader,
528 char *buf, size_t blen, size_t *nread, bool *eos)
529 {
530 *nread = 0;
531 *eos = FALSE;
532 if(!reader)
533 return CURLE_READ_ERROR;
534 return reader->crt->do_read(data, reader, buf, blen, nread, eos);
535 }
536
Curl_creader_def_init(struct Curl_easy * data,struct Curl_creader * reader)537 CURLcode Curl_creader_def_init(struct Curl_easy *data,
538 struct Curl_creader *reader)
539 {
540 (void)data;
541 (void)reader;
542 return CURLE_OK;
543 }
544
Curl_creader_def_close(struct Curl_easy * data,struct Curl_creader * reader)545 void Curl_creader_def_close(struct Curl_easy *data,
546 struct Curl_creader *reader)
547 {
548 (void)data;
549 (void)reader;
550 }
551
Curl_creader_def_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)552 CURLcode Curl_creader_def_read(struct Curl_easy *data,
553 struct Curl_creader *reader,
554 char *buf, size_t blen,
555 size_t *nread, bool *eos)
556 {
557 if(reader->next)
558 return reader->next->crt->do_read(data, reader->next, buf, blen,
559 nread, eos);
560 else {
561 *nread = 0;
562 *eos = FALSE;
563 return CURLE_READ_ERROR;
564 }
565 }
566
Curl_creader_def_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)567 bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
568 struct Curl_creader *reader)
569 {
570 (void)data;
571 (void)reader;
572 return FALSE;
573 }
574
Curl_creader_def_total_length(struct Curl_easy * data,struct Curl_creader * reader)575 curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
576 struct Curl_creader *reader)
577 {
578 return reader->next ?
579 reader->next->crt->total_length(data, reader->next) : -1;
580 }
581
Curl_creader_def_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)582 CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
583 struct Curl_creader *reader,
584 curl_off_t offset)
585 {
586 (void)data;
587 (void)reader;
588 (void)offset;
589 return CURLE_READ_ERROR;
590 }
591
Curl_creader_def_rewind(struct Curl_easy * data,struct Curl_creader * reader)592 CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
593 struct Curl_creader *reader)
594 {
595 (void)data;
596 (void)reader;
597 return CURLE_OK;
598 }
599
Curl_creader_def_unpause(struct Curl_easy * data,struct Curl_creader * reader)600 CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
601 struct Curl_creader *reader)
602 {
603 (void)data;
604 (void)reader;
605 return CURLE_OK;
606 }
607
Curl_creader_def_is_paused(struct Curl_easy * data,struct Curl_creader * reader)608 bool Curl_creader_def_is_paused(struct Curl_easy *data,
609 struct Curl_creader *reader)
610 {
611 (void)data;
612 (void)reader;
613 return FALSE;
614 }
615
Curl_creader_def_done(struct Curl_easy * data,struct Curl_creader * reader,int premature)616 void Curl_creader_def_done(struct Curl_easy *data,
617 struct Curl_creader *reader, int premature)
618 {
619 (void)data;
620 (void)reader;
621 (void)premature;
622 }
623
624 struct cr_in_ctx {
625 struct Curl_creader super;
626 curl_read_callback read_cb;
627 void *cb_user_data;
628 curl_off_t total_len;
629 curl_off_t read_len;
630 CURLcode error_result;
631 BIT(seen_eos);
632 BIT(errored);
633 BIT(has_used_cb);
634 BIT(is_paused);
635 };
636
cr_in_init(struct Curl_easy * data,struct Curl_creader * reader)637 static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
638 {
639 struct cr_in_ctx *ctx = reader->ctx;
640 (void)data;
641 ctx->read_cb = data->state.fread_func;
642 ctx->cb_user_data = data->state.in;
643 ctx->total_len = -1;
644 ctx->read_len = 0;
645 return CURLE_OK;
646 }
647
648 /* 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)649 static CURLcode cr_in_read(struct Curl_easy *data,
650 struct Curl_creader *reader,
651 char *buf, size_t blen,
652 size_t *pnread, bool *peos)
653 {
654 struct cr_in_ctx *ctx = reader->ctx;
655 size_t nread;
656
657 ctx->is_paused = FALSE;
658
659 /* Once we have errored, we will return the same error forever */
660 if(ctx->errored) {
661 *pnread = 0;
662 *peos = FALSE;
663 return ctx->error_result;
664 }
665 if(ctx->seen_eos) {
666 *pnread = 0;
667 *peos = TRUE;
668 return CURLE_OK;
669 }
670 /* respect length limitations */
671 if(ctx->total_len >= 0) {
672 curl_off_t remain = ctx->total_len - ctx->read_len;
673 if(remain <= 0)
674 blen = 0;
675 else if(remain < (curl_off_t)blen)
676 blen = (size_t)remain;
677 }
678 nread = 0;
679 if(ctx->read_cb && blen) {
680 Curl_set_in_callback(data, TRUE);
681 nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
682 Curl_set_in_callback(data, FALSE);
683 ctx->has_used_cb = TRUE;
684 }
685
686 switch(nread) {
687 case 0:
688 if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
689 failf(data, "client read function EOF fail, "
690 "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read",
691 ctx->read_len, ctx->total_len);
692 return CURLE_READ_ERROR;
693 }
694 *pnread = 0;
695 *peos = TRUE;
696 ctx->seen_eos = TRUE;
697 break;
698
699 case CURL_READFUNC_ABORT:
700 failf(data, "operation aborted by callback");
701 *pnread = 0;
702 *peos = FALSE;
703 ctx->errored = TRUE;
704 ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
705 return CURLE_ABORTED_BY_CALLBACK;
706
707 case CURL_READFUNC_PAUSE:
708 if(data->conn->handler->flags & PROTOPT_NONETWORK) {
709 /* protocols that work without network cannot be paused. This is
710 actually only FILE:// just now, and it cannot pause since the transfer
711 is not done using the "normal" procedure. */
712 failf(data, "Read callback asked for PAUSE when not supported");
713 return CURLE_READ_ERROR;
714 }
715 /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
716 CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
717 ctx->is_paused = TRUE;
718 data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
719 *pnread = 0;
720 *peos = FALSE;
721 break; /* nothing was read */
722
723 default:
724 if(nread > blen) {
725 /* the read function returned a too large value */
726 failf(data, "read function returned funny value");
727 *pnread = 0;
728 *peos = FALSE;
729 ctx->errored = TRUE;
730 ctx->error_result = CURLE_READ_ERROR;
731 return CURLE_READ_ERROR;
732 }
733 ctx->read_len += nread;
734 if(ctx->total_len >= 0)
735 ctx->seen_eos = (ctx->read_len >= ctx->total_len);
736 *pnread = nread;
737 *peos = ctx->seen_eos;
738 break;
739 }
740 CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T
741 ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d",
742 blen, ctx->total_len, ctx->read_len, CURLE_OK,
743 *pnread, *peos);
744 return CURLE_OK;
745 }
746
cr_in_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)747 static bool cr_in_needs_rewind(struct Curl_easy *data,
748 struct Curl_creader *reader)
749 {
750 struct cr_in_ctx *ctx = reader->ctx;
751 (void)data;
752 return ctx->has_used_cb;
753 }
754
cr_in_total_length(struct Curl_easy * data,struct Curl_creader * reader)755 static curl_off_t cr_in_total_length(struct Curl_easy *data,
756 struct Curl_creader *reader)
757 {
758 struct cr_in_ctx *ctx = reader->ctx;
759 (void)data;
760 return ctx->total_len;
761 }
762
cr_in_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)763 static CURLcode cr_in_resume_from(struct Curl_easy *data,
764 struct Curl_creader *reader,
765 curl_off_t offset)
766 {
767 struct cr_in_ctx *ctx = reader->ctx;
768 int seekerr = CURL_SEEKFUNC_CANTSEEK;
769
770 DEBUGASSERT(data->conn);
771 /* already started reading? */
772 if(ctx->read_len)
773 return CURLE_READ_ERROR;
774
775 if(data->set.seek_func) {
776 Curl_set_in_callback(data, TRUE);
777 seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
778 Curl_set_in_callback(data, FALSE);
779 }
780
781 if(seekerr != CURL_SEEKFUNC_OK) {
782 curl_off_t passed = 0;
783
784 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
785 failf(data, "Could not seek stream");
786 return CURLE_READ_ERROR;
787 }
788 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
789 do {
790 char scratch[4*1024];
791 size_t readthisamountnow =
792 (offset - passed > (curl_off_t)sizeof(scratch)) ?
793 sizeof(scratch) :
794 curlx_sotouz(offset - passed);
795 size_t actuallyread;
796
797 Curl_set_in_callback(data, TRUE);
798 actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
799 ctx->cb_user_data);
800 Curl_set_in_callback(data, FALSE);
801
802 passed += actuallyread;
803 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
804 /* this checks for greater-than only to make sure that the
805 CURL_READFUNC_ABORT return code still aborts */
806 failf(data, "Could only read %" FMT_OFF_T " bytes from the input",
807 passed);
808 return CURLE_READ_ERROR;
809 }
810 } while(passed < offset);
811 }
812
813 /* now, decrease the size of the read */
814 if(ctx->total_len > 0) {
815 ctx->total_len -= offset;
816
817 if(ctx->total_len <= 0) {
818 failf(data, "File already completely uploaded");
819 return CURLE_PARTIAL_FILE;
820 }
821 }
822 /* we have passed, proceed as normal */
823 return CURLE_OK;
824 }
825
cr_in_rewind(struct Curl_easy * data,struct Curl_creader * reader)826 static CURLcode cr_in_rewind(struct Curl_easy *data,
827 struct Curl_creader *reader)
828 {
829 struct cr_in_ctx *ctx = reader->ctx;
830
831 /* If we never invoked the callback, there is noting to rewind */
832 if(!ctx->has_used_cb)
833 return CURLE_OK;
834
835 if(data->set.seek_func) {
836 int err;
837
838 Curl_set_in_callback(data, TRUE);
839 err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
840 Curl_set_in_callback(data, FALSE);
841 CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
842 if(err) {
843 failf(data, "seek callback returned error %d", (int)err);
844 return CURLE_SEND_FAIL_REWIND;
845 }
846 }
847 else if(data->set.ioctl_func) {
848 curlioerr err;
849
850 Curl_set_in_callback(data, TRUE);
851 err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
852 data->set.ioctl_client);
853 Curl_set_in_callback(data, FALSE);
854 CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
855 if(err) {
856 failf(data, "ioctl callback returned error %d", (int)err);
857 return CURLE_SEND_FAIL_REWIND;
858 }
859 }
860 else {
861 /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
862 given FILE * stream and we can actually attempt to rewind that
863 ourselves with fseek() */
864 if(data->state.fread_func == (curl_read_callback)fread) {
865 int err = fseek(data->state.in, 0, SEEK_SET);
866 CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)",
867 (int)err, (int)errno);
868 if(-1 != err)
869 /* successful rewind */
870 return CURLE_OK;
871 }
872
873 /* no callback set or failure above, makes us fail at once */
874 failf(data, "necessary data rewind was not possible");
875 return CURLE_SEND_FAIL_REWIND;
876 }
877 return CURLE_OK;
878 }
879
cr_in_unpause(struct Curl_easy * data,struct Curl_creader * reader)880 static CURLcode cr_in_unpause(struct Curl_easy *data,
881 struct Curl_creader *reader)
882 {
883 struct cr_in_ctx *ctx = reader->ctx;
884 (void)data;
885 ctx->is_paused = FALSE;
886 return CURLE_OK;
887 }
888
cr_in_is_paused(struct Curl_easy * data,struct Curl_creader * reader)889 static bool cr_in_is_paused(struct Curl_easy *data,
890 struct Curl_creader *reader)
891 {
892 struct cr_in_ctx *ctx = reader->ctx;
893 (void)data;
894 return ctx->is_paused;
895 }
896
897 static const struct Curl_crtype cr_in = {
898 "cr-in",
899 cr_in_init,
900 cr_in_read,
901 Curl_creader_def_close,
902 cr_in_needs_rewind,
903 cr_in_total_length,
904 cr_in_resume_from,
905 cr_in_rewind,
906 cr_in_unpause,
907 cr_in_is_paused,
908 Curl_creader_def_done,
909 sizeof(struct cr_in_ctx)
910 };
911
Curl_creader_create(struct Curl_creader ** preader,struct Curl_easy * data,const struct Curl_crtype * crt,Curl_creader_phase phase)912 CURLcode Curl_creader_create(struct Curl_creader **preader,
913 struct Curl_easy *data,
914 const struct Curl_crtype *crt,
915 Curl_creader_phase phase)
916 {
917 struct Curl_creader *reader = NULL;
918 CURLcode result = CURLE_OUT_OF_MEMORY;
919 void *p;
920
921 DEBUGASSERT(crt->creader_size >= sizeof(struct Curl_creader));
922 p = calloc(1, crt->creader_size);
923 if(!p)
924 goto out;
925
926 reader = (struct Curl_creader *)p;
927 reader->crt = crt;
928 reader->ctx = p;
929 reader->phase = phase;
930 result = crt->do_init(data, reader);
931
932 out:
933 *preader = result ? NULL : reader;
934 if(result)
935 free(reader);
936 return result;
937 }
938
Curl_creader_free(struct Curl_easy * data,struct Curl_creader * reader)939 void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader)
940 {
941 if(reader) {
942 reader->crt->do_close(data, reader);
943 free(reader);
944 }
945 }
946
947 struct cr_lc_ctx {
948 struct Curl_creader super;
949 struct bufq buf;
950 BIT(read_eos); /* we read an EOS from the next reader */
951 BIT(eos); /* we have returned an EOS */
952 BIT(prev_cr); /* the last byte was a CR */
953 };
954
cr_lc_init(struct Curl_easy * data,struct Curl_creader * reader)955 static CURLcode cr_lc_init(struct Curl_easy *data, struct Curl_creader *reader)
956 {
957 struct cr_lc_ctx *ctx = reader->ctx;
958 (void)data;
959 Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
960 return CURLE_OK;
961 }
962
cr_lc_close(struct Curl_easy * data,struct Curl_creader * reader)963 static void cr_lc_close(struct Curl_easy *data, struct Curl_creader *reader)
964 {
965 struct cr_lc_ctx *ctx = reader->ctx;
966 (void)data;
967 Curl_bufq_free(&ctx->buf);
968 }
969
970 /* 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)971 static CURLcode cr_lc_read(struct Curl_easy *data,
972 struct Curl_creader *reader,
973 char *buf, size_t blen,
974 size_t *pnread, bool *peos)
975 {
976 struct cr_lc_ctx *ctx = reader->ctx;
977 CURLcode result;
978 size_t nread, i, start, n;
979 bool eos;
980
981 if(ctx->eos) {
982 *pnread = 0;
983 *peos = TRUE;
984 return CURLE_OK;
985 }
986
987 if(Curl_bufq_is_empty(&ctx->buf)) {
988 if(ctx->read_eos) {
989 ctx->eos = TRUE;
990 *pnread = 0;
991 *peos = TRUE;
992 return CURLE_OK;
993 }
994 /* Still getting data form the next reader, ctx->buf is empty */
995 result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
996 if(result)
997 return result;
998 ctx->read_eos = eos;
999
1000 if(!nread || !memchr(buf, '\n', nread)) {
1001 /* nothing to convert, return this right away */
1002 if(ctx->read_eos)
1003 ctx->eos = TRUE;
1004 *pnread = nread;
1005 *peos = ctx->eos;
1006 goto out;
1007 }
1008
1009 /* at least one \n might need conversion to '\r\n', place into ctx->buf */
1010 for(i = start = 0; i < nread; ++i) {
1011 /* if this byte is not an LF character, or if the preceding character is
1012 a CR (meaning this already is a CRLF pair), go to next */
1013 if((buf[i] != '\n') || ctx->prev_cr) {
1014 ctx->prev_cr = (buf[i] == '\r');
1015 continue;
1016 }
1017 ctx->prev_cr = FALSE;
1018 /* on a soft limit bufq, we do not need to check length */
1019 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1020 if(!result)
1021 result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
1022 if(result)
1023 return result;
1024 start = i + 1;
1025 if(!data->set.crlf && (data->state.infilesize != -1)) {
1026 /* we are here only because FTP is in ASCII mode...
1027 bump infilesize for the LF we just added */
1028 data->state.infilesize++;
1029 /* comment: this might work for FTP, but in HTTP we could not change
1030 * the content length after having started the request... */
1031 }
1032 }
1033
1034 if(start < i) { /* leftover */
1035 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1036 if(result)
1037 return result;
1038 }
1039 }
1040
1041 DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
1042 *peos = FALSE;
1043 result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
1044 if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
1045 /* no more data, read all, done. */
1046 ctx->eos = TRUE;
1047 *peos = TRUE;
1048 }
1049
1050 out:
1051 CURL_TRC_READ(data, "cr_lc_read(len=%zu) -> %d, nread=%zu, eos=%d",
1052 blen, result, *pnread, *peos);
1053 return result;
1054 }
1055
cr_lc_total_length(struct Curl_easy * data,struct Curl_creader * reader)1056 static curl_off_t cr_lc_total_length(struct Curl_easy *data,
1057 struct Curl_creader *reader)
1058 {
1059 /* this reader changes length depending on input */
1060 (void)data;
1061 (void)reader;
1062 return -1;
1063 }
1064
1065 static const struct Curl_crtype cr_lc = {
1066 "cr-lineconv",
1067 cr_lc_init,
1068 cr_lc_read,
1069 cr_lc_close,
1070 Curl_creader_def_needs_rewind,
1071 cr_lc_total_length,
1072 Curl_creader_def_resume_from,
1073 Curl_creader_def_rewind,
1074 Curl_creader_def_unpause,
1075 Curl_creader_def_is_paused,
1076 Curl_creader_def_done,
1077 sizeof(struct cr_lc_ctx)
1078 };
1079
cr_lc_add(struct Curl_easy * data)1080 static CURLcode cr_lc_add(struct Curl_easy *data)
1081 {
1082 struct Curl_creader *reader = NULL;
1083 CURLcode result;
1084
1085 result = Curl_creader_create(&reader, data, &cr_lc,
1086 CURL_CR_CONTENT_ENCODE);
1087 if(!result)
1088 result = Curl_creader_add(data, reader);
1089
1090 if(result && reader)
1091 Curl_creader_free(data, reader);
1092 return result;
1093 }
1094
do_init_reader_stack(struct Curl_easy * data,struct Curl_creader * r)1095 static CURLcode do_init_reader_stack(struct Curl_easy *data,
1096 struct Curl_creader *r)
1097 {
1098 CURLcode result = CURLE_OK;
1099 curl_off_t clen;
1100
1101 DEBUGASSERT(r);
1102 DEBUGASSERT(r->crt);
1103 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1104 DEBUGASSERT(!data->req.reader_stack);
1105
1106 data->req.reader_stack = r;
1107 clen = r->crt->total_length(data, r);
1108 /* if we do not have 0 length init, and crlf conversion is wanted,
1109 * add the reader for it */
1110 if(clen && (data->set.crlf
1111 #ifdef CURL_PREFER_LF_LINEENDS
1112 || data->state.prefer_ascii
1113 #endif
1114 )) {
1115 result = cr_lc_add(data);
1116 if(result)
1117 return result;
1118 }
1119
1120 return result;
1121 }
1122
Curl_creader_set_fread(struct Curl_easy * data,curl_off_t len)1123 CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
1124 {
1125 CURLcode result;
1126 struct Curl_creader *r;
1127 struct cr_in_ctx *ctx;
1128
1129 result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
1130 if(result)
1131 goto out;
1132 ctx = r->ctx;
1133 ctx->total_len = len;
1134
1135 cl_reset_reader(data);
1136 result = do_init_reader_stack(data, r);
1137 out:
1138 CURL_TRC_READ(data, "add fread reader, len=%"FMT_OFF_T " -> %d",
1139 len, result);
1140 return result;
1141 }
1142
Curl_creader_add(struct Curl_easy * data,struct Curl_creader * reader)1143 CURLcode Curl_creader_add(struct Curl_easy *data,
1144 struct Curl_creader *reader)
1145 {
1146 CURLcode result;
1147 struct Curl_creader **anchor = &data->req.reader_stack;
1148
1149 if(!*anchor) {
1150 result = Curl_creader_set_fread(data, data->state.infilesize);
1151 if(result)
1152 return result;
1153 }
1154
1155 /* Insert the writer as first in its phase.
1156 * Skip existing readers of lower phases. */
1157 while(*anchor && (*anchor)->phase < reader->phase)
1158 anchor = &((*anchor)->next);
1159 reader->next = *anchor;
1160 *anchor = reader;
1161 return CURLE_OK;
1162 }
1163
Curl_creader_set(struct Curl_easy * data,struct Curl_creader * r)1164 CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
1165 {
1166 CURLcode result;
1167
1168 DEBUGASSERT(r);
1169 DEBUGASSERT(r->crt);
1170 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1171
1172 cl_reset_reader(data);
1173 result = do_init_reader_stack(data, r);
1174 if(result)
1175 Curl_creader_free(data, r);
1176 return result;
1177 }
1178
Curl_client_read(struct Curl_easy * data,char * buf,size_t blen,size_t * nread,bool * eos)1179 CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
1180 size_t *nread, bool *eos)
1181 {
1182 CURLcode result;
1183
1184 DEBUGASSERT(buf);
1185 DEBUGASSERT(blen);
1186 DEBUGASSERT(nread);
1187 DEBUGASSERT(eos);
1188
1189 if(!data->req.reader_stack) {
1190 result = Curl_creader_set_fread(data, data->state.infilesize);
1191 if(result)
1192 return result;
1193 DEBUGASSERT(data->req.reader_stack);
1194 }
1195
1196 result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
1197 nread, eos);
1198 CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",
1199 blen, result, *nread, *eos);
1200 return result;
1201 }
1202
Curl_creader_needs_rewind(struct Curl_easy * data)1203 bool Curl_creader_needs_rewind(struct Curl_easy *data)
1204 {
1205 struct Curl_creader *reader = data->req.reader_stack;
1206 while(reader) {
1207 if(reader->crt->needs_rewind(data, reader)) {
1208 CURL_TRC_READ(data, "client reader needs rewind before next request");
1209 return TRUE;
1210 }
1211 reader = reader->next;
1212 }
1213 return FALSE;
1214 }
1215
cr_null_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)1216 static CURLcode cr_null_read(struct Curl_easy *data,
1217 struct Curl_creader *reader,
1218 char *buf, size_t blen,
1219 size_t *pnread, bool *peos)
1220 {
1221 (void)data;
1222 (void)reader;
1223 (void)buf;
1224 (void)blen;
1225 *pnread = 0;
1226 *peos = TRUE;
1227 return CURLE_OK;
1228 }
1229
cr_null_total_length(struct Curl_easy * data,struct Curl_creader * reader)1230 static curl_off_t cr_null_total_length(struct Curl_easy *data,
1231 struct Curl_creader *reader)
1232 {
1233 /* this reader changes length depending on input */
1234 (void)data;
1235 (void)reader;
1236 return 0;
1237 }
1238
1239 static const struct Curl_crtype cr_null = {
1240 "cr-null",
1241 Curl_creader_def_init,
1242 cr_null_read,
1243 Curl_creader_def_close,
1244 Curl_creader_def_needs_rewind,
1245 cr_null_total_length,
1246 Curl_creader_def_resume_from,
1247 Curl_creader_def_rewind,
1248 Curl_creader_def_unpause,
1249 Curl_creader_def_is_paused,
1250 Curl_creader_def_done,
1251 sizeof(struct Curl_creader)
1252 };
1253
Curl_creader_set_null(struct Curl_easy * data)1254 CURLcode Curl_creader_set_null(struct Curl_easy *data)
1255 {
1256 struct Curl_creader *r;
1257 CURLcode result;
1258
1259 result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
1260 if(result)
1261 return result;
1262
1263 cl_reset_reader(data);
1264 return do_init_reader_stack(data, r);
1265 }
1266
1267 struct cr_buf_ctx {
1268 struct Curl_creader super;
1269 const char *buf;
1270 size_t blen;
1271 size_t index;
1272 };
1273
cr_buf_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)1274 static CURLcode cr_buf_read(struct Curl_easy *data,
1275 struct Curl_creader *reader,
1276 char *buf, size_t blen,
1277 size_t *pnread, bool *peos)
1278 {
1279 struct cr_buf_ctx *ctx = reader->ctx;
1280 size_t nread = ctx->blen - ctx->index;
1281
1282 (void)data;
1283 if(!nread || !ctx->buf) {
1284 *pnread = 0;
1285 *peos = TRUE;
1286 }
1287 else {
1288 if(nread > blen)
1289 nread = blen;
1290 memcpy(buf, ctx->buf + ctx->index, nread);
1291 *pnread = nread;
1292 ctx->index += nread;
1293 *peos = (ctx->index == ctx->blen);
1294 }
1295 CURL_TRC_READ(data, "cr_buf_read(len=%zu) -> 0, nread=%zu, eos=%d",
1296 blen, *pnread, *peos);
1297 return CURLE_OK;
1298 }
1299
cr_buf_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)1300 static bool cr_buf_needs_rewind(struct Curl_easy *data,
1301 struct Curl_creader *reader)
1302 {
1303 struct cr_buf_ctx *ctx = reader->ctx;
1304 (void)data;
1305 return ctx->index > 0;
1306 }
1307
cr_buf_total_length(struct Curl_easy * data,struct Curl_creader * reader)1308 static curl_off_t cr_buf_total_length(struct Curl_easy *data,
1309 struct Curl_creader *reader)
1310 {
1311 struct cr_buf_ctx *ctx = reader->ctx;
1312 (void)data;
1313 return (curl_off_t)ctx->blen;
1314 }
1315
cr_buf_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)1316 static CURLcode cr_buf_resume_from(struct Curl_easy *data,
1317 struct Curl_creader *reader,
1318 curl_off_t offset)
1319 {
1320 struct cr_buf_ctx *ctx = reader->ctx;
1321 size_t boffset;
1322
1323 (void)data;
1324 DEBUGASSERT(data->conn);
1325 /* already started reading? */
1326 if(ctx->index)
1327 return CURLE_READ_ERROR;
1328 if(offset <= 0)
1329 return CURLE_OK;
1330 boffset = (size_t)offset;
1331 if(boffset > ctx->blen)
1332 return CURLE_READ_ERROR;
1333
1334 ctx->buf += boffset;
1335 ctx->blen -= boffset;
1336 return CURLE_OK;
1337 }
1338
1339 static const struct Curl_crtype cr_buf = {
1340 "cr-buf",
1341 Curl_creader_def_init,
1342 cr_buf_read,
1343 Curl_creader_def_close,
1344 cr_buf_needs_rewind,
1345 cr_buf_total_length,
1346 cr_buf_resume_from,
1347 Curl_creader_def_rewind,
1348 Curl_creader_def_unpause,
1349 Curl_creader_def_is_paused,
1350 Curl_creader_def_done,
1351 sizeof(struct cr_buf_ctx)
1352 };
1353
Curl_creader_set_buf(struct Curl_easy * data,const char * buf,size_t blen)1354 CURLcode Curl_creader_set_buf(struct Curl_easy *data,
1355 const char *buf, size_t blen)
1356 {
1357 CURLcode result;
1358 struct Curl_creader *r;
1359 struct cr_buf_ctx *ctx;
1360
1361 result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
1362 if(result)
1363 goto out;
1364 ctx = r->ctx;
1365 ctx->buf = buf;
1366 ctx->blen = blen;
1367 ctx->index = 0;
1368
1369 cl_reset_reader(data);
1370 result = do_init_reader_stack(data, r);
1371 out:
1372 CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
1373 return result;
1374 }
1375
Curl_creader_total_length(struct Curl_easy * data)1376 curl_off_t Curl_creader_total_length(struct Curl_easy *data)
1377 {
1378 struct Curl_creader *r = data->req.reader_stack;
1379 return r ? r->crt->total_length(data, r) : -1;
1380 }
1381
Curl_creader_client_length(struct Curl_easy * data)1382 curl_off_t Curl_creader_client_length(struct Curl_easy *data)
1383 {
1384 struct Curl_creader *r = data->req.reader_stack;
1385 while(r && r->phase != CURL_CR_CLIENT)
1386 r = r->next;
1387 return r ? r->crt->total_length(data, r) : -1;
1388 }
1389
Curl_creader_resume_from(struct Curl_easy * data,curl_off_t offset)1390 CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
1391 {
1392 struct Curl_creader *r = data->req.reader_stack;
1393 while(r && r->phase != CURL_CR_CLIENT)
1394 r = r->next;
1395 return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
1396 }
1397
Curl_creader_unpause(struct Curl_easy * data)1398 CURLcode Curl_creader_unpause(struct Curl_easy *data)
1399 {
1400 struct Curl_creader *reader = data->req.reader_stack;
1401 CURLcode result = CURLE_OK;
1402
1403 while(reader) {
1404 result = reader->crt->unpause(data, reader);
1405 if(result)
1406 break;
1407 reader = reader->next;
1408 }
1409 return result;
1410 }
1411
Curl_creader_is_paused(struct Curl_easy * data)1412 bool Curl_creader_is_paused(struct Curl_easy *data)
1413 {
1414 struct Curl_creader *reader = data->req.reader_stack;
1415
1416 while(reader) {
1417 if(reader->crt->is_paused(data, reader))
1418 return TRUE;
1419 reader = reader->next;
1420 }
1421 return FALSE;
1422 }
1423
Curl_creader_done(struct Curl_easy * data,int premature)1424 void Curl_creader_done(struct Curl_easy *data, int premature)
1425 {
1426 struct Curl_creader *reader = data->req.reader_stack;
1427 while(reader) {
1428 reader->crt->done(data, reader, premature);
1429 reader = reader->next;
1430 }
1431 }
1432
Curl_creader_get_by_type(struct Curl_easy * data,const struct Curl_crtype * crt)1433 struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
1434 const struct Curl_crtype *crt)
1435 {
1436 struct Curl_creader *r;
1437 for(r = data->req.reader_stack; r; r = r->next) {
1438 if(r->crt == crt)
1439 return r;
1440 }
1441 return NULL;
1442
1443 }
1444