Coverage Report

Created: 2026-09-14 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/transfer.c
Line
Count
Source
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
#include "curl_setup.h"
25
26
#ifdef HAVE_NETINET_IN_H
27
#include <netinet/in.h>
28
#endif
29
#ifdef HAVE_NETDB_H
30
#include <netdb.h>
31
#endif
32
#ifdef HAVE_ARPA_INET_H
33
#include <arpa/inet.h>
34
#endif
35
#ifdef HAVE_NET_IF_H
36
#include <net/if.h>
37
#endif
38
#ifdef HAVE_SYS_IOCTL_H
39
#include <sys/ioctl.h>
40
#endif
41
#include <signal.h>
42
43
#ifdef HAVE_SYS_PARAM_H
44
#include <sys/param.h>
45
#endif
46
47
#ifdef HAVE_SYS_SELECT_H
48
#include <sys/select.h>
49
#elif defined(HAVE_UNISTD_H)
50
#include <unistd.h>
51
#endif
52
53
#ifndef HAVE_SOCKET
54
#error "We cannot compile without socket() support"
55
#endif
56
57
#include "urldata.h"
58
59
#include "cfilters.h"
60
#include "cw-out.h"
61
#include "transfer.h"
62
#include "sendf.h"
63
#include "curl_trc.h"
64
#include "progress.h"
65
#include "http.h"
66
#include "url.h"
67
#include "getinfo.h"
68
#include "multiif.h"
69
#include "connect.h"
70
#include "hsts.h"
71
#include "setopt.h"
72
#include "headers.h"
73
#include "bufref.h"
74
#include "rtsp.h"
75
76
#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
77
  !defined(CURL_DISABLE_IMAP)
78
/*
79
 * checkheaders() checks the linked list of custom headers for a
80
 * particular header (prefix). Provide the prefix without colon!
81
 *
82
 * Returns a pointer to the first matching header or NULL if none matched.
83
 */
84
char *Curl_checkheaders(const struct Curl_easy *data,
85
                        const char *thisheader,
86
                        const size_t thislen)
87
36.4k
{
88
36.4k
  struct curl_slist *head;
89
36.4k
  DEBUGASSERT(thislen);
90
36.4k
  DEBUGASSERT(thisheader[thislen - 1] != ':');
91
92
41.9k
  for(head = data->set.headers; head; head = head->next) {
93
5.50k
    if(curl_strnequal(head->data, thisheader, thislen) &&
94
21
       Curl_headersep(head->data[thislen]))
95
11
      return head->data;
96
5.50k
  }
97
98
36.4k
  return NULL;
99
36.4k
}
100
#endif
101
102
static int data_pending(struct Curl_easy *data, bool rcvd_eagain)
103
19.0k
{
104
19.0k
  struct connectdata *conn = data->conn;
105
106
19.0k
  if(conn->scheme->protocol & PROTO_FAMILY_FTP)
107
0
    return Curl_conn_data_pending(data, SECONDARYSOCKET);
108
109
  /* in the case of libssh2, we can never be really sure that we have emptied
110
     its internal buffers so we MUST always try until we get EAGAIN back */
111
19.0k
  return (!rcvd_eagain &&
112
0
          conn->scheme->protocol & (CURLPROTO_SCP | CURLPROTO_SFTP)) ||
113
19.0k
         Curl_conn_data_pending(data, FIRSTSOCKET);
114
19.0k
}
115
116
/*
117
 * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
118
 * remote document with the time provided by CURLOPT_TIMEVAL
119
 */
120
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
121
4
{
122
4
  if((timeofdoc == 0) || (data->set.timevalue == 0))
123
4
    return TRUE;
124
125
0
  switch(data->set.timecondition) {
126
0
  case CURL_TIMECOND_IFMODSINCE:
127
0
  default:
128
0
    if(timeofdoc <= data->set.timevalue) {
129
0
      infof(data, "The requested document is not new enough");
130
0
      data->info.timecond = TRUE;
131
0
      return FALSE;
132
0
    }
133
0
    break;
134
0
  case CURL_TIMECOND_IFUNMODSINCE:
135
0
    if(timeofdoc >= data->set.timevalue) {
136
0
      infof(data, "The requested document is not old enough");
137
0
      data->info.timecond = TRUE;
138
0
      return FALSE;
139
0
    }
140
0
    break;
141
0
  }
142
143
0
  return TRUE;
144
0
}
145
146
static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
147
0
{
148
0
  if(!data || !data->conn)
149
0
    return CURLE_FAILED_INIT;
150
0
  return Curl_cshutdn_try_once_idx(data, data->conn->recv_idx, done);
151
0
}
152
153
static bool xfer_recv_shutdown_started(struct Curl_easy *data)
154
22.9k
{
155
22.9k
  if(!data || !data->conn)
156
0
    return FALSE;
157
22.9k
  return Curl_cshutdn_has_started(data->conn, data->conn->recv_idx);
158
22.9k
}
159
160
CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
161
0
{
162
0
  if(!data || !data->conn)
163
0
    return CURLE_FAILED_INIT;
164
0
  return Curl_cshutdn_try_once_idx(data, data->conn->send_idx, done);
165
0
}
166
167
/**
168
 * Receive raw response data for the transfer.
169
 * @param data         the transfer
170
 * @param buf          buffer to keep response data received
171
 * @param blen         length of `buf`
172
 * @param eos_reliable if EOS detection in underlying connection is reliable
173
 * @return number of bytes read or -1 for error
174
 */
