Coverage Report

Created: 2026-10-15 06:19

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