xref: /aosp_15_r20/external/curl/docs/internals/CLIENT-WRITERS.md (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker<!--
2*6236dae4SAndroid Build Coastguard WorkerCopyright (C) Daniel Stenberg, <[email protected]>, et al.
3*6236dae4SAndroid Build Coastguard Worker
4*6236dae4SAndroid Build Coastguard WorkerSPDX-License-Identifier: curl
5*6236dae4SAndroid Build Coastguard Worker-->
6*6236dae4SAndroid Build Coastguard Worker
7*6236dae4SAndroid Build Coastguard Worker# curl client writers
8*6236dae4SAndroid Build Coastguard Worker
9*6236dae4SAndroid Build Coastguard WorkerClient writers is a design in the internals of libcurl, not visible in its public API. They were started
10*6236dae4SAndroid Build Coastguard Workerin curl v8.5.0. This document describes the concepts, its high level implementation and the motivations.
11*6236dae4SAndroid Build Coastguard Worker
12*6236dae4SAndroid Build Coastguard Worker## Naming
13*6236dae4SAndroid Build Coastguard Worker
14*6236dae4SAndroid Build Coastguard Worker`libcurl` operates between clients and servers. A *client* is the application using libcurl, like the command line tool `curl` itself. Data to be uploaded to a server is **read** from the client and **send** to the server, the servers response is **received** by `libcurl` and then **written** to the client.
15*6236dae4SAndroid Build Coastguard Worker
16*6236dae4SAndroid Build Coastguard WorkerWith this naming established, client writers are concerned with writing responses from the server to the application. Applications register callbacks via `CURLOPT_WRITEFUNCTION` and `CURLOPT_HEADERFUNCTION` to be invoked by `libcurl` when the response is received.
17*6236dae4SAndroid Build Coastguard Worker
18*6236dae4SAndroid Build Coastguard Worker## Invoking
19*6236dae4SAndroid Build Coastguard Worker
20*6236dae4SAndroid Build Coastguard WorkerAll code in `libcurl` that handles response data is ultimately expected to forward this data via `Curl_client_write()` to the application. The exact prototype of this function is:
21*6236dae4SAndroid Build Coastguard Worker
22*6236dae4SAndroid Build Coastguard Worker```
23*6236dae4SAndroid Build Coastguard WorkerCURLcode Curl_client_write(struct Curl_easy *data, int type, const char *buf, size_t blen);
24*6236dae4SAndroid Build Coastguard Worker```
25*6236dae4SAndroid Build Coastguard WorkerThe `type` argument specifies what the bytes in `buf` actually are. The following bits are defined:
26*6236dae4SAndroid Build Coastguard Worker
27*6236dae4SAndroid Build Coastguard Worker```
28*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_BODY    (1<<0) /* non-meta information, BODY */
29*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_INFO    (1<<1) /* meta information, not a HEADER */
30*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_HEADER  (1<<2) /* meta information, HEADER */
31*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_STATUS  (1<<3) /* a special status HEADER */
32*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */
33*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_1XX     (1<<5) /* a 1xx response related HEADER */
34*6236dae4SAndroid Build Coastguard Worker#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
35*6236dae4SAndroid Build Coastguard Worker```
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard WorkerThe main types here are `CLIENTWRITE_BODY` and `CLIENTWRITE_HEADER`. They are
38*6236dae4SAndroid Build Coastguard Workermutually exclusive. The other bits are enhancements to `CLIENTWRITE_HEADER` to
39*6236dae4SAndroid Build Coastguard Workerspecify what the header is about. They are only used in HTTP and related
40*6236dae4SAndroid Build Coastguard Workerprotocols (RTSP and WebSocket).
41*6236dae4SAndroid Build Coastguard Worker
42*6236dae4SAndroid Build Coastguard WorkerThe implementation of `Curl_client_write()` uses a chain of *client writer* instances to process the call and make sure that the bytes reach the proper application callbacks. This is similar to the design of connection filters: client writers can be chained to process the bytes written through them. The definition is:
43*6236dae4SAndroid Build Coastguard Worker
44*6236dae4SAndroid Build Coastguard Worker```
45*6236dae4SAndroid Build Coastguard Workerstruct Curl_cwtype {
46*6236dae4SAndroid Build Coastguard Worker  const char *name;
47*6236dae4SAndroid Build Coastguard Worker  CURLcode (*do_init)(struct Curl_easy *data,
48*6236dae4SAndroid Build Coastguard Worker                      struct Curl_cwriter *writer);
49*6236dae4SAndroid Build Coastguard Worker  CURLcode (*do_write)(struct Curl_easy *data,
50*6236dae4SAndroid Build Coastguard Worker                       struct Curl_cwriter *writer, int type,
51*6236dae4SAndroid Build Coastguard Worker                       const char *buf, size_t nbytes);
52*6236dae4SAndroid Build Coastguard Worker  void (*do_close)(struct Curl_easy *data,
53*6236dae4SAndroid Build Coastguard Worker                   struct Curl_cwriter *writer);
54*6236dae4SAndroid Build Coastguard Worker};
55*6236dae4SAndroid Build Coastguard Worker
56*6236dae4SAndroid Build Coastguard Workerstruct Curl_cwriter {
57*6236dae4SAndroid Build Coastguard Worker  const struct Curl_cwtype *cwt;  /* type implementation */
58*6236dae4SAndroid Build Coastguard Worker  struct Curl_cwriter *next;  /* Downstream writer. */
59*6236dae4SAndroid Build Coastguard Worker  Curl_cwriter_phase phase; /* phase at which it operates */
60*6236dae4SAndroid Build Coastguard Worker};
61*6236dae4SAndroid Build Coastguard Worker```
62*6236dae4SAndroid Build Coastguard Worker
63*6236dae4SAndroid Build Coastguard Worker`Curl_cwriter` is a writer instance with a `next` pointer to form the chain. It has a type `cwt` which provides the implementation. The main callback is `do_write()` that processes the data and calls then the `next` writer. The others are for setup and tear down.
64*6236dae4SAndroid Build Coastguard Worker
65*6236dae4SAndroid Build Coastguard Worker## Phases and Ordering
66*6236dae4SAndroid Build Coastguard Worker
67*6236dae4SAndroid Build Coastguard WorkerSince client writers may transform the bytes written through them, the order in which the are called is relevant for the outcome. When a writer is created, one property it gets is the `phase` in which it operates. Writer phases are defined like:
68*6236dae4SAndroid Build Coastguard Worker
69*6236dae4SAndroid Build Coastguard Worker```
70*6236dae4SAndroid Build Coastguard Workertypedef enum {
71*6236dae4SAndroid Build Coastguard Worker  CURL_CW_RAW,  /* raw data written, before any decoding */
72*6236dae4SAndroid Build Coastguard Worker  CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
73*6236dae4SAndroid Build Coastguard Worker  CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
74*6236dae4SAndroid Build Coastguard Worker  CURL_CW_CONTENT_DECODE, /* remove content-encodings */
75*6236dae4SAndroid Build Coastguard Worker  CURL_CW_CLIENT  /* data written to client */
76*6236dae4SAndroid Build Coastguard Worker} Curl_cwriter_phase;
77*6236dae4SAndroid Build Coastguard Worker```
78*6236dae4SAndroid Build Coastguard Worker
79*6236dae4SAndroid Build Coastguard WorkerIf a writer for phase `PROTOCOL` is added to the chain, it is always added *after* any `RAW` or `TRANSFER_DECODE` and *before* any `CONTENT_DECODE` and `CLIENT` phase writer. If there is already a writer for the same phase present, the new writer is inserted just before that one.
80*6236dae4SAndroid Build Coastguard Worker
81*6236dae4SAndroid Build Coastguard WorkerAll transfers have a chain of 3 writers by default. A specific protocol handler may alter that by adding additional writers. The 3 standard writers are (name, phase):
82*6236dae4SAndroid Build Coastguard Worker
83*6236dae4SAndroid Build Coastguard Worker1. `"raw", CURL_CW_RAW `: if the transfer is verbose, it forwards the body data to the debug function.
84*6236dae4SAndroid Build Coastguard Worker1. `"download", CURL_CW_PROTOCOL`: checks that protocol limits are kept and updates progress counters. When a download has a known length, it checks that it is not exceeded and errors otherwise.
85*6236dae4SAndroid Build Coastguard Worker1. `"client", CURL_CW_CLIENT`: the main work horse. It invokes the application callbacks or writes to the configured file handles. It chops large writes into smaller parts, as documented for `CURLOPT_WRITEFUNCTION`. If also handles *pausing* of transfers when the application callback returns `CURL_WRITEFUNC_PAUSE`.
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard WorkerWith these writers always in place, libcurl's protocol handlers automatically have these implemented.
88*6236dae4SAndroid Build Coastguard Worker
89*6236dae4SAndroid Build Coastguard Worker## Enhanced Use
90*6236dae4SAndroid Build Coastguard Worker
91*6236dae4SAndroid Build Coastguard WorkerHTTP is the protocol in curl that makes use of the client writer chain by
92*6236dae4SAndroid Build Coastguard Workeradding writers to it. When the `libcurl` application set
93*6236dae4SAndroid Build Coastguard Worker`CURLOPT_ACCEPT_ENCODING` (as `curl` does with `--compressed`), the server is
94*6236dae4SAndroid Build Coastguard Workeroffered an `Accept-Encoding` header with the algorithms supported. The server
95*6236dae4SAndroid Build Coastguard Workerthen may choose to send the response body compressed. For example using `gzip`
96*6236dae4SAndroid Build Coastguard Workeror `brotli` or even both.
97*6236dae4SAndroid Build Coastguard Worker
98*6236dae4SAndroid Build Coastguard WorkerIn the server's response, if there is a `Content-Encoding` header listing the
99*6236dae4SAndroid Build Coastguard Workerencoding applied. If supported by `libcurl` it then decompresses the content
100*6236dae4SAndroid Build Coastguard Workerbefore writing it out to the client. How does it do that?
101*6236dae4SAndroid Build Coastguard Worker
102*6236dae4SAndroid Build Coastguard WorkerThe HTTP protocol adds client writers in phase `CURL_CW_CONTENT_DECODE` on
103*6236dae4SAndroid Build Coastguard Workerseeing such a header. For each encoding listed, it adds the corresponding
104*6236dae4SAndroid Build Coastguard Workerwriter. The response from the server is then passed through
105*6236dae4SAndroid Build Coastguard Worker`Curl_client_write()` to the writers that decode it. If several encodings had
106*6236dae4SAndroid Build Coastguard Workerbeen applied the writer chain decodes them in the proper order.
107*6236dae4SAndroid Build Coastguard Worker
108*6236dae4SAndroid Build Coastguard WorkerWhen the server provides a `Content-Length` header, that value applies to the
109*6236dae4SAndroid Build Coastguard Worker*compressed* content. Length checks on the response bytes must happen *before*
110*6236dae4SAndroid Build Coastguard Workerit gets decoded. That is why this check happens in phase `CURL_CW_PROTOCOL`
111*6236dae4SAndroid Build Coastguard Workerwhich always is ordered before writers in phase `CURL_CW_CONTENT_DECODE`.
112*6236dae4SAndroid Build Coastguard Worker
113*6236dae4SAndroid Build Coastguard WorkerWhat else?
114*6236dae4SAndroid Build Coastguard Worker
115*6236dae4SAndroid Build Coastguard WorkerWell, HTTP servers may also apply a `Transfer-Encoding` to the body of a response. The most well-known one is `chunked`, but algorithms like `gzip` and friends could also be applied. The difference to content encodings is that decoding needs to happen *before* protocol checks, for example on length, are done.
116*6236dae4SAndroid Build Coastguard Worker
117*6236dae4SAndroid Build Coastguard WorkerThat is why transfer decoding writers are added for phase `CURL_CW_TRANSFER_DECODE`. Which makes their operation happen *before* phase `CURL_CW_PROTOCOL` where length may be checked.
118*6236dae4SAndroid Build Coastguard Worker
119*6236dae4SAndroid Build Coastguard Worker## Summary
120*6236dae4SAndroid Build Coastguard Worker
121*6236dae4SAndroid Build Coastguard WorkerBy adding the common behavior of all protocols into `Curl_client_write()` we make sure that they do apply everywhere. Protocol handler have less to worry about. Changes to default behavior can be done without affecting handler implementations.
122*6236dae4SAndroid Build Coastguard Worker
123*6236dae4SAndroid Build Coastguard WorkerHaving a writer chain as implementation allows protocol handlers with extra needs, like HTTP, to add to this for special behavior. The common way of writing the actual response data stays the same.
124