175
static CURLcode xfer_recv_resp(struct Curl_easy *data,
176
                               char *buf, size_t blen,
177
                               bool eos_reliable,
178
                               size_t *pnread)
179
22.9k
{
180
22.9k
  CURLcode result;
181
182
22.9k
  DEBUGASSERT(blen > 0);
183
22.9k
  *pnread = 0;
184
  /* If we are reading BODY data and the connection does NOT handle EOF
185
   * and we know the size of the BODY data, limit the read amount */
186
22.9k
  if(!eos_reliable && !data->req.header && data->req.size != -1) {
187
0
    blen = curlx_sotouz_range(data->req.size - data->req.bytecount, 0, blen);
188
0
  }
189
22.9k
  else if(xfer_recv_shutdown_started(data)) {
190
    /* we already received everything. Do not try more. */
191
0
    blen = 0;
192
0
  }
193
194
22.9k
  if(blen) {
195
22.9k
    result = Curl_xfer_recv(data, buf, blen, pnread);
196
22.9k
    if(result)
197
22.2k
      return result;
198
22.9k
  }
199
200
694
  if(*pnread == 0) {
201
694
    if(data->req.shutdown) {
202
0
      bool done;
203
0
      result = xfer_recv_shutdown(data, &done);
204
0
      if(result)
205
0
        return result;
206
0
      if(!done) {
207
0
        return CURLE_AGAIN;
208
0
      }
209
0
    }
210
694
    DEBUGF(infof(data, "sendrecv_dl: we are done"));
211
694
  }
212
694
  return CURLE_OK;
213
694
}
214
215
/*
216
 * Go ahead and do a read if we have a readable socket or if
217
 * the stream was rewound (in which case we have data in a
218
 * buffer)
219
 */
220
static CURLcode sendrecv_dl(struct Curl_easy *data,
221
                            struct SingleRequest *k)
222
22.9k
{
223
22.9k
  struct connectdata *conn = data->conn;
224
22.9k
  CURLcode result = CURLE_OK;
225
22.9k
  char *buf, *xfer_buf;
226
22.9k
  size_t blen, xfer_blen;
227
22.9k
  int maxloops = 10;
228
22.9k
  bool is_multiplex = FALSE;
229
22.9k
  bool rcvd_eagain = FALSE;
230
22.9k
  bool is_eos = FALSE, rate_limited = FALSE;
231
232
22.9k
  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
233
22.9k
  if(result)
234
0
    goto out;
235
236
  /* This is where we loop until we have read everything there is to
237
     read or we get a CURLE_AGAIN */
238
22.9k
  do {
239
22.9k
    size_t bytestoread;
240
241
22.9k
    if(!is_multiplex) {
242
      /* Multiplexed connection have inherent handling of EOF and we do not
243
       * have to carefully restrict the amount we try to read.
244
       * Multiplexed changes only in one direction. */
245
22.9k
      is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
246
22.9k
    }
247
248
22.9k
    buf = xfer_buf;
249
22.9k
    bytestoread = xfer_blen;
250
251
22.9k
    if(bytestoread && Curl_rlimit_active(&data->progress.dl.rlimit)) {
252
0
      curl_off_t dl_avail = Curl_rlimit_avail(&data->progress.dl.rlimit, NULL);
253
#if 0
254
      DEBUGF(infof(data, "dl_rlimit, available=%" FMT_OFF_T, dl_avail));
255
#endif
256
      /* In case of rate limited downloads: if this loop already got data and
257
       * less than 16k is left in the limit, break out. We want to stutter a
258
       * bit to keep in the limit, but too small receives will cost cpu
259
       * unnecessarily. */
260
0
      if(dl_avail <= 0) {
261
0
        rate_limited = TRUE;
262
0
        break;
263
0
      }
264
0
      if(dl_avail < (curl_off_t)bytestoread)
265
0
        bytestoread = (size_t)dl_avail;
266
0
    }
267
268
22.9k
    rcvd_eagain = FALSE;
269
22.9k
    result = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &blen);
270
22.9k
    if(result) {
271
22.2k
      if(result != CURLE_AGAIN)
272
3.20k
        goto out; /* real error */
273
19.0k
      rcvd_eagain = TRUE;
274
19.0k
      result = CURLE_OK;
275
19.0k
      if(data->req.download_done && data->req.no_body &&
276
0
         !data->req.resp_trailer) {
277
0
        DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
278
0
                     "not waiting for EOS"));
279
0
        blen = 0;
280
        /* continue as if we received the EOS */
281
0
      }
