xref: /curl/lib/sendf.c (revision fc3e1cbc)
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