Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/curl/lib/sendf.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#ifdef HAVE_NETINET_IN_H
28
#include <netinet/in.h>
29
#endif
30
31
#ifdef HAVE_LINUX_TCP_H
32
#include <linux/tcp.h>
33
#elif defined(HAVE_NETINET_TCP_H)
34
#include <netinet/tcp.h>
35
#endif
36
37
#include <curl/curl.h>
38
39
#include "urldata.h"
40
#include "sendf.h"
41
#include "cfilters.h"
42
#include "connect.h"
43
#include "content_encoding.h"
44
#include "vtls/vtls.h"
45
#include "vssh/ssh.h"
46
#include "easyif.h"
47
#include "multiif.h"
48
#include "strerror.h"
49
#include "select.h"
50
#include "strdup.h"
51
#include "http2.h"
52
#include "headers.h"
53
#include "progress.h"
54
#include "ws.h"
55
56
/* The last 3 #include files should be in this order */
57
#include "curl_printf.h"
58
#include "curl_memory.h"
59
#include "memdebug.h"
60
61
62
static CURLcode do_init_stack(struct Curl_easy *data);
63
64
/*
65
 * Curl_nwrite() is an internal write function that sends data to the
66
 * server. Works with a socket index for the connection.
67
 *
68
 * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
69
 * (*nwritten == 0). Otherwise we return regular CURLcode value.
70
 */
71
CURLcode Curl_nwrite(struct Curl_easy *data,
72
                     int sockindex,
73
                     const void *buf,
74
                     size_t blen,
75
                     ssize_t *pnwritten)
76
0
{
77
0
  ssize_t nwritten;
78
0
  CURLcode result = CURLE_OK;
79
0
  struct connectdata *conn;
80
81
0
  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
82
0
  DEBUGASSERT(pnwritten);
83
0
  DEBUGASSERT(data);
84
0
  DEBUGASSERT(data->conn);
85
0
  conn = data->conn;
86
#ifdef CURLDEBUG
87
  {
88
    /* Allow debug builds to override this logic to force short sends
89
    */
90
    char *p = getenv("CURL_SMALLSENDS");
91
    if(p) {
92
      size_t altsize = (size_t)strtoul(p, NULL, 10);
93
      if(altsize)
94
        blen = CURLMIN(blen, altsize);
95
    }
96
  }
97
#endif
98
0
  nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
99
0
  if(result == CURLE_AGAIN) {
100
0
    nwritten = 0;
101
0
    result = CURLE_OK;
102
0
  }
103
0
  else if(result) {
104
0
    nwritten = -1; /* make sure */
105
0
  }
106
0
  else {
107
0
    DEBUGASSERT(nwritten >= 0);
108
0
  }
109
110
0
  *pnwritten = nwritten;
111
0
  return result;
112
0
}
113
114
/*
115
 * Curl_write() is an internal write function that sends data to the
116
 * server. Works with plain sockets, SCP, SSL or kerberos.
117
 *
118
 * If the write would block (CURLE_AGAIN), we return CURLE_OK and
119
 * (*written == 0). Otherwise we return regular CURLcode value.
120
 */
121
CURLcode Curl_write(struct Curl_easy *data,
122
                    curl_socket_t sockfd,
123
                    const void *mem,
124
                    size_t len,
125
                    ssize_t *written)
126
0
{
127
0
  struct connectdata *conn;
128
0
  int num;
129
130
0
  DEBUGASSERT(data);
131
0
  DEBUGASSERT(data->conn);
132
0
  conn = data->conn;
133
0
  num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
134
0
  return Curl_nwrite(data, num, mem, len, written);
135
0
}
136
137
static CURLcode pausewrite(struct Curl_easy *data,
138
                           int type, /* what type of data */
139
                           bool paused_body,
140
                           const char *ptr,
141
                           size_t len)