282
19.0k
      else
283
19.0k
        break; /* get out of loop */
284
19.0k
    }
285
286
    /* We only get a 0-length receive at the end of the response */
287
694
    is_eos = (blen == 0);
288
289
694
    if(!blen) {
290
694
      result = Curl_req_stop_send_recv(data);
291
694
      if(result)
292
0
        goto out;
293
694
      if(k->eos_written) /* already did write this to client, leave */
294
0
        break;
295
694
    }
296
297
694
    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
298
694
    if(result || data->req.done)
299
0
      goto out;
300
301
    /* if we are done, we stop receiving. On multiplexed connections,
302
     * we should read the EOS. Which may arrive as meta data after
303
     * the bytes. Not taking it in might lead to RST of streams. */
304
694
    if((!is_multiplex && data->req.download_done) || is_eos) {
305
694
      CURL_REQ_CLEAR_RECV(data);
306
694
    }
307
    /* if we stopped receiving, leave the loop */
308
694
    if(!CURL_REQ_WANT_RECV(data))
309
694
      break;
310
311
694
  } while(maxloops--);
312
313
19.7k
  if(!is_eos && !rate_limited && CURL_REQ_WANT_RECV(data) &&
314
19.0k
     (!rcvd_eagain || data_pending(data, rcvd_eagain))) {
315
    /* Did not read until EAGAIN/EOS or there is still data pending
316
     * in buffers. Mark as read-again via simulated SELECT results. */
317
0
    Curl_multi_mark_dirty(data);
318
0
    CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty");
319
0
  }
320
321
19.7k
  if(!CURL_REQ_WANT_RECV(data) && CURL_REQ_WANT_SEND(data) &&
322
0
     (conn->bits.close || is_multiplex)) {
323
    /* When we have read the entire thing and the close bit is set, the server
324
       may now close the connection. If there is now any kind of sending going
325
       on from our side, we need to stop that immediately. */
326
0
    infof(data, "we are done reading and this is set to close, stop send");
327
0
    Curl_req_abort_sending(data);
328
0
  }
329
330
22.9k
out:
331
22.9k
  Curl_multi_xfer_buf_release(data, xfer_buf);
332
22.9k
  if(result)
333
3.20k
    DEBUGF(infof(data, "sendrecv_dl() -> %d", (int)result));
334
22.9k
  return result;
335
19.7k
}
336
337
/*
338
 * Send data to upload to the server, when the socket is writable.
339
 */
340
static CURLcode sendrecv_ul(struct Curl_easy *data)
341
767
{
342
  /* We should not get here when the sending is already done. */
343
767
  DEBUGASSERT(!Curl_req_done_sending(data));
344
345
767
  if(!Curl_req_done_sending(data))
346
767
    return Curl_req_send_more(data);
347
0
  return CURLE_OK;
348
767
}
349
350
/*
351
 * Curl_sendrecv() is the low-level function to be called when data is to
352
 * be read and written to/from the connection.
353
 */
354
CURLcode Curl_sendrecv(struct Curl_easy *data)
355
22.9k
{
356
22.9k
  struct SingleRequest *k = &data->req;
357
22.9k
  const struct curltime *pnow = NULL;
358
22.9k
  CURLcode result = CURLE_OK;
359
360
22.9k
  if(Curl_xfer_is_blocked(data)) {
361
0
    result = CURLE_OK;
362
0
    goto out;
363
0
  }
364
365
  /* We go ahead and do a read if we have a readable socket or if the stream
366
     was rewound (in which case we have data in a buffer) */
367
22.9k
  if(CURL_REQ_WANT_RECV(data)) {
368
22.9k
    result = sendrecv_dl(data, k);
369
22.9k
    if(result || data->req.done)
370
3.20k
      goto out;
371
22.9k
  }
372
373
  /* If we still have writing to do, we check if we have a writable socket. */
374
19.7k
  if(Curl_req_want_send(data)) {
375
767
    result = sendrecv_ul(data);
376
767
    if(result)
377
6
      goto out;
378
767
  }
379
380
19.6k
  pnow = Curl_pgrs_now(data);
381
19.6k
  if(CURL_REQ_WANT_IO(data)) {
382
19.0k
    if(Curl_timeleft_now_ms(data, pnow) < 0) {
383
0
      if(k->size != -1) {
384
0
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
385
0
              " milliseconds with %" FMT_OFF_T " out of %"
386
0
              FMT_OFF_T " bytes received",
387
0
              Curl_pgrs_since_ms(data, NULL, TIMER_STARTSINGLE),
388
0
              k->bytecount, k->size);
389
0
      }
390
0
      else {
391
0
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
392
0
              " milliseconds with %" FMT_OFF_T " bytes received",
393
0
              Curl_pgrs_since_ms(data, NULL, TIMER_STARTSINGLE),
394
0
              k->bytecount);
395
0
      }
396
0
      result = CURLE_OPERATION_TIMEDOUT;
397
0
      goto out;
398
0
    }
