xref: /aosp_15_r20/external/curl/lib/cw-out.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
30*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
31*6236dae4SAndroid Build Coastguard Worker #include "headers.h"
32*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
33*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
34*6236dae4SAndroid Build Coastguard Worker #include "cw-out.h"
35*6236dae4SAndroid Build Coastguard Worker 
36*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
37*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
38*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
39*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
40*6236dae4SAndroid Build Coastguard Worker 
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker /**
43*6236dae4SAndroid Build Coastguard Worker  * OVERALL DESIGN of this client writer
44*6236dae4SAndroid Build Coastguard Worker  *
45*6236dae4SAndroid Build Coastguard Worker  * The 'cw-out' writer is supposed to be the last writer in a transfer's
46*6236dae4SAndroid Build Coastguard Worker  * stack. It is always added when that stack is initialized. Its purpose
47*6236dae4SAndroid Build Coastguard Worker  * is to pass BODY and HEADER bytes to the client-installed callback
48*6236dae4SAndroid Build Coastguard Worker  * functions.
49*6236dae4SAndroid Build Coastguard Worker  *
50*6236dae4SAndroid Build Coastguard Worker  * These callback may return `CURL_WRITEFUNC_PAUSE` to indicate that the
51*6236dae4SAndroid Build Coastguard Worker  * data had not been written and the whole transfer should stop receiving
52*6236dae4SAndroid Build Coastguard Worker  * new data. Or at least, stop calling the functions. When the transfer
53*6236dae4SAndroid Build Coastguard Worker  * is "unpaused" by the client, the previous data shall be passed as
54*6236dae4SAndroid Build Coastguard Worker  * if nothing happened.
55*6236dae4SAndroid Build Coastguard Worker  *
56*6236dae4SAndroid Build Coastguard Worker  * The `cw-out` writer therefore manages buffers for bytes that could
57*6236dae4SAndroid Build Coastguard Worker  * not be written. Data that was already in flight from the server also
58*6236dae4SAndroid Build Coastguard Worker  * needs buffering on paused transfer when it arrives.
59*6236dae4SAndroid Build Coastguard Worker  *
60*6236dae4SAndroid Build Coastguard Worker  * In addition, the writer allows buffering of "small" body writes,
61*6236dae4SAndroid Build Coastguard Worker  * so client functions are called less often. That is only enabled on a
62*6236dae4SAndroid Build Coastguard Worker  * number of conditions.
63*6236dae4SAndroid Build Coastguard Worker  *
64*6236dae4SAndroid Build Coastguard Worker  * HEADER and BODY data may arrive in any order. For paused transfers,
65*6236dae4SAndroid Build Coastguard Worker  * a list of `struct cw_out_buf` is kept for `cw_out_type` types. The
66*6236dae4SAndroid Build Coastguard Worker  * list may be: [BODY]->[HEADER]->[BODY]->[HEADER]....
67*6236dae4SAndroid Build Coastguard Worker  * When unpausing, this list is "played back" to the client callbacks.
68*6236dae4SAndroid Build Coastguard Worker  *
69*6236dae4SAndroid Build Coastguard Worker  * The amount of bytes being buffered is limited by `DYN_PAUSE_BUFFER`
70*6236dae4SAndroid Build Coastguard Worker  * and when that is exceeded `CURLE_TOO_LARGE` is returned as error.
71*6236dae4SAndroid Build Coastguard Worker  */
72*6236dae4SAndroid Build Coastguard Worker typedef enum {
73*6236dae4SAndroid Build Coastguard Worker   CW_OUT_NONE,
74*6236dae4SAndroid Build Coastguard Worker   CW_OUT_BODY,
75*6236dae4SAndroid Build Coastguard Worker   CW_OUT_HDS
76*6236dae4SAndroid Build Coastguard Worker } cw_out_type;
77*6236dae4SAndroid Build Coastguard Worker 
78*6236dae4SAndroid Build Coastguard Worker struct cw_out_buf {
79*6236dae4SAndroid Build Coastguard Worker   struct cw_out_buf *next;
80*6236dae4SAndroid Build Coastguard Worker   struct dynbuf b;
81*6236dae4SAndroid Build Coastguard Worker   cw_out_type type;
82*6236dae4SAndroid Build Coastguard Worker };
83*6236dae4SAndroid Build Coastguard Worker 
cw_out_buf_create(cw_out_type otype)84*6236dae4SAndroid Build Coastguard Worker static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
85*6236dae4SAndroid Build Coastguard Worker {
86*6236dae4SAndroid Build Coastguard Worker   struct cw_out_buf *cwbuf = calloc(1, sizeof(*cwbuf));
87*6236dae4SAndroid Build Coastguard Worker   if(cwbuf) {
88*6236dae4SAndroid Build Coastguard Worker     cwbuf->type = otype;
89*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
90*6236dae4SAndroid Build Coastguard Worker   }
91*6236dae4SAndroid Build Coastguard Worker   return cwbuf;
92*6236dae4SAndroid Build Coastguard Worker }
93*6236dae4SAndroid Build Coastguard Worker 
cw_out_buf_free(struct cw_out_buf * cwbuf)94*6236dae4SAndroid Build Coastguard Worker static void cw_out_buf_free(struct cw_out_buf *cwbuf)
95*6236dae4SAndroid Build Coastguard Worker {
96*6236dae4SAndroid Build Coastguard Worker   if(cwbuf) {
97*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_free(&cwbuf->b);
98*6236dae4SAndroid Build Coastguard Worker     free(cwbuf);
99*6236dae4SAndroid Build Coastguard Worker   }
100*6236dae4SAndroid Build Coastguard Worker }
101*6236dae4SAndroid Build Coastguard Worker 
102*6236dae4SAndroid Build Coastguard Worker struct cw_out_ctx {
103*6236dae4SAndroid Build Coastguard Worker   struct Curl_cwriter super;
104*6236dae4SAndroid Build Coastguard Worker   struct cw_out_buf *buf;
105*6236dae4SAndroid Build Coastguard Worker   BIT(paused);
106*6236dae4SAndroid Build Coastguard Worker   BIT(errored);
107*6236dae4SAndroid Build Coastguard Worker };
108*6236dae4SAndroid Build Coastguard Worker 
109*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_write(struct Curl_easy *data,
110*6236dae4SAndroid Build Coastguard Worker                              struct Curl_cwriter *writer, int type,
111*6236dae4SAndroid Build Coastguard Worker                              const char *buf, size_t nbytes);
112*6236dae4SAndroid Build Coastguard Worker static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer);
113*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_init(struct Curl_easy *data,
114*6236dae4SAndroid Build Coastguard Worker                             struct Curl_cwriter *writer);
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker struct Curl_cwtype Curl_cwt_out = {
117*6236dae4SAndroid Build Coastguard Worker   "cw-out",
118*6236dae4SAndroid Build Coastguard Worker   NULL,
119*6236dae4SAndroid Build Coastguard Worker   cw_out_init,
120*6236dae4SAndroid Build Coastguard Worker   cw_out_write,
121*6236dae4SAndroid Build Coastguard Worker   cw_out_close,
122*6236dae4SAndroid Build Coastguard Worker   sizeof(struct cw_out_ctx)
123*6236dae4SAndroid Build Coastguard Worker };
124*6236dae4SAndroid Build Coastguard Worker 
cw_out_init(struct Curl_easy * data,struct Curl_cwriter * writer)125*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_init(struct Curl_easy *data,
126*6236dae4SAndroid Build Coastguard Worker                             struct Curl_cwriter *writer)
127*6236dae4SAndroid Build Coastguard Worker {
128*6236dae4SAndroid Build Coastguard Worker   struct cw_out_ctx *ctx = writer->ctx;
129*6236dae4SAndroid Build Coastguard Worker   (void)data;
130*6236dae4SAndroid Build Coastguard Worker   ctx->buf = NULL;
131*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
132*6236dae4SAndroid Build Coastguard Worker }
133*6236dae4SAndroid Build Coastguard Worker 
cw_out_bufs_free(struct cw_out_ctx * ctx)134*6236dae4SAndroid Build Coastguard Worker static void cw_out_bufs_free(struct cw_out_ctx *ctx)
135*6236dae4SAndroid Build Coastguard Worker {
136*6236dae4SAndroid Build Coastguard Worker   while(ctx->buf) {
137*6236dae4SAndroid Build Coastguard Worker     struct cw_out_buf *next = ctx->buf->next;
138*6236dae4SAndroid Build Coastguard Worker     cw_out_buf_free(ctx->buf);
139*6236dae4SAndroid Build Coastguard Worker     ctx->buf = next;
140*6236dae4SAndroid Build Coastguard Worker   }
141*6236dae4SAndroid Build Coastguard Worker }
142*6236dae4SAndroid Build Coastguard Worker 
cw_out_bufs_len(struct cw_out_ctx * ctx)143*6236dae4SAndroid Build Coastguard Worker static size_t cw_out_bufs_len(struct cw_out_ctx *ctx)
144*6236dae4SAndroid Build Coastguard Worker {
145*6236dae4SAndroid Build Coastguard Worker   struct cw_out_buf *cwbuf = ctx->buf;
146*6236dae4SAndroid Build Coastguard Worker   size_t len = 0;
147*6236dae4SAndroid Build Coastguard Worker   while(cwbuf) {
148*6236dae4SAndroid Build Coastguard Worker     len += Curl_dyn_len(&cwbuf->b);
149*6236dae4SAndroid Build Coastguard Worker     cwbuf = cwbuf->next;
150*6236dae4SAndroid Build Coastguard Worker   }
151*6236dae4SAndroid Build Coastguard Worker   return len;
152*6236dae4SAndroid Build Coastguard Worker }
153*6236dae4SAndroid Build Coastguard Worker 
cw_out_close(struct Curl_easy * data,struct Curl_cwriter * writer)154*6236dae4SAndroid Build Coastguard Worker static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer)
155*6236dae4SAndroid Build Coastguard Worker {
156*6236dae4SAndroid Build Coastguard Worker   struct cw_out_ctx *ctx = writer->ctx;
157*6236dae4SAndroid Build Coastguard Worker 
158*6236dae4SAndroid Build Coastguard Worker   (void)data;
159*6236dae4SAndroid Build Coastguard Worker   cw_out_bufs_free(ctx);
160*6236dae4SAndroid Build Coastguard Worker }
161*6236dae4SAndroid Build Coastguard Worker 
162*6236dae4SAndroid Build Coastguard Worker /**
163*6236dae4SAndroid Build Coastguard Worker  * Return the current curl_write_callback and user_data for the buf type
164*6236dae4SAndroid Build Coastguard Worker  */
cw_get_writefunc(struct Curl_easy * data,cw_out_type otype,curl_write_callback * pwcb,void ** pwcb_data,size_t * pmax_write,size_t * pmin_write)165*6236dae4SAndroid Build Coastguard Worker static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
166*6236dae4SAndroid Build Coastguard Worker                              curl_write_callback *pwcb, void **pwcb_data,
167*6236dae4SAndroid Build Coastguard Worker                              size_t *pmax_write, size_t *pmin_write)
168*6236dae4SAndroid Build Coastguard Worker {
169*6236dae4SAndroid Build Coastguard Worker   switch(otype) {
170*6236dae4SAndroid Build Coastguard Worker   case CW_OUT_BODY:
171*6236dae4SAndroid Build Coastguard Worker     *pwcb = data->set.fwrite_func;
172*6236dae4SAndroid Build Coastguard Worker     *pwcb_data = data->set.out;
173*6236dae4SAndroid Build Coastguard Worker     *pmax_write = CURL_MAX_WRITE_SIZE;
174*6236dae4SAndroid Build Coastguard Worker     /* if we ever want buffering of BODY output, we can set `min_write`
175*6236dae4SAndroid Build Coastguard Worker      * the preferred size. The default should always be to pass data
176*6236dae4SAndroid Build Coastguard Worker      * to the client as it comes without delay */
177*6236dae4SAndroid Build Coastguard Worker     *pmin_write = 0;
178*6236dae4SAndroid Build Coastguard Worker     break;
179*6236dae4SAndroid Build Coastguard Worker   case CW_OUT_HDS:
180*6236dae4SAndroid Build Coastguard Worker     *pwcb = data->set.fwrite_header ? data->set.fwrite_header :
181*6236dae4SAndroid Build Coastguard Worker              (data->set.writeheader ? data->set.fwrite_func : NULL);
182*6236dae4SAndroid Build Coastguard Worker     *pwcb_data = data->set.writeheader;
183*6236dae4SAndroid Build Coastguard Worker     *pmax_write = 0; /* do not chunk-write headers, write them as they are */
184*6236dae4SAndroid Build Coastguard Worker     *pmin_write = 0;
185*6236dae4SAndroid Build Coastguard Worker     break;
186*6236dae4SAndroid Build Coastguard Worker   default:
187*6236dae4SAndroid Build Coastguard Worker     *pwcb = NULL;
188*6236dae4SAndroid Build Coastguard Worker     *pwcb_data = NULL;
189*6236dae4SAndroid Build Coastguard Worker     *pmax_write = CURL_MAX_WRITE_SIZE;
190*6236dae4SAndroid Build Coastguard Worker     *pmin_write = 0;
191*6236dae4SAndroid Build Coastguard Worker   }
192*6236dae4SAndroid Build Coastguard Worker }
193*6236dae4SAndroid Build Coastguard Worker 
cw_out_ptr_flush(struct cw_out_ctx * ctx,struct Curl_easy * data,cw_out_type otype,bool flush_all,const char * buf,size_t blen,size_t * pconsumed)194*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
195*6236dae4SAndroid Build Coastguard Worker                                  struct Curl_easy *data,
196*6236dae4SAndroid Build Coastguard Worker                                  cw_out_type otype,
197*6236dae4SAndroid Build Coastguard Worker                                  bool flush_all,
198*6236dae4SAndroid Build Coastguard Worker                                  const char *buf, size_t blen,
199*6236dae4SAndroid Build Coastguard Worker                                  size_t *pconsumed)
200*6236dae4SAndroid Build Coastguard Worker {
201*6236dae4SAndroid Build Coastguard Worker   curl_write_callback wcb;
202*6236dae4SAndroid Build Coastguard Worker   void *wcb_data;
203*6236dae4SAndroid Build Coastguard Worker   size_t max_write, min_write;
204*6236dae4SAndroid Build Coastguard Worker   size_t wlen, nwritten;
205*6236dae4SAndroid Build Coastguard Worker 
206*6236dae4SAndroid Build Coastguard Worker   /* If we errored once, we do not invoke the client callback  again */
207*6236dae4SAndroid Build Coastguard Worker   if(ctx->errored)
208*6236dae4SAndroid Build Coastguard Worker     return CURLE_WRITE_ERROR;
209*6236dae4SAndroid Build Coastguard Worker 
210*6236dae4SAndroid Build Coastguard Worker   /* write callbacks may get NULLed by the client between calls. */
211*6236dae4SAndroid Build Coastguard Worker   cw_get_writefunc(data, otype, &wcb, &wcb_data, &max_write, &min_write);
212*6236dae4SAndroid Build Coastguard Worker   if(!wcb) {
213*6236dae4SAndroid Build Coastguard Worker     *pconsumed = blen;
214*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
215*6236dae4SAndroid Build Coastguard Worker   }
216*6236dae4SAndroid Build Coastguard Worker 
217*6236dae4SAndroid Build Coastguard Worker   *pconsumed = 0;
218*6236dae4SAndroid Build Coastguard Worker   while(blen && !ctx->paused) {
219*6236dae4SAndroid Build Coastguard Worker     if(!flush_all && blen < min_write)
220*6236dae4SAndroid Build Coastguard Worker       break;
221*6236dae4SAndroid Build Coastguard Worker     wlen = max_write ? CURLMIN(blen, max_write) : blen;
222*6236dae4SAndroid Build Coastguard Worker     Curl_set_in_callback(data, TRUE);
223*6236dae4SAndroid Build Coastguard Worker     nwritten = wcb((char *)buf, 1, wlen, wcb_data);
224*6236dae4SAndroid Build Coastguard Worker     Curl_set_in_callback(data, FALSE);
225*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
226*6236dae4SAndroid Build Coastguard Worker                    wlen, (otype == CW_OUT_BODY) ? "body" : "header",
227*6236dae4SAndroid Build Coastguard Worker                    nwritten);
228*6236dae4SAndroid Build Coastguard Worker     if(CURL_WRITEFUNC_PAUSE == nwritten) {
229*6236dae4SAndroid Build Coastguard Worker       if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
230*6236dae4SAndroid Build Coastguard Worker         /* Protocols that work without network cannot be paused. This is
231*6236dae4SAndroid Build Coastguard Worker            actually only FILE:// just now, and it cannot pause since the
232*6236dae4SAndroid Build Coastguard Worker            transfer is not done using the "normal" procedure. */
233*6236dae4SAndroid Build Coastguard Worker         failf(data, "Write callback asked for PAUSE when not supported");
234*6236dae4SAndroid Build Coastguard Worker         return CURLE_WRITE_ERROR;
235*6236dae4SAndroid Build Coastguard Worker       }
236*6236dae4SAndroid Build Coastguard Worker       /* mark the connection as RECV paused */
237*6236dae4SAndroid Build Coastguard Worker       data->req.keepon |= KEEP_RECV_PAUSE;
238*6236dae4SAndroid Build Coastguard Worker       ctx->paused = TRUE;
239*6236dae4SAndroid Build Coastguard Worker       CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
240*6236dae4SAndroid Build Coastguard Worker       break;
241*6236dae4SAndroid Build Coastguard Worker     }
242*6236dae4SAndroid Build Coastguard Worker     else if(CURL_WRITEFUNC_ERROR == nwritten) {
243*6236dae4SAndroid Build Coastguard Worker       failf(data, "client returned ERROR on write of %zu bytes", wlen);
244*6236dae4SAndroid Build Coastguard Worker       return CURLE_WRITE_ERROR;
245*6236dae4SAndroid Build Coastguard Worker     }
246*6236dae4SAndroid Build Coastguard Worker     else if(nwritten != wlen) {
247*6236dae4SAndroid Build Coastguard Worker       failf(data, "Failure writing output to destination, "
248*6236dae4SAndroid Build Coastguard Worker             "passed %zu returned %zd", wlen, nwritten);
249*6236dae4SAndroid Build Coastguard Worker       return CURLE_WRITE_ERROR;
250*6236dae4SAndroid Build Coastguard Worker     }
251*6236dae4SAndroid Build Coastguard Worker     *pconsumed += nwritten;
252*6236dae4SAndroid Build Coastguard Worker     blen -= nwritten;
253*6236dae4SAndroid Build Coastguard Worker     buf += nwritten;
254*6236dae4SAndroid Build Coastguard Worker   }
255*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
256*6236dae4SAndroid Build Coastguard Worker }
257*6236dae4SAndroid Build Coastguard Worker 
cw_out_buf_flush(struct cw_out_ctx * ctx,struct Curl_easy * data,struct cw_out_buf * cwbuf,bool flush_all)258*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx,
259*6236dae4SAndroid Build Coastguard Worker                                  struct Curl_easy *data,
260*6236dae4SAndroid Build Coastguard Worker                                  struct cw_out_buf *cwbuf,
261*6236dae4SAndroid Build Coastguard Worker                                  bool flush_all)
262*6236dae4SAndroid Build Coastguard Worker {
263*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
264*6236dae4SAndroid Build Coastguard Worker 
265*6236dae4SAndroid Build Coastguard Worker   if(Curl_dyn_len(&cwbuf->b)) {
266*6236dae4SAndroid Build Coastguard Worker     size_t consumed;
267*6236dae4SAndroid Build Coastguard Worker 
268*6236dae4SAndroid Build Coastguard Worker     result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all,
269*6236dae4SAndroid Build Coastguard Worker                               Curl_dyn_ptr(&cwbuf->b),
270*6236dae4SAndroid Build Coastguard Worker                               Curl_dyn_len(&cwbuf->b),
271*6236dae4SAndroid Build Coastguard Worker                               &consumed);
272*6236dae4SAndroid Build Coastguard Worker     if(result)
273*6236dae4SAndroid Build Coastguard Worker       return result;
274*6236dae4SAndroid Build Coastguard Worker 
275*6236dae4SAndroid Build Coastguard Worker     if(consumed) {
276*6236dae4SAndroid Build Coastguard Worker       if(consumed == Curl_dyn_len(&cwbuf->b)) {
277*6236dae4SAndroid Build Coastguard Worker         Curl_dyn_free(&cwbuf->b);
278*6236dae4SAndroid Build Coastguard Worker       }
279*6236dae4SAndroid Build Coastguard Worker       else {
280*6236dae4SAndroid Build Coastguard Worker         DEBUGASSERT(consumed < Curl_dyn_len(&cwbuf->b));
281*6236dae4SAndroid Build Coastguard Worker         result = Curl_dyn_tail(&cwbuf->b, Curl_dyn_len(&cwbuf->b) - consumed);
282*6236dae4SAndroid Build Coastguard Worker         if(result)
283*6236dae4SAndroid Build Coastguard Worker           return result;
284*6236dae4SAndroid Build Coastguard Worker       }
285*6236dae4SAndroid Build Coastguard Worker     }
286*6236dae4SAndroid Build Coastguard Worker   }
287*6236dae4SAndroid Build Coastguard Worker   return result;
288*6236dae4SAndroid Build Coastguard Worker }
289*6236dae4SAndroid Build Coastguard Worker 
cw_out_flush_chain(struct cw_out_ctx * ctx,struct Curl_easy * data,struct cw_out_buf ** pcwbuf,bool flush_all)290*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
291*6236dae4SAndroid Build Coastguard Worker                                    struct Curl_easy *data,
292*6236dae4SAndroid Build Coastguard Worker                                    struct cw_out_buf **pcwbuf,
293*6236dae4SAndroid Build Coastguard Worker                                    bool flush_all)
294*6236dae4SAndroid Build Coastguard Worker {
295*6236dae4SAndroid Build Coastguard Worker   struct cw_out_buf *cwbuf = *pcwbuf;
296*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
297*6236dae4SAndroid Build Coastguard Worker 
298*6236dae4SAndroid Build Coastguard Worker   if(!cwbuf)
299*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
300*6236dae4SAndroid Build Coastguard Worker   if(ctx->paused)
301*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
302*6236dae4SAndroid Build Coastguard Worker 
303*6236dae4SAndroid Build Coastguard Worker   /* write the end of the chain until it blocks or gets empty */
304*6236dae4SAndroid Build Coastguard Worker   while(cwbuf->next) {
305*6236dae4SAndroid Build Coastguard Worker     struct cw_out_buf **plast = &cwbuf->next;
306*6236dae4SAndroid Build Coastguard Worker     while((*plast)->next)
307*6236dae4SAndroid Build Coastguard Worker       plast = &(*plast)->next;
308*6236dae4SAndroid Build Coastguard Worker     result = cw_out_flush_chain(ctx, data, plast, flush_all);
309*6236dae4SAndroid Build Coastguard Worker     if(result)
310*6236dae4SAndroid Build Coastguard Worker       return result;
311*6236dae4SAndroid Build Coastguard Worker     if(*plast) {
312*6236dae4SAndroid Build Coastguard Worker       /* could not write last, paused again? */
313*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(ctx->paused);
314*6236dae4SAndroid Build Coastguard Worker       return CURLE_OK;
315*6236dae4SAndroid Build Coastguard Worker     }
316*6236dae4SAndroid Build Coastguard Worker   }
317*6236dae4SAndroid Build Coastguard Worker 
318*6236dae4SAndroid Build Coastguard Worker   result = cw_out_buf_flush(ctx, data, cwbuf, flush_all);
319*6236dae4SAndroid Build Coastguard Worker   if(result)
320*6236dae4SAndroid Build Coastguard Worker     return result;
321*6236dae4SAndroid Build Coastguard Worker   if(!Curl_dyn_len(&cwbuf->b)) {
322*6236dae4SAndroid Build Coastguard Worker     cw_out_buf_free(cwbuf);
323*6236dae4SAndroid Build Coastguard Worker     *pcwbuf = NULL;
324*6236dae4SAndroid Build Coastguard Worker   }
325*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
326*6236dae4SAndroid Build Coastguard Worker }
327*6236dae4SAndroid Build Coastguard Worker 
cw_out_append(struct cw_out_ctx * ctx,cw_out_type otype,const char * buf,size_t blen)328*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_append(struct cw_out_ctx *ctx,
329*6236dae4SAndroid Build Coastguard Worker                               cw_out_type otype,
330*6236dae4SAndroid Build Coastguard Worker                               const char *buf, size_t blen)
331*6236dae4SAndroid Build Coastguard Worker {
332*6236dae4SAndroid Build Coastguard Worker   if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER)
333*6236dae4SAndroid Build Coastguard Worker     return CURLE_TOO_LARGE;
334*6236dae4SAndroid Build Coastguard Worker 
335*6236dae4SAndroid Build Coastguard Worker   /* if we do not have a buffer, or it is of another type, make a new one.
336*6236dae4SAndroid Build Coastguard Worker    * And for CW_OUT_HDS always make a new one, so we "replay" headers
337*6236dae4SAndroid Build Coastguard Worker    * exactly as they came in */
338*6236dae4SAndroid Build Coastguard Worker   if(!ctx->buf || (ctx->buf->type != otype) || (otype == CW_OUT_HDS)) {
339*6236dae4SAndroid Build Coastguard Worker     struct cw_out_buf *cwbuf = cw_out_buf_create(otype);
340*6236dae4SAndroid Build Coastguard Worker     if(!cwbuf)
341*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
342*6236dae4SAndroid Build Coastguard Worker     cwbuf->next = ctx->buf;
343*6236dae4SAndroid Build Coastguard Worker     ctx->buf = cwbuf;
344*6236dae4SAndroid Build Coastguard Worker   }
345*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(ctx->buf && (ctx->buf->type == otype));
346*6236dae4SAndroid Build Coastguard Worker   return Curl_dyn_addn(&ctx->buf->b, buf, blen);
347*6236dae4SAndroid Build Coastguard Worker }
348*6236dae4SAndroid Build Coastguard Worker 
cw_out_do_write(struct cw_out_ctx * ctx,struct Curl_easy * data,cw_out_type otype,bool flush_all,const char * buf,size_t blen)349*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
350*6236dae4SAndroid Build Coastguard Worker                                 struct Curl_easy *data,
351*6236dae4SAndroid Build Coastguard Worker                                 cw_out_type otype,
352*6236dae4SAndroid Build Coastguard Worker                                 bool flush_all,
353*6236dae4SAndroid Build Coastguard Worker                                 const char *buf, size_t blen)
354*6236dae4SAndroid Build Coastguard Worker {
355*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
356*6236dae4SAndroid Build Coastguard Worker 
357*6236dae4SAndroid Build Coastguard Worker   /* if we have buffered data and it is a different type than what
358*6236dae4SAndroid Build Coastguard Worker    * we are writing now, try to flush all */
359*6236dae4SAndroid Build Coastguard Worker   if(ctx->buf && ctx->buf->type != otype) {
360*6236dae4SAndroid Build Coastguard Worker     result = cw_out_flush_chain(ctx, data, &ctx->buf, TRUE);
361*6236dae4SAndroid Build Coastguard Worker     if(result)
362*6236dae4SAndroid Build Coastguard Worker       goto out;
363*6236dae4SAndroid Build Coastguard Worker   }
364*6236dae4SAndroid Build Coastguard Worker 
365*6236dae4SAndroid Build Coastguard Worker   if(ctx->buf) {
366*6236dae4SAndroid Build Coastguard Worker     /* still have buffered data, append and flush */
367*6236dae4SAndroid Build Coastguard Worker     result = cw_out_append(ctx, otype, buf, blen);
368*6236dae4SAndroid Build Coastguard Worker     if(result)
369*6236dae4SAndroid Build Coastguard Worker       return result;
370*6236dae4SAndroid Build Coastguard Worker     result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
371*6236dae4SAndroid Build Coastguard Worker     if(result)
372*6236dae4SAndroid Build Coastguard Worker       goto out;
373*6236dae4SAndroid Build Coastguard Worker   }
374*6236dae4SAndroid Build Coastguard Worker   else {
375*6236dae4SAndroid Build Coastguard Worker     /* nothing buffered, try direct write */
376*6236dae4SAndroid Build Coastguard Worker     size_t consumed;
377*6236dae4SAndroid Build Coastguard Worker     result = cw_out_ptr_flush(ctx, data, otype, flush_all,
378*6236dae4SAndroid Build Coastguard Worker                               buf, blen, &consumed);
379*6236dae4SAndroid Build Coastguard Worker     if(result)
380*6236dae4SAndroid Build Coastguard Worker       return result;
381*6236dae4SAndroid Build Coastguard Worker     if(consumed < blen) {
382*6236dae4SAndroid Build Coastguard Worker       /* did not write all, append the rest */
383*6236dae4SAndroid Build Coastguard Worker       result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
384*6236dae4SAndroid Build Coastguard Worker       if(result)
385*6236dae4SAndroid Build Coastguard Worker         goto out;
386*6236dae4SAndroid Build Coastguard Worker     }
387*6236dae4SAndroid Build Coastguard Worker   }
388*6236dae4SAndroid Build Coastguard Worker 
389*6236dae4SAndroid Build Coastguard Worker out:
390*6236dae4SAndroid Build Coastguard Worker   if(result) {
391*6236dae4SAndroid Build Coastguard Worker     /* We do not want to invoked client callbacks a second time after
392*6236dae4SAndroid Build Coastguard Worker      * encountering an error. See issue #13337 */
393*6236dae4SAndroid Build Coastguard Worker     ctx->errored = TRUE;
394*6236dae4SAndroid Build Coastguard Worker     cw_out_bufs_free(ctx);
395*6236dae4SAndroid Build Coastguard Worker   }
396*6236dae4SAndroid Build Coastguard Worker   return result;
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker 
cw_out_write(struct Curl_easy * data,struct Curl_cwriter * writer,int type,const char * buf,size_t blen)399*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_write(struct Curl_easy *data,
400*6236dae4SAndroid Build Coastguard Worker                              struct Curl_cwriter *writer, int type,
401*6236dae4SAndroid Build Coastguard Worker                              const char *buf, size_t blen)
402*6236dae4SAndroid Build Coastguard Worker {
403*6236dae4SAndroid Build Coastguard Worker   struct cw_out_ctx *ctx = writer->ctx;
404*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
405*6236dae4SAndroid Build Coastguard Worker   bool flush_all = !!(type & CLIENTWRITE_EOS);
406*6236dae4SAndroid Build Coastguard Worker 
407*6236dae4SAndroid Build Coastguard Worker   if((type & CLIENTWRITE_BODY) ||
408*6236dae4SAndroid Build Coastguard Worker      ((type & CLIENTWRITE_HEADER) && data->set.include_header)) {
409*6236dae4SAndroid Build Coastguard Worker     result = cw_out_do_write(ctx, data, CW_OUT_BODY, flush_all, buf, blen);
410*6236dae4SAndroid Build Coastguard Worker     if(result)
411*6236dae4SAndroid Build Coastguard Worker       return result;
412*6236dae4SAndroid Build Coastguard Worker   }
413*6236dae4SAndroid Build Coastguard Worker 
414*6236dae4SAndroid Build Coastguard Worker   if(type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) {
415*6236dae4SAndroid Build Coastguard Worker     result = cw_out_do_write(ctx, data, CW_OUT_HDS, flush_all, buf, blen);
416*6236dae4SAndroid Build Coastguard Worker     if(result)
417*6236dae4SAndroid Build Coastguard Worker       return result;
418*6236dae4SAndroid Build Coastguard Worker   }
419*6236dae4SAndroid Build Coastguard Worker 
420*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
421*6236dae4SAndroid Build Coastguard Worker }
422*6236dae4SAndroid Build Coastguard Worker 
Curl_cw_out_is_paused(struct Curl_easy * data)423*6236dae4SAndroid Build Coastguard Worker bool Curl_cw_out_is_paused(struct Curl_easy *data)
424*6236dae4SAndroid Build Coastguard Worker {
425*6236dae4SAndroid Build Coastguard Worker   struct Curl_cwriter *cw_out;
426*6236dae4SAndroid Build Coastguard Worker   struct cw_out_ctx *ctx;
427*6236dae4SAndroid Build Coastguard Worker 
428*6236dae4SAndroid Build Coastguard Worker   cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
429*6236dae4SAndroid Build Coastguard Worker   if(!cw_out)
430*6236dae4SAndroid Build Coastguard Worker     return FALSE;
431*6236dae4SAndroid Build Coastguard Worker 
432*6236dae4SAndroid Build Coastguard Worker   ctx = (struct cw_out_ctx *)cw_out;
433*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused ? "" : " not");
434*6236dae4SAndroid Build Coastguard Worker   return ctx->paused;
435*6236dae4SAndroid Build Coastguard Worker }
436*6236dae4SAndroid Build Coastguard Worker 
cw_out_flush(struct Curl_easy * data,bool unpause,bool flush_all)437*6236dae4SAndroid Build Coastguard Worker static CURLcode cw_out_flush(struct Curl_easy *data,
438*6236dae4SAndroid Build Coastguard Worker                              bool unpause, bool flush_all)
439*6236dae4SAndroid Build Coastguard Worker {
440*6236dae4SAndroid Build Coastguard Worker   struct Curl_cwriter *cw_out;
441*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
442*6236dae4SAndroid Build Coastguard Worker 
443*6236dae4SAndroid Build Coastguard Worker   cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
444*6236dae4SAndroid Build Coastguard Worker   if(cw_out) {
445*6236dae4SAndroid Build Coastguard Worker     struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
446*6236dae4SAndroid Build Coastguard Worker     if(ctx->errored)
447*6236dae4SAndroid Build Coastguard Worker       return CURLE_WRITE_ERROR;
448*6236dae4SAndroid Build Coastguard Worker     if(unpause && ctx->paused)
449*6236dae4SAndroid Build Coastguard Worker       ctx->paused = FALSE;
450*6236dae4SAndroid Build Coastguard Worker     if(ctx->paused)
451*6236dae4SAndroid Build Coastguard Worker       return CURLE_OK;  /* not doing it */
452*6236dae4SAndroid Build Coastguard Worker 
453*6236dae4SAndroid Build Coastguard Worker     result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
454*6236dae4SAndroid Build Coastguard Worker     if(result) {
455*6236dae4SAndroid Build Coastguard Worker       ctx->errored = TRUE;
456*6236dae4SAndroid Build Coastguard Worker       cw_out_bufs_free(ctx);
457*6236dae4SAndroid Build Coastguard Worker       return result;
458*6236dae4SAndroid Build Coastguard Worker     }
459*6236dae4SAndroid Build Coastguard Worker   }
460*6236dae4SAndroid Build Coastguard Worker   return result;
461*6236dae4SAndroid Build Coastguard Worker }
462*6236dae4SAndroid Build Coastguard Worker 
Curl_cw_out_unpause(struct Curl_easy * data)463*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
464*6236dae4SAndroid Build Coastguard Worker {
465*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_WRITE(data, "cw-out unpause");
466*6236dae4SAndroid Build Coastguard Worker   return cw_out_flush(data, TRUE, FALSE);
467*6236dae4SAndroid Build Coastguard Worker }
468*6236dae4SAndroid Build Coastguard Worker 
Curl_cw_out_done(struct Curl_easy * data)469*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cw_out_done(struct Curl_easy *data)
470*6236dae4SAndroid Build Coastguard Worker {
471*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_WRITE(data, "cw-out done");
472*6236dae4SAndroid Build Coastguard Worker   return cw_out_flush(data, FALSE, TRUE);
473*6236dae4SAndroid Build Coastguard Worker }
474