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