399
19.0k
  }
400
694
  else {
401
    /*
402
     * The transfer has been performed. Make some general checks before
403
     * returning.
404
     */
405
694
    if(!data->req.no_body && (k->size != -1) &&
406
1
       (k->bytecount != k->size) && !k->newurl) {
407
0
      failf(data, "transfer closed with %" FMT_OFF_T
408
0
            " bytes remaining to read", k->size - k->bytecount);
409
0
      result = CURLE_PARTIAL_FILE;
410
0
      goto out;
411
0
    }
412
694
  }
413
414
  /* If there is nothing more to send/recv, the request is done */
415
19.6k
  if(!CURL_REQ_WANT_IO(data))
416
694
    data->req.done = TRUE;
417
418
19.6k
  result = Curl_pgrsCheckX(data, pnow);
419
420
22.9k
out:
421
22.9k
  if(result)
422
3.20k
    DEBUGF(infof(data, "Curl_sendrecv() -> %d", (int)result));
423
22.9k
  return result;
424
19.6k
}
425
426
/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
427
   which means this gets called once for each subsequent redirect etc */
428
void Curl_init_CONNECT(struct Curl_easy *data)
429
6.97k
{
430
6.97k
  data->state.fread_func = data->set.fread_func_set;
431
6.97k
  data->state.in = data->set.in_set;
432
6.97k
  data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
433
6.97k
}
434
435
/*
436
 * Curl_pretransfer() is called immediately before a transfer starts, and only
437
 * once for one transfer no matter if it has redirects or do multi-pass
438
 * authentication etc.
439
 */
