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 */ |