142
0
{
143
  /* signalled to pause sending on this connection, but since we have data
144
     we want to send we need to dup it to save a copy for when the sending
145
     is again enabled */
146
0
  struct SingleRequest *k = &data->req;
147
0
  struct UrlState *s = &data->state;
148
0
  unsigned int i;
149
0
  bool newtype = TRUE;
150
151
0
  Curl_conn_ev_data_pause(data, TRUE);
152
153
0
  if(s->tempcount) {
154
0
    for(i = 0; i< s->tempcount; i++) {
155
0
      if(s->tempwrite[i].type == type &&
156
0
         !!s->tempwrite[i].paused_body == !!paused_body) {
157
        /* data for this type exists */
158
0
        newtype = FALSE;
159
0
        break;
160
0
      }
161
0
    }
162
0
    DEBUGASSERT(i < 3);
163
0
    if(i >= 3)
164
      /* There are more types to store than what fits: very bad */
165
0
      return CURLE_OUT_OF_MEMORY;
166
0
  }
167
0
  else
168
0
    i = 0;
169
170
0
  if(newtype) {
171
    /* store this information in the state struct for later use */
172
0
    Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
173
0
    s->tempwrite[i].type = type;
174
0
    s->tempwrite[i].paused_body = paused_body;
175
0
    s->tempcount++;
176
0
  }
177
178
0
  if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
179
0
    return CURLE_OUT_OF_MEMORY;
180
181
  /* mark the connection as RECV paused */
182
0
  k->keepon |= KEEP_RECV_PAUSE;
183
184
0
  return CURLE_OK;
185
0
}
186
187
188
/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
189
 * client write callback(s) and takes care of pause requests from the
190
 * callbacks.
191
 */
192
static CURLcode chop_write(struct Curl_easy *data,
193
                           int type,
194
                           bool skip_body_write,
195
                           char *optr,
196
                           size_t olen)
197
0
{
198
0
  struct connectdata *conn = data->conn;
199
0
  curl_write_callback writeheader = NULL;
200
0
  curl_write_callback writebody = NULL;
201
0
  char *ptr = optr;
202
0
  size_t len = olen;
203
0
  void *writebody_ptr = data->set.out;
204
205
0
  if(!len)
206
0
    return CURLE_OK;
207
208
  /* If reading is paused, append this data to the already held data for this
209
     type. */
210
0
  if(data->req.keepon & KEEP_RECV_PAUSE)
211
0
    return pausewrite(data, type, !skip_body_write, ptr, len);
212
213
  /* Determine the callback(s) to use. */
214
0
  if(!skip_body_write &&
215
0
     ((type & CLIENTWRITE_BODY) ||
216
0
      ((type & CLIENTWRITE_HEADER) && data->set.include_header))) {
217
0
    writebody = data->set.fwrite_func;
218
0
  }
219
0
  if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) &&
220
0
     (data->set.fwrite_header || data->set.writeheader)) {
221
    /*
222
     * Write headers to the same callback or to the especially setup
223
     * header callback function (added after version 7.7.1).
224
     */
225
0
    writeheader =
226
0
      data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
227
0
  }
228
229
  /* Chop data, write chunks. */
230
0
  while(len) {
231
0
    size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
232
233
0
    if(writebody) {
234
0
      size_t wrote;
235
0
      Curl_set_in_callback(data, true);
236
0
      wrote = writebody(ptr, 1, chunklen, writebody_ptr);
237
0
      Curl_set_in_callback(data, false);
238
239
0
      if(CURL_WRITEFUNC_PAUSE == wrote) {
240
0
        if(conn->handler->flags & PROTOPT_NONETWORK) {
241
          /* Protocols that work without network cannot be paused. This is
242
             actually only FILE:// just now, and it can't pause since the
243
             transfer isn't done using the "normal" procedure. */
244
0
          failf(data, "Write callback asked for PAUSE when not supported");
245
0
          return CURLE_WRITE_ERROR;
246
0
        }
247
0
        return pausewrite(data, type, TRUE, ptr, len);
248
0
      }
249
0
      if(wrote != chunklen) {
250
0
        failf(data, "Failure writing output to destination");
251
0
        return CURLE_WRITE_ERROR;
252
0
      }
253
0
    }
254
255
0
    ptr += chunklen;
256
0
    len -= chunklen;
257
0
  }