440
CURLcode Curl_pretransfer(struct Curl_easy *data)
441
7.04k
{
442
7.04k
  CURLcode result = CURLE_OK;
443
444
  /* Reset the retry count at the start of each request.
445
   * If the retry count is not reset, when the connection drops,
446
   * it will not enter the retry mechanism on CONN_MAX_RETRIES + 1 attempts
447
   * and will immediately throw
448
   * "Connection died, tried CONN_MAX_RETRIES times before giving up".
449
   * By resetting it here, we ensure each new request starts fresh. */
450
7.04k
  data->state.retrycount = 0;
451
452
7.04k
  if(!CURL_EASY_STR(data, STRING_SET_URL) && !data->set.uh) {
453
    /* we cannot do anything without URL */
454
0
    failf(data, "No URL set");
455
0
    return CURLE_URL_MALFORMAT;
456
0
  }
457
458
  /* CURLOPT_CURLU overrides CURLOPT_URL and the contents of the CURLU handle
459
     is allowed to be changed by the user between transfers */
460
7.04k
  if(data->set.uh) {
461
0
    char *url = NULL;
462
0
    CURLUcode uc;
463
0
    uc = curl_url_get(data->set.uh, CURLUPART_URL, &url, 0);
464
0
    if(uc) {
465
      /* clear the pointer to not point to freed memory anymore */
466
0
      Curl_bufref_set(&data->state.url, NULL, 0, NULL);
467
0
      failf(data, "No URL set");
468
0
      return CURLE_URL_MALFORMAT;
469
0
    }
470
0
    result = CURL_EASY_STR_SETN(data, STRING_SET_URL, url);
471
0
    if(result)
472
0
      return result;
473
0
  }
474
475
7.04k
  Curl_bufref_set(&data->state.url, CURL_EASY_STR(data, STRING_SET_URL),
476
7.04k
                  0, NULL);
477
478
7.04k
  if(data->set.postfields && data->set.set_resume_from) {
479
    /* we cannot */
480
71
    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
481
71
    return CURLE_BAD_FUNCTION_ARGUMENT;
482
71
  }
483
484
6.97k
  data->state.prefer_ascii = data->set.prefer_ascii;
485
6.97k
#ifdef CURL_LIST_ONLY_PROTOCOL
486
6.97k
  data->state.list_only = data->set.list_only;
487
6.97k
#endif
488
6.97k
  data->state.httpreq = data->set.method;
489
490
  /* initial transfer request coming up, forget the initial origin
491
   * from a previous perform() on this handle. */
492
6.97k
  Curl_peer_unlink(&data->state.initial_origin);
493
6.97k
  Curl_peer_unlink(&data->state.origin);
494
6.97k
  data->state.requests = 0;
495
6.97k
  data->state.followlocation = 0; /* reset the location-follow counter */
496
6.97k
  data->state.this_is_a_follow = FALSE; /* reset this */
497
6.97k
  data->state.http_ignorecustom = FALSE; /* use custom HTTP method */
498
6.97k
  data->state.errorbuf = FALSE; /* no error has occurred */
499
6.97k
#ifndef CURL_DISABLE_HTTP
500
6.97k
  Curl_http_neg_init(data, &data->state.http_neg);
501
6.97k
#endif
502
6.97k
  data->state.authproblem = FALSE;
503
6.97k
  data->state.authhost.want = data->set.httpauth;
504
6.97k
  data->state.authproxy.want = data->set.proxyauth;
505
6.97k
  curlx_safefree(data->info.wouldredirect);
506
6.97k
  Curl_data_priority_clear_state(data);
507
6.97k
  if(data->set.http_auto_referer)
508
10
    Curl_bufref_free(&data->state.referer);
509
6.97k
  if(CURL_EASY_STR(data, STRING_SET_REFERER))
510
48
    Curl_bufref_set(&data->state.referer,
511
48
                    CURL_EASY_STR(data, STRING_SET_REFERER), 0, NULL);
512
6.92k
  else
513
6.92k
    Curl_bufref_free(&data->state.referer);
514
515
6.97k
  if(data->state.httpreq == HTTPREQ_PUT)
516
17
    data->state.infilesize = data->set.filesize;
517
6.95k
  else if((data->state.httpreq != HTTPREQ_GET) &&
518
784
          (data->state.httpreq != HTTPREQ_HEAD)) {
519
776
    data->state.infilesize = data->set.postfieldsize;
520
776
    if(data->set.postfields && (data->state.infilesize == -1))
521
0
      data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
522
776
  }
523
6.18k
  else
524
6.18k
    data->state.infilesize = 0;
525
526
  /* If there is a list of cookie files to read, do it now! */
527
6.97k
  result = Curl_cookie_loadfiles(data,
528
6.97k
                                 data->set.cookiesession ?
529
6.94k
                                 COOKIE_NOSESSION : 0);
530
6.97k
  if(!result)
531
6.97k
    Curl_cookie_run(data); /* activate */
532
533
  /* If there is a list of host pairs to deal with */
534
6.97k
  if(!result && data->state.resolve)
535
0
    result = Curl_loadhostpairs(data);
536
537
6.97k
  if(!result)
538
    /* If there is a list of hsts files to read */
539
6.97k
    result = Curl_hsts_loadfiles(data);
540
541
6.97k
  if(!result) {
542
    /* Allow data->set.use_port to set which port to use. This needs to be
543
     * disabled for example when we follow Location: headers to URLs using
544
     * different ports! */
545
6.97k
    data->state.allow_port = TRUE;
546
547
#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(MSG_NOSIGNAL)
548
    /*************************************************************
549
     * Tell signal handler to ignore SIGPIPE
550
     *************************************************************/
551
    if(!data->set.no_signal)
552
      data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
553
#endif
554
555
6.97k
    Curl_initinfo(data); /* reset session-specific information "variables" */
556
6.97k
    Curl_pgrsResetTransferSizes(data);
557
6.97k
    Curl_pgrsStart(data, NULL);
558
559
    /* In case the handle is reused and an authentication method was picked
560
       in the session we need to make sure we only use the one(s) we now
561
       consider to be fine */
562
6.97k
    data->state.authhost.picked &= data->state.authhost.want;
563
6.97k
    data->state.authproxy.picked &= data->state.authproxy.want;
564
565
6.97k
#ifndef CURL_DISABLE_FTP
566
6.97k
    data->state.wildcardmatch = data->set.wildcard_enabled;
567
6.97k
    if(data->state.wildcardmatch) {
568
0
      struct WildcardData *wc;
569
0
      if(!data->wildcard) {
570
0
        data->wildcard = curlx_calloc(1, sizeof(struct WildcardData));
571
0
        if(!data->wildcard)
572
0
          return CURLE_OUT_OF_MEMORY;
573
0
      }
574
0
      wc = data->wildcard;
575
0
      if(wc->state < CURLWC_INIT) {
576
0
        if(wc->ftpwc)
577
0
          wc->dtor(wc->ftpwc);
578
0
        curlx_safefree(wc->pattern);
579
0
        curlx_safefree(wc->path);
580
0
        Curl_wildcard_init(wc); /* init wildcard structures */
581
0
      }
582
0
    }
583
6.97k
#endif
584
6.97k
    result = Curl_hsts_loadcb(data, data->hsts);
585
6.97k
  }
586
587
6.97k
  data->req.headerbytecount = 0;
588
6.97k
  Curl_headers_cleanup(data);
589
6.97k
  return result;
590
6.97k
}
591
592
/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
593
594
   NOTE: that the *url is curlx_malloc()ed. */
