Coverage Report

Created: 2026-07-30 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/sendf.h
Line
Count
Source
1
#ifndef HEADER_CURL_SENDF_H
2
#define HEADER_CURL_SENDF_H
3
/***************************************************************************
4
 *                                  _   _ ____  _
5
 *  Project                     ___| | | |  _ \| |
6
 *                             / __| | | | |_) | |
7
 *                            | (__| |_| |  _ <| |___
8
 *                             \___|\___/|_| \_\_____|
9
 *
10
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
11
 *
12
 * This software is licensed as described in the file COPYING, which
13
 * you should have received as part of this distribution. The terms
14
 * are also available at https://curl.se/docs/copyright.html.
15
 *
16
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17
 * copies of the Software, and permit persons to whom the Software is
18
 * furnished to do so, under the terms of the COPYING file.
19
 *
20
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21
 * KIND, either express or implied.
22
 *
23
 * SPDX-License-Identifier: curl
24
 *
25
 ***************************************************************************/
26
#include "curl_setup.h"
27
#include "cw-out.h"
28
29
/**
30
 * Type of data that is being written to the client (application)
31
 * - data written can be either BODY or META data
32
 * - META data is either INFO or HEADER
33
 * - INFO is meta information, e.g. not BODY, that cannot be interpreted
34
 *   as headers of a response. Example FTP/IMAP pingpong answers.
35
 * - HEADER can have additional bits set (more than one)
36
 *   - STATUS special "header", e.g. response status line in HTTP
37
 *   - CONNECT header was received during proxying the connection
38
 *   - 1XX header is part of an intermediate response, e.g. HTTP 1xx code
39
 *   - TRAILER header is trailing response data, e.g. HTTP trailers
40
 * BODY, INFO and HEADER should not be mixed, as this would lead to
41
 * confusion on how to interpret/format/convert the data.
42
 */
43
0
#define CLIENTWRITE_BODY    (1 << 0) /* non-meta information, BODY */
44
0
#define CLIENTWRITE_INFO    (1 << 1) /* meta information, not a HEADER */
45
0
#define CLIENTWRITE_HEADER  (1 << 2) /* meta information, HEADER */
46
0
#define CLIENTWRITE_STATUS  (1 << 3) /* a special status HEADER */
47
0
#define CLIENTWRITE_CONNECT (1 << 4) /* a CONNECT related HEADER */
48
0
#define CLIENTWRITE_1XX     (1 << 5) /* a 1xx response related HEADER */
49
0
#define CLIENTWRITE_TRAILER (1 << 6) /* a trailer HEADER */
50
0
#define CLIENTWRITE_EOS     (1 << 7) /* End Of transfer download Stream */
51
0
#define CLIENTWRITE_0LEN    (1 << 8) /* write even 0-length buffers */
52
53
/* Forward declarations */
54
struct Curl_creader;
55
struct Curl_cwriter;
56
struct Curl_easy;
57
58
/**
59
 * Write `len` bytes at `buf` to the client. `type` indicates what
60
 * kind of data is being written.
61
 */
62
CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *buf,
63
                           size_t len) WARN_UNUSED_RESULT;
64
65
CURLcode Curl_client_flush(struct Curl_easy *data);
66
67
/**
68
 * Free all resources related to client writing.
69
 */
70
void Curl_client_cleanup(struct Curl_easy *data);
71
72
/**
73
 * Reset readers and writer chains, keep rewind information
74
 * when necessary.
75
 */
76
void Curl_client_reset(struct Curl_easy *data);
77
78
/**
79
 * A new request is starting, perform any ops like rewinding
80
 * previous readers when needed.
81
 */
82
CURLcode Curl_client_start(struct Curl_easy *data);
83
84
/**
85
 * Client Writers - a chain passing transfer BODY data to the client.
86
 * Main application: HTTP and related protocols
87
 * Other uses: monitoring of download progress
88
 *
89
 * Writers in the chain are order by their `phase`. First come all
90
 * writers in CURL_CW_RAW, followed by any in CURL_CW_TRANSFER_DECODE,
91
 * followed by any in CURL_CW_PROTOCOL, etc.
92
 *
93
 * When adding a writer, it is inserted as first in its phase. This means
94
 * the order of adding writers of the same phase matters, but writers for
95
 * different phases may be added in any order.
96
 *
97
 * Writers which do modify the BODY data written are expected to be of
98
 * phases TRANSFER_DECODE or CONTENT_DECODE. The other phases are intended
99
 * for monitoring writers. Which do *not* modify the data but gather
100
 * statistics or update progress reporting.
101
 */
