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