595
CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
596
3.05k
{
597
3.05k
  struct connectdata *conn = data->conn;
598
3.05k
  bool retry = FALSE;
599
3.05k
  *url = NULL;
600
601
  /* if we are talking upload, we cannot do the checks below, unless the
602
     protocol is HTTP as when uploading over HTTP we will still get a
603
     response */
604
3.05k
  if(data->state.upload &&
605
8
     !(conn->scheme->protocol & (PROTO_FAMILY_HTTP | CURLPROTO_RTSP)))
606
0
    return CURLE_OK;
607
608
3.05k
  if(conn->bits.reuse &&
609
2
     (data->req.bytecount + data->req.headerbytecount == 0) &&
610
2
     ((!data->req.no_body && !data->req.done) ||
611
0
      (conn->scheme->protocol & PROTO_FAMILY_HTTP))
612
2
#ifndef CURL_DISABLE_RTSP
613
2
     && (data->set.rtspreq != RTSPREQ_RECEIVE)
614
3.05k
#endif
615
3.05k
    )
616
    /* We got no data, we attempted to reuse a connection. For HTTP this
617
       can be a retry so we try again regardless if we expected a body.
618
       For other protocols we only try again only if we expected a body.
619
620
       This might happen if the connection was left alive when we were
621
       done using it before, but that was closed when we wanted to read from
622
       it again. Bad luck. Retry the same request on a fresh connect! */
623
2
    retry = TRUE;
624
3.04k
  else if(data->state.refused_stream &&
625
0
          (data->req.bytecount + data->req.headerbytecount == 0)) {
626
    /* This was sent on a refused stream, safe to rerun. A refused stream
627
       error can typically only happen on HTTP/2 level if the stream is safe
628
       to issue again, but the nghttp2 API can deliver the message to other
629
       streams as well, which is why this adds the check the data counters
630
       too. */
631
0
    infof(data, "REFUSED_STREAM, retrying a fresh connect");
632
0
    data->state.refused_stream = FALSE; /* clear again */
633
0
    retry = TRUE;
634
0
  }
635
3.05k
  if(retry) {
636
2
#define CONN_MAX_RETRIES 5
637
2
    if(data->state.retrycount++ >= CONN_MAX_RETRIES) {
638
0
      failf(data, "Connection died, tried %d times before giving up",
639
0
            CONN_MAX_RETRIES);
640
0
      data->state.retrycount = 0;
641
0
      return CURLE_SEND_ERROR;
642
0
    }
643
2
    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
644
2
          data->state.retrycount);
645
2
    *url = Curl_bufref_dup(&data->state.url);
646
2
    if(!*url)
647
0
      return CURLE_OUT_OF_MEMORY;
648
649
2
    connclose(conn); /* close this connection */
650
2
    conn->bits.retry = TRUE; /* mark this as a connection we are about to
651
                                retry. Marking it this way should prevent i.e
652
                                HTTP transfers to return error because nothing
653
                                has been transferred! */
654
2
    Curl_creader_set_rewind(data, TRUE);
655
2
  }
656
3.05k
  return CURLE_OK;
657
3.05k
}
658
659
static void xfer_setup(
660
  struct Curl_easy *data,   /* transfer */
661
  int8_t send_idx,             /* sockindex to send on or -1 */
662
  int8_t recv_idx,             /* sockindex to receive on or -1 */
663
  curl_off_t recv_size      /* how much to receive, -1 if unknown */
664
  )