102
103
/* Phase a writer operates at. */
104
typedef enum {
105
  CURL_CW_RAW,  /* raw data written, before any decoding */
106
  CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
107
  CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
108
  CURL_CW_BEFORE_DECODE, /* after protocol, but before content decoding */
109
  CURL_CW_CONTENT_DECODE, /* remove content-encodings */
110
  CURL_CW_CLIENT  /* data written to client */
111
} Curl_cwriter_phase;
112
113
/* writer may blow up size of write data, e.g. zip bombs */
114
0
#define CURL_CW_FLAG_BLOWUP     (1U << 0)
115
116
/* Client Writer Type, provides the implementation */
117
struct Curl_cwtype {
118
  const char *name;        /* writer name. */
119
  const char *alias;       /* writer name alias, maybe NULL. */
120
  uint8_t flags;           /* flags for writer behaviour */
121
  CURLcode (*do_init)(struct Curl_easy *data,
122
                      struct Curl_cwriter *writer);
123
  CURLcode (*do_write)(struct Curl_easy *data,
124
                       struct Curl_cwriter *writer, int type,
125
                       const char *buf, size_t nbytes);
126
  CURLcode (*do_flush)(struct Curl_easy *data,
127
                       struct Curl_cwriter *writer);
128
  void (*do_close)(struct Curl_easy *data,
129
                   struct Curl_cwriter *writer);
130
  size_t cwriter_size;  /* sizeof() allocated struct Curl_cwriter */
131
};
132
133
/* Client writer instance, allocated on creation.
134
 * `void *ctx` is the pointer from the allocation of
135
 * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
136
 * by the writers implementation. See https://github.com/curl/curl/pull/13054
137
 * for the alignment problems that arise otherwise.
138
 */
139
struct Curl_cwriter {
140
  const struct Curl_cwtype *cwt;  /* type implementation */
141
  struct Curl_cwriter *next;  /* Downstream writer. */
142
  void *ctx;                  /* allocated instance pointer */
143
  Curl_cwriter_phase phase; /* phase at which it operates */
144
};
145
146
/**
147
 * Create a new cwriter instance with given type and phase. Is not
148
 * inserted into the writer chain by this call.
149
 * Invokes `writer->do_init()`.
150
 */
151
CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
152
                             struct Curl_easy *data,
153
                             const struct Curl_cwtype *cwt,
154
                             Curl_cwriter_phase phase);
155
156
/**
157
 * Free a cwriter instance.
158
 * Invokes `writer->do_close()`.
159
 */
160
void Curl_cwriter_free(struct Curl_easy *data,
161
                       struct Curl_cwriter *writer);
162
163
/**
164
 * Count the number of writers installed of the given phase.
165
 */
166
size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase);
167
168
/**
169
 * Adds a writer to the transfer's writer chain.
170
 * The writers `phase` determines where in the chain it is inserted.
171
 */
172
CURLcode Curl_cwriter_add(struct Curl_easy *data,
173
                          struct Curl_cwriter *writer);
174
175
/**
176
 * Look up an installed client writer on `data` by its type.
177
 * @return first writer with that type or NULL
178
 */
179
struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
180
                                              const struct Curl_cwtype *cwt);
181
182
struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
183
                                              const char *name);
184
185
/* Convenience method for calling `writer->do_write()` that
186
 * checks for NULL writer. */
187
#define Curl_cwriter_write(d, w, t, b, n) \
188
0
  ((w) ? (w)->cwt->do_write((d), (w), (t), (b), (n)) : CURLE_WRITE_ERROR)
189
190
#define Curl_cwriter_flush(d, w) \
191
0
  ((w) ? (w)->cwt->do_flush((d), (w)) : CURLE_WRITE_ERROR)
192
193
/* TRUE if client writer is paused. */
194
0
#define Curl_cwriter_is_paused(d)     ((bool)(d)->req.writer.paused)
195
196
/**
197
 * Unpause client writer and flush any buffered date to the client.
198
 */
199
CURLcode Curl_cwriter_unpause(struct Curl_easy *data);
200
201
/**
202
 * Default implementations for do_init, do_write, do_close that
203
 * do nothing and pass the data through.
204
 */
205
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
206
                               struct Curl_cwriter *writer);
207
CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
208
                                struct Curl_cwriter *writer, int type,
209
                                const char *buf, size_t nbytes);
210
CURLcode Curl_cwriter_def_flush(struct Curl_easy *data,
211
                                struct Curl_cwriter *writer);