258
259
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
260
  /* HTTP header, but not status-line */
261
0
  if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
262
0
     (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
263
0
    unsigned char htype = (unsigned char)
264
0
      (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
265
0
       (type & CLIENTWRITE_1XX ? CURLH_1XX :
266
0
        (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
267
0
         CURLH_HEADER)));
268
0
    CURLcode result = Curl_headers_push(data, optr, htype);
269
0
    if(result)
270
0
      return result;
271
0
  }
272
0
#endif
273
274
0
  if(writeheader) {
275
0
    size_t wrote;
276
277
0
    Curl_set_in_callback(data, true);
278
0
    wrote = writeheader(optr, 1, olen, data->set.writeheader);
279
0
    Curl_set_in_callback(data, false);
280
281
0
    if(CURL_WRITEFUNC_PAUSE == wrote)
282
0
      return pausewrite(data, type, FALSE, optr, olen);
283
0
    if(wrote != olen) {
284
0
      failf(data, "Failed writing header");
285
0
      return CURLE_WRITE_ERROR;
286
0
    }
287
0
  }
288
289
0
  return CURLE_OK;
290
0
}
291
292
293
/* Curl_client_write() sends data to the write callback(s)
294
295
   The bit pattern defines to what "streams" to write to. Body and/or header.
296
   The defines are in sendf.h of course.
297
 */
298
CURLcode Curl_client_write(struct Curl_easy *data,
299
                           int type, char *buf, size_t blen)
300
0
{
301
0
  CURLcode result;
302
303
  /* it is one of those, at least */
304
0
  DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
305
  /* BODY is only BODY (with optional EOS) */
306
0
  DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
307
0
              ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
308
  /* INFO is only INFO (with optional EOS) */
309
0
  DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
310
0
              ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
311
312
0
  if(!data->req.writer_stack) {
313
0
    result = do_init_stack(data);
314
0
    if(result)
315
0
      return result;
316
0
    DEBUGASSERT(data->req.writer_stack);
317
0
  }
318
319
0
  return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
320
0
}
321
322
CURLcode Curl_client_unpause(struct Curl_easy *data)
323
0
{
324
0
  CURLcode result = CURLE_OK;
325
326
0
  if(data->state.tempcount) {
327
    /* there are buffers for sending that can be delivered as the receive
328
       pausing is lifted! */
329
0
    unsigned int i;
330
0
    unsigned int count = data->state.tempcount;
331
0
    struct tempbuf writebuf[3]; /* there can only be three */
332
333
    /* copy the structs to allow for immediate re-pausing */
334
0
    for(i = 0; i < data->state.tempcount; i++) {
335
0
      writebuf[i] = data->state.tempwrite[i];
336
0
      Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER);
337
0
    }
338
0
    data->state.tempcount = 0;
339
340
0
    for(i = 0; i < count; i++) {
341
      /* even if one function returns error, this loops through and frees
342
         all buffers */
343
0
      if(!result)
344
0
        result = chop_write(data, writebuf[i].type,
345
0
                            !writebuf[i].paused_body,
346
0
                            Curl_dyn_ptr(&writebuf[i].b),
347
0
                            Curl_dyn_len(&writebuf[i].b));
348
0
      Curl_dyn_free(&writebuf[i].b);
349
0
    }
350
0
  }
351
0
  return result;
352
0
}
353
354
void Curl_client_cleanup(struct Curl_easy *data)
355
0
{
356
0
  struct Curl_cwriter *writer = data->req.writer_stack;
357
0
  size_t i;
358
359
0
  while(writer) {
360
0
    data->req.writer_stack = writer->next;
361
0
    writer->cwt->do_close(data, writer);
362
0
    free(writer);
363
0
    writer = data->req.writer_stack;
364
0
  }
365
366
0
  for(i = 0; i < data->state.tempcount; i++) {
367
0
    Curl_dyn_free(&data->state.tempwrite[i].b);
368
0
  }
369
0
  data->state.tempcount = 0;
370
0
  data->req.bytecount = 0;
371
0
  data->req.headerline = 0;
372
0
}
373
374
/* Write data using an unencoding writer stack. "nbytes" is not
375
   allowed to be 0. */