665
6.77k
{
666
6.77k
  struct SingleRequest *k = &data->req;
667
6.77k
  struct connectdata *conn = data->conn;
668
669
6.77k
  DEBUGASSERT(conn);
670
  /* indexes are in range */
671
6.77k
  DEBUGASSERT((send_idx <= 1) && (send_idx >= -1));
672
6.77k
  DEBUGASSERT((recv_idx <= 1) && (recv_idx >= -1));
673
  /* if request wants to send, switching off the send direction is wrong */
674
6.77k
  DEBUGASSERT((send_idx >= 0) || !Curl_req_want_send(data));
675
676
6.77k
  conn->send_idx = send_idx;
677
6.77k
  conn->recv_idx = recv_idx;
678
679
  /* without receiving, there should be not recv_size */
680
6.77k
  DEBUGASSERT((conn->recv_idx >= 0) || (recv_size == -1));
681
6.77k
  k->size = recv_size;
682
6.77k
  k->header = !!conn->scheme->run->write_resp_hd;
683
  /* by default, we do not shutdown at the end of the transfer */
684
6.77k
  k->shutdown = FALSE;
685
6.77k
  k->shutdown_err_ignore = FALSE;
686
687
  /* The code sequence below is placed in this function because all necessary
688
     input is not always known in do_complete() as this function may be called
689
     after that */
690
6.77k
  if(!k->header && (recv_size > 0))
691
0
    Curl_pgrsSetDownloadSize(data, recv_size);
692
693
  /* we want header and/or body, if neither then do not do this! */
694
6.77k
  if(conn->scheme->run->write_resp_hd || !data->req.no_body) {
695
6.77k
    if(conn->recv_idx != -1)
696
6.77k
      CURL_REQ_SET_RECV(data);
697
6.77k
    if(conn->send_idx != -1)
698
6.77k
      CURL_REQ_SET_SEND(data);
699
6.77k
  }
700
6.77k
  CURL_TRC_M(data, "xfer_setup: recv_idx=%d, send_idx=%d",
701
6.77k
             conn->recv_idx, conn->send_idx);
702
6.77k
}
703
704
void Curl_xfer_setup_nop(struct Curl_easy *data)
705
0
{
706
0
  xfer_setup(data, -1, -1, -1);
707
0
}
708
709
void Curl_xfer_setup_sendrecv(struct Curl_easy *data,
710
                              int8_t sockindex,
711
                              curl_off_t recv_size)
712
6.77k
{
713
6.77k
  xfer_setup(data, sockindex, sockindex, recv_size);
714
6.77k
}
715
716
void Curl_xfer_setup_send(struct Curl_easy *data,
717
                          int8_t sockindex)
718
0
{
719
0
  xfer_setup(data, sockindex, -1, -1);
720
0
}
721
722
void Curl_xfer_setup_recv(struct Curl_easy *data,
723
                          int8_t sockindex,
724
                          curl_off_t recv_size)
725
0
{
726
0
  xfer_setup(data, -1, sockindex, recv_size);
727
0
}
728
729
void Curl_xfer_set_shutdown(struct Curl_easy *data,
730
                            bool shutdown,
731
                            bool ignore_errors)
732
0
{
733
  /* Shutdown should only be set when the transfer only sends or receives. */
734
0
  DEBUGASSERT(!shutdown ||
735
0
              (data->conn->send_idx < 0) || (data->conn->recv_idx < 0));
736
0
  data->req.shutdown = shutdown;
737
0
  data->req.shutdown_err_ignore = ignore_errors;
738
0
}
739
740
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
741
                              const char *buf, size_t blen,
742
                              bool is_eos)
743
882
{
744
882
  CURLcode result = CURLE_OK;
745
746
882
  if(data->conn->scheme->run->write_resp) {
747
    /* protocol handlers offering this function take full responsibility
748
     * for writing all received download data to the client. */
749
882
    result = data->conn->scheme->run->write_resp(data, buf, blen, is_eos);
750
882
  }
751
0
  else {
752
    /* No special handling by protocol handler, write all received data
753
     * as BODY to the client. */
754
0
    if(blen || is_eos) {
755
0
      int cwtype = CLIENTWRITE_BODY;
756
0
      if(is_eos)
757
0
        cwtype |= CLIENTWRITE_EOS;
758
0
      result = Curl_client_write(data, cwtype, buf, blen);
759
0
    }
760
0
  }
761
762
882
  if(!result && is_eos) {
763
    /* If we wrote the EOS, we are definitely done */
764
694
    data->req.eos_written = TRUE;
765
694
    data->req.download_done = TRUE;
766
694
  }
767
882
  CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
768
882
                 blen, is_eos, (int)result);
769
882
  return result;
770
882
}
771
772
bool Curl_xfer_write_is_paused(struct Curl_easy *data)
773
0
{
774
0
  return Curl_cwriter_is_paused(data);
775
0
}
776
777
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
778
                                 const char *hd0, size_t hdlen, bool is_eos)
779
3.66k
{
780
3.66k
  if(data->conn->scheme->run->write_resp_hd) {
781
3.66k
    DEBUGASSERT(!hd0[hdlen]); /* null-terminated */
782
    /* protocol handlers offering this function take full responsibility
783
     * for writing all received download data to the client. */
784
3.66k
    return data->conn->scheme->run->write_resp_hd(data, hd0, hdlen, is_eos);
785
3.66k
  }
786
  /* No special handling by protocol handler, write as response bytes */
787
0
  return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
788
3.66k
}
789
790
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
791
6.80k
{
792
6.80k
  (void)premature;
793
6.80k
  return Curl_cw_out_done(data);
794
6.80k
}
795
796
bool Curl_xfer_needs_flush(struct Curl_easy *data)
797
38.6k
{
798
38.6k
  return Curl_conn_needs_flush(data, data->conn->send_idx);
799
38.6k
}
800
801
CURLcode Curl_xfer_flush(struct Curl_easy *data)
802
0
{
803
0
  return Curl_conn_flush(data, data->conn->send_idx);
804
0
}
805
806
CURLcode Curl_xfer_send(struct Curl_easy *data,
807
                        const void *buf, size_t blen, bool eos,
808
                        size_t *pnwritten)