212
void Curl_cwriter_def_close(struct Curl_easy *data,
213
                            struct Curl_cwriter *writer);
214
215
typedef enum {
216
  CURL_CRCNTRL_REWIND,
217
  CURL_CRCNTRL_UNPAUSE,
218
  CURL_CRCNTRL_CLEAR_EOS
219
} Curl_creader_cntrl;
220
221
/* Client Reader Type, provides the implementation */
222
struct Curl_crtype {
223
  const char *name;        /* writer name. */
224
  CURLcode (*do_init)(struct Curl_easy *data, struct Curl_creader *reader);
225
  CURLcode (*do_read)(struct Curl_easy *data, struct Curl_creader *reader,
226
                      char *buf, size_t blen, size_t *nread, bool *eos);
227
  void (*do_close)(struct Curl_easy *data, struct Curl_creader *reader);
228
  bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader);
229
  curl_off_t (*total_length)(struct Curl_easy *data,
230
                             struct Curl_creader *reader);
231
  CURLcode (*resume_from)(struct Curl_easy *data,
232
                          struct Curl_creader *reader, curl_off_t offset);
233
  CURLcode (*cntrl)(struct Curl_easy *data, struct Curl_creader *reader,
234
                    Curl_creader_cntrl opcode);
235
  bool (*is_paused)(struct Curl_easy *data, struct Curl_creader *reader);
236
  void (*done)(struct Curl_easy *data,
237
               struct Curl_creader *reader, int premature);
238
  size_t creader_size;  /* sizeof() allocated struct Curl_creader */
239
};
240
241
/* Phase a reader operates at. */
242
typedef enum {
243
  CURL_CR_NET,  /* data send to the network (connection filters) */
244
  CURL_CR_TRANSFER_ENCODE, /* add transfer-encodings */
245
  CURL_CR_PROTOCOL, /* before transfer, but after content decoding */
246
  CURL_CR_CONTENT_ENCODE, /* add content-encodings */
247
  CURL_CR_CLIENT  /* data read from client */
248
} Curl_creader_phase;
249
250
/* Client reader instance, allocated on creation.
251
 * `void *ctx` is the pointer from the allocation of
252
 * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
253
 * by the writers implementation. See https://github.com/curl/curl/pull/13054
254
 * for the alignment problems that arise otherwise.
255
 */
256
struct Curl_creader {
257
  const struct Curl_crtype *crt;  /* type implementation */
258
  struct Curl_creader *next;  /* Downstream reader. */
259
  void *ctx;
260
  Curl_creader_phase phase; /* phase at which it operates */
261
};
262
263
/**
264
 * Default implementations for do_init, do_write, do_close that
265
 * do nothing and pass the data through.
266
 */
267
CURLcode Curl_creader_def_init(struct Curl_easy *data,
268
                               struct Curl_creader *reader);
269
void Curl_creader_def_close(struct Curl_easy *data,
270
                            struct Curl_creader *reader);
271
CURLcode Curl_creader_def_read(struct Curl_easy *data,
272
                               struct Curl_creader *reader,
273
                               char *buf, size_t blen,
274
                               size_t *nread, bool *eos);
275
bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
276
                                   struct Curl_creader *reader);
277
curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
278
                                         struct Curl_creader *reader);
279
CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
280
                                      struct Curl_creader *reader,
281
                                      curl_off_t offset);
282
CURLcode Curl_creader_def_cntrl(struct Curl_easy *data,
283
                                struct Curl_creader *reader,
284
                                Curl_creader_cntrl opcode);
285
bool Curl_creader_def_is_paused(struct Curl_easy *data,
286
                                struct Curl_creader *reader);
287
void Curl_creader_def_done(struct Curl_easy *data,
288
                           struct Curl_creader *reader, int premature);
289
290
/**
291
 * Convenience method for calling `reader->do_read()` that
292
 * checks for NULL reader.
293
 */
294
CURLcode Curl_creader_read(struct Curl_easy *data,
295
                           struct Curl_creader *reader,
296
                           char *buf, size_t blen, size_t *nread, bool *eos);
297
298
/* Tell the reader and all below that any EOS state is to be cleared */
299
void Curl_creader_clear_eos(struct Curl_easy *data,
300
                            struct Curl_creader *reader);
301
302
/**
303
 * Create a new creader instance with given type and phase. Is not
304
 * inserted into the writer chain by this call.
305
 * Invokes `reader->do_init()`.
306
 */