376
CURLcode Curl_cwriter_write(struct Curl_easy *data,
377
                             struct Curl_cwriter *writer, int type,
378
                             const char *buf, size_t nbytes)
379
0
{
380
0
  if(!writer)
381
0
    return CURLE_WRITE_ERROR;
382
0
  return writer->cwt->do_write(data, writer, type, buf, nbytes);
383
0
}
384
385
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
386
                               struct Curl_cwriter *writer)
387
0
{
388
0
  (void)data;
389
0
  (void)writer;
390
0
  return CURLE_OK;
391
0
}
392
393
CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
394
                                struct Curl_cwriter *writer, int type,
395
                                const char *buf, size_t nbytes)
396
0
{
397
0
  return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
398
0
}
399
400
void Curl_cwriter_def_close(struct Curl_easy *data,
401
                            struct Curl_cwriter *writer)
402
0
{
403
0
  (void) data;
404
0
  (void) writer;
405
0
}
406
407
/* Real client writer to installed callbacks. */
408
static CURLcode cw_client_write(struct Curl_easy *data,
409
                                struct Curl_cwriter *writer, int type,
410
                                const char *buf, size_t nbytes)
411
0
{
412
0
  (void)writer;
413
0
  if(!nbytes)
414
0
    return CURLE_OK;
415
0
  return chop_write(data, type, FALSE, (char *)buf, nbytes);
416
0
}
417
418
static const struct Curl_cwtype cw_client = {
419
  "client",
420
  NULL,
421
  Curl_cwriter_def_init,
422
  cw_client_write,
423
  Curl_cwriter_def_close,
424
  sizeof(struct Curl_cwriter)
425
};
426
427
static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
428
0
{
429
0
  if(limit != -1) {
430
    /* How much more are we allowed to write? */
431
0
    curl_off_t remain_diff;
432
0
    remain_diff = limit - data->req.bytecount;
433
0
    if(remain_diff < 0) {
434
      /* already written too much! */
435
0
      return 0;
436
0
    }
437
#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
438
    else if(remain_diff > SSIZE_T_MAX) {
439
      return SIZE_T_MAX;
440
    }
441
#endif
442
0
    else {
443
0
      return (size_t)remain_diff;
444
0
    }
445
0
  }
446
0
  return SIZE_T_MAX;
447
0
}
448
449
/* Download client writer in phase CURL_CW_PROTOCOL that
450
 * sees the "real" download body data. */
451
static CURLcode cw_download_write(struct Curl_easy *data,
452
                                  struct Curl_cwriter *writer, int type,
453
                                  const char *buf, size_t nbytes)
454
0
{
455
0
  CURLcode result;
456
0
  size_t nwrite, excess_len = 0;
457
458
0
  if(!(type & CLIENTWRITE_BODY)) {
459
0
    if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
460
0
      return CURLE_OK;
461
0
    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
462
0
  }
463
464
0
  if(!data->req.bytecount) {
465
0
    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
466
0
    if(data->req.exp100 > EXP100_SEND_DATA)
467
      /* set time stamp to compare with when waiting for the 100 */
468
0
      data->req.start100 = Curl_now();
469
0
  }
470
471
  /* Here, we deal with REAL BODY bytes. All filtering and transfer
472
   * encodings have been applied and only the true content, e.g. BODY,
473
   * bytes are passed here.
474
   * This allows us to check sizes, update stats, etc. independent
475
   * from the protocol in play. */
476
477
0
  if(data->req.no_body && nbytes > 0) {
478
    /* BODY arrives although we want none, bail out */
479
0
    streamclose(data->conn, "ignoring body");
480
0
    DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
481
0
                 nbytes));
482
0
    data->req.download_done = TRUE;
483
0
    if(data->info.header_size)
484
      /* if headers have been received, this is fine */
485
0
      return CURLE_OK;