809
7.51k
{
810
7.51k
  CURLcode result;
811
812
7.51k
  DEBUGASSERT(data);
813
7.51k
  DEBUGASSERT(data->conn);
814
815
7.51k
  result = Curl_conn_send(data, data->conn->send_idx,
816
7.51k
                          buf, blen, eos, pnwritten);
817
7.51k
  if(result == CURLE_AGAIN) {
818
0
    result = CURLE_OK;
819
0
    *pnwritten = 0;
820
0
  }
821
7.51k
  else if(!result && *pnwritten)
822
7.46k
    data->info.request_size += *pnwritten;
823
824
7.51k
  DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
825
7.51k
               blen, eos, (int)result, *pnwritten));
826
7.51k
  return result;
827
7.51k
}
828
829
CURLcode Curl_xfer_recv(struct Curl_easy *data,
830
                        char *buf, size_t blen,
831
                        size_t *pnrcvd)
832
22.9k
{
833
22.9k
  DEBUGASSERT(data);
834
22.9k
  DEBUGASSERT(data->conn);
835
22.9k
  DEBUGASSERT(data->set.buffer_size > 0);
836
837
22.9k
  if(curlx_uitouz(data->set.buffer_size) < blen)
838
0
    blen = curlx_uitouz(data->set.buffer_size);
839
22.9k
  return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
840
22.9k
}
841
842
CURLcode Curl_xfer_send_close(struct Curl_easy *data)
843
6.71k
{
844
6.71k
  Curl_conn_ev_data_done_send(data);
845
6.71k
  return CURLE_OK;
846
6.71k
}
847
848
bool Curl_xfer_is_blocked(struct Curl_easy *data)
849
22.9k
{
850
22.9k
  bool want_send = CURL_REQ_WANT_SEND(data);
851
22.9k
  bool want_recv = CURL_REQ_WANT_RECV(data);
852
22.9k
  if(!want_send)
853
22.1k
    return want_recv && Curl_xfer_recv_is_paused(data);
854
767
  else if(!want_recv)
855
0
    return want_send && Curl_xfer_send_is_paused(data);
856
767
  else
857
767
    return Curl_xfer_recv_is_paused(data) && Curl_xfer_send_is_paused(data);
858
22.9k
}
859
860
bool Curl_xfer_send_is_paused(struct Curl_easy *data)
861
842
{
862
842
  return Curl_rlimit_is_blocked(&data->progress.ul.rlimit);
863
842
}
864
865
bool Curl_xfer_recv_is_paused(struct Curl_easy *data)
866
57.0k
{
867
57.0k
  return Curl_rlimit_is_blocked(&data->progress.dl.rlimit);
868
57.0k
}
869
870
CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable)
871
0
{
872
0
  CURLcode result = CURLE_OK;
873
0
  Curl_rlimit_block(&data->progress.ul.rlimit, enable, Curl_pgrs_now(data));
874
0
  if(!enable && Curl_creader_is_paused(data))
875
0
    result = Curl_creader_unpause(data);
876
0
  Curl_pgrsSendPause(data, enable);
877
0
  return result;
878
0
}
879
880
CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable)
881
0
{
882
0
  CURLcode result = CURLE_OK;
883
0
  Curl_rlimit_block(&data->progress.dl.rlimit, enable, Curl_pgrs_now(data));
884
0
  if(!enable && Curl_cwriter_is_paused(data))
885
0
    result = Curl_cwriter_unpause(data);
886
0
  Curl_conn_ev_data_pause(data, enable);
887
0
  Curl_pgrsRecvPause(data, enable);
888
0
  return result;
889
0
}
890
891
bool Curl_xfer_is_secure(struct Curl_easy *data)
892
7.15k
{
893
7.15k
#ifndef CURL_DISABLE_PROXY
894
7.15k
  if(data->conn && data->conn->bits.origin_is_proxy) {
895
    /* talking to a forward proxy, not secure. we do not use
896
     * a forward proxy for https: and other 's' URLs. Let's just check that
897
     * this did not fail somewhere. */
898
0
    DEBUGASSERT(!(data->state.origin->scheme->flags & PROTOPT_SSL));
899
0
    return FALSE;
900
0
  }
901
7.15k
#endif
902
7.15k
  return (data->state.origin->scheme->flags & PROTOPT_SSL);
903
7.15k
}