Coverage Report

Created: 2025-08-29 06:06

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