Coverage Report

Created: 2025-10-30 06:17

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