Coverage Report

Created: 2026-07-30 07:03

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