486
0
    return CURLE_WEIRD_SERVER_REPLY;
487
0
  }
488
489
  /* Determine if we see any bytes in excess to what is allowed.
490
   * We write the allowed bytes and handle excess further below.
491
   * This gives deterministic BODY writes on varying buffer receive
492
   * lengths. */
493
0
  nwrite = nbytes;
494
0
  if(-1 != data->req.maxdownload) {
495
0
    size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
496
0
    if(nwrite > wmax) {
497
0
      excess_len = nbytes - wmax;
498
0
      nwrite = wmax;
499
0
    }
500
501
0
    if(nwrite == wmax) {
502
0
      data->req.download_done = TRUE;
503
0
    }
504
0
  }
505
506
  /* Error on too large filesize is handled below, after writing
507
   * the permitted bytes */
508
0
  if(data->set.max_filesize) {
509
0
    size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
510
0
    if(nwrite > wmax) {
511
0
      nwrite = wmax;
512
0
    }
513
0
  }
514
515
  /* Update stats, write and report progress */
516
0
  data->req.bytecount += nwrite;
517
0
  ++data->req.bodywrites;
518
0
  if(!data->req.ignorebody && nwrite) {
519
0
    result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
520
0
    if(result)
521
0
      return result;
522
0
  }
523
0
  result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
524
0
  if(result)
525
0
    return result;
526
527
0
  if(excess_len) {
528
0
    if(!data->req.ignorebody) {
529
0
      infof(data,
530
0
            "Excess found writing body:"
531
0
            " excess = %zu"
532
0
            ", size = %" CURL_FORMAT_CURL_OFF_T
533
0
            ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
534
0
            ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
535
0
            excess_len, data->req.size, data->req.maxdownload,
536
0
            data->req.bytecount);
537
0
      connclose(data->conn, "excess found in a read");
538
0
    }
539
0
  }
540
0
  else if(nwrite < nbytes) {
541
0
    failf(data, "Exceeded the maximum allowed file size "
542
0
          "(%" CURL_FORMAT_CURL_OFF_T ") with %"
543
0
          CURL_FORMAT_CURL_OFF_T " bytes",
544
0
          data->set.max_filesize, data->req.bytecount);
545
0
    return CURLE_FILESIZE_EXCEEDED;
546
0
  }
547
548
0
  return CURLE_OK;
549
0
}
550
551
static const struct Curl_cwtype cw_download = {
552
  "download",
553
  NULL,
554
  Curl_cwriter_def_init,
555
  cw_download_write,
556
  Curl_cwriter_def_close,
557
  sizeof(struct Curl_cwriter)
558
};
559
560
/* RAW client writer in phase CURL_CW_RAW that
561
 * enabled tracing of raw data. */
562
static CURLcode cw_raw_write(struct Curl_easy *data,
563
                             struct Curl_cwriter *writer, int type,
564
                             const char *buf, size_t nbytes)
565
0
{
566
0
  if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
567
0
    Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
568
0
  }
569
0
  return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
570
0
}
571
572
static const struct Curl_cwtype cw_raw = {
573
  "raw",
574
  NULL,
575
  Curl_cwriter_def_init,
576
  cw_raw_write,
577
  Curl_cwriter_def_close,
578
  sizeof(struct Curl_cwriter)
579
};
580
581
/* Create an unencoding writer stage using the given handler. */
582
CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
583
                                   struct Curl_easy *data,
584
                                   const struct Curl_cwtype *cwt,
585
                                   Curl_cwriter_phase phase)
586
0
{
587
0
  struct Curl_cwriter *writer;
588
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
589
590
0
  DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
591
0
  writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size);
592
0
  if(!writer)
593
0
    goto out;
594
595
0
  writer->cwt = cwt;
596
0
  writer->phase = phase;
597
0
  result = cwt->do_init(data, writer);
598
599
0
out:
600
0
  *pwriter = result? NULL : writer;
601
0
  if(result)
602
0
    free(writer);
603
0
  return result;
604
0
}
605
606
void Curl_cwriter_free(struct Curl_easy *data,
607
                             struct Curl_cwriter *writer)