307
CURLcode Curl_creader_create(struct Curl_creader **preader,
308
                             struct Curl_easy *data,
309
                             const struct Curl_crtype *crt,
310
                             Curl_creader_phase phase);
311
312
/**
313
 * Free a creader instance.
314
 * Invokes `reader->do_close()`.
315
 */
316
void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader);
317
318
/**
319
 * Adds a reader to the transfer's reader chain.
320
 * The readers `phase` determines where in the chain it is inserted.
321
 */
322
CURLcode Curl_creader_add(struct Curl_easy *data,
323
                          struct Curl_creader *reader);
324
325
/**
326
 * Set the given reader, which needs to be of type CURL_CR_CLIENT,
327
 * as the new first reader. Discard any installed readers and init
328
 * the reader chain anew.
329
 * The function takes ownership of `r`.
330
 */
331
CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r);
332
333
/**
334
 * Read at most `blen` bytes at `buf` from the client.
335
 * @param data    the transfer to read client bytes for
336
 * @param buf     the memory location to read to
337
 * @param blen    the amount of memory at `buf`
338
 * @param nread   on return the number of bytes read into `buf`
339
 * @param eos     TRUE iff bytes are the end of data from client
340
 * @return CURLE_OK on successful read (even 0 length) or error
341
 */
342
CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
343
                          size_t *nread, bool *eos) WARN_UNUSED_RESULT;
344
345
/**
346
 * TRUE iff client reader needs rewing before it can be used for
347
 * a retry request.
348
 */
349
bool Curl_creader_needs_rewind(struct Curl_easy *data);
350
351
/**
352
 * TRUE iff client reader will rewind at next start
353
 */
354
bool Curl_creader_will_rewind(struct Curl_easy *data);
355
356
/**
357
 * En-/disable rewind of client reader at next start.
358
 */
359
void Curl_creader_set_rewind(struct Curl_easy *data, bool enable);
360
361
/**
362
 * Get the total length of bytes provided by the installed readers.
363
 * This is independent of the amount already delivered and is calculated
364
 * by all readers in the stack. If a reader like "chunked" or
365
 * "crlf conversion" is installed, the returned length will be -1.
366
 * @return -1 if length is indeterminate
367
 */
368
curl_off_t Curl_creader_total_length(struct Curl_easy *data);
369
370
/**
371
 * Get the total length of bytes provided by the reader at phase
372
 * CURL_CR_CLIENT. This may not match the amount of bytes read
373
 * for a request, depending if other, encoding readers are also installed.
374
 * However it allows for rough estimation of the overall length.
375
 * @return -1 if length is indeterminate
376
 */
377
curl_off_t Curl_creader_client_length(struct Curl_easy *data);
378
379
/**
380
 * Ask the installed reader at phase CURL_CR_CLIENT to start
381
 * reading from the given offset. On success, this will reduce
382
 * the `total_length()` by the amount.
383
 * @param data    the transfer to read client bytes for
384
 * @param offset  the offset where to start reads from, negative
385
 *                values will be ignored.
386
 * @return CURLE_OK if offset could be set
387
 *         CURLE_READ_ERROR if not supported by reader or seek/read failed
388
 *                          of offset larger than total length
389
 *         CURLE_PARTIAL_FILE if offset led to 0 total length
390
 */
391
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);
392
393
/**
394
 * Unpause all installed readers.
395
 */
396
CURLcode Curl_creader_unpause(struct Curl_easy *data);
397
398
/**
399
 * Return TRUE iff any of the installed readers is paused.
400
 */
401
bool Curl_creader_is_paused(struct Curl_easy *data);
402
403
/**
404
 * Tell all client readers that they are done.
405
 */
406
void Curl_creader_done(struct Curl_easy *data, int premature);
407
408
/**
409
 * Look up an installed client reader on `data` by its type.
410
 * @return first reader with that type or NULL
411
 */
412
struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
413
                                              const struct Curl_crtype *crt);
414
415
/**
416
 * Set the client reader to provide 0 bytes, immediate EOS.
417
 */
418
CURLcode Curl_creader_set_null(struct Curl_easy *data);
419
420
/**
421
 * Set the client reader the reads from fread callback.
422
 */
423
CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len);
424
425
/**
426
 * Set the client reader the reads from the supplied buf (NOT COPIED).
427
 */
428
CURLcode Curl_creader_set_buf(struct Curl_easy *data,
429
                              const char *buf, size_t blen);
430
431
#endif /* HEADER_CURL_SENDF_H */