Coverage Report

Created: 2026-01-10 06:51

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