608
0
{
609
0
  if(writer) {
610
0
    writer->cwt->do_close(data, writer);
611
0
    free(writer);
612
0
  }
613
0
}
614
615
size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
616
0
{
617
0
  struct Curl_cwriter *w;
618
0
  size_t n = 0;
619
620
0
  for(w = data->req.writer_stack; w; w = w->next) {
621
0
    if(w->phase == phase)
622
0
      ++n;
623
0
  }
624
0
  return n;
625
0
}
626
627
static CURLcode do_init_stack(struct Curl_easy *data)
628
0
{
629
0
  struct Curl_cwriter *writer;
630
0
  CURLcode result;
631
632
0
  DEBUGASSERT(!data->req.writer_stack);
633
0
  result = Curl_cwriter_create(&data->req.writer_stack,
634
0
                               data, &cw_client, CURL_CW_CLIENT);
635
0
  if(result)
636
0
    return result;
637
638
0
  result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
639
0
  if(result)
640
0
    return result;
641
0
  result = Curl_cwriter_add(data, writer);
642
0
  if(result) {
643
0
    Curl_cwriter_free(data, writer);
644
0
  }
645
646
0
  result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
647
0
  if(result)
648
0
    return result;
649
0
  result = Curl_cwriter_add(data, writer);
650
0
  if(result) {
651
0
    Curl_cwriter_free(data, writer);
652
0
  }
653
0
  return result;
654
0
}
655
656
CURLcode Curl_cwriter_add(struct Curl_easy *data,
657
                          struct Curl_cwriter *writer)
658
0
{
659
0
  CURLcode result;
660
0
  struct Curl_cwriter **anchor = &data->req.writer_stack;
661
662
0
  if(!*anchor) {
663
0
    result = do_init_stack(data);
664
0
    if(result)
665
0
      return result;
666
0
  }
667
668
  /* Insert the writer as first in its phase.
669
   * Skip existing writers of lower phases. */
670
0
  while(*anchor && (*anchor)->phase < writer->phase)
671
0
    anchor = &((*anchor)->next);
672
0
  writer->next = *anchor;
673
0
  *anchor = writer;
674
0
  return CURLE_OK;
675
0
}
676
677
void Curl_cwriter_remove_by_name(struct Curl_easy *data,
678
                                 const char *name)
679
0
{
680
0
  struct Curl_cwriter **anchor = &data->req.writer_stack;
681
682
0
  while(*anchor) {
683
0
    if(!strcmp(name, (*anchor)->cwt->name)) {
684
0
      struct Curl_cwriter *w = (*anchor);
685
0
      *anchor = w->next;
686
0
      Curl_cwriter_free(data, w);
687
0
      continue;
688
0
    }
689
0
    anchor = &((*anchor)->next);
690
0
  }
691
0
}
692
693
/*
694
 * Internal read-from-socket function. This is meant to deal with plain
695
 * sockets, SSL sockets and kerberos sockets.
696
 *
697
 * Returns a regular CURLcode value.
698
 */
699
CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
700
                   curl_socket_t sockfd,     /* read from this socket */
701
                   char *buf,                /* store read data here */
702
                   size_t sizerequested,     /* max amount to read */
703
                   ssize_t *n)               /* amount bytes read */
704
0
{
705
0
  CURLcode result = CURLE_RECV_ERROR;
706
0
  ssize_t nread = 0;
707
0
  size_t bytesfromsocket = 0;
708
0
  char *buffertofill = NULL;
709
0
  struct connectdata *conn = data->conn;
710
711
  /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
712
     If it is the second socket, we set num to 1. Otherwise to 0. This lets
713
     us use the correct ssl handle. */
714
0
  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
715
716
0
  *n = 0; /* reset amount to zero */
717
718
0
  bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
719
0
  buffertofill = buf;
720
721
0
  nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
722
0
  if(nread < 0)
723
0
    goto out;
724
725
0
  *n += nread;
726
0
  result = CURLE_OK;
727
0
out:
728
0
  return result;
729
0
}