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