Coverage Report

Created: 2026-10-22 06:50

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
73.0k
{
88
73.0k
  struct curl_slist *head;
89
73.0k
  DEBUGASSERT(thislen);
90
73.0k
  DEBUGASSERT(thisheader[thislen - 1] != ':');
91
92
97.1k
  for(head = data->set.headers; head; head = head->next) {
93
24.1k
    if(curl_strnequal(head->data, thisheader, thislen) &&
94
53
       Curl_headersep(head->data[thislen]))
95
18
      return head->data;
96
24.1k
  }
97
98
73.0k
  return NULL;
99
73.0k
}
100
#endif
101
102
static int data_pending(struct Curl_easy *data, bool rcvd_eagain)
103
81.1k
{
104
81.1k
  struct connectdata *conn = data->conn;
105
106
81.1k
  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
81.1k
  return (!rcvd_eagain &&
112
0
          conn->scheme->protocol & (CURLPROTO_SCP | CURLPROTO_SFTP)) ||
113
81.1k
         Curl_conn_data_pending(data, FIRSTSOCKET);
114
81.1k
}
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
0
{
122
0
  if((timeofdoc == 0) || (data->set.timevalue == 0))
123
0
    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
94.5k
{
155
94.5k
  if(!data || !data->conn)
156
0
    return FALSE;
157
94.5k
  return CURL_CONN_IN_SHUTDOWN(data->conn, data->conn->recv_idx);
158
94.5k
}
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
94.5k
{
180
94.5k
  CURLcode result;
181
182
94.5k
  DEBUGASSERT(blen > 0);
183
94.5k
  *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
94.5k
  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
94.5k
  else if(xfer_recv_shutdown_started(data)) {
190
    /* we already received everything. Do not try more. */
191
0
    blen = 0;
192
0
  }
193
194
94.5k
  if(blen) {
195
94.5k
    result = Curl_xfer_recv(data, buf, blen, pnread);
196
94.5k
    if(result)
197
81.1k
      return result;
198
94.5k
  }
199
200
13.4k
  if(*pnread == 0) {
201
541
    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
541
    DEBUGF(infof(data, "sendrecv_dl: we are done"));
211
541
  }
212
13.4k
  return CURLE_OK;
213
13.4k
}
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
83.3k
{
223
83.3k
  struct connectdata *conn = data->conn;
224
83.3k
  CURLcode result = CURLE_OK;
225
83.3k
  char *buf, *xfer_buf;
226
83.3k
  size_t blen, xfer_blen;
227
83.3k
  int maxloops = 10;
228
83.3k
  bool is_multiplex = FALSE;
229
83.3k
  bool rcvd_eagain = FALSE;
230
83.3k
  bool is_eos = FALSE, rate_limited = FALSE;
231
232
83.3k
  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
233
83.3k
  if(result)
234
12
    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
94.5k
  do {
239
94.5k
    size_t bytestoread;
240
241
94.5k
    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
94.5k
      is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
246
94.5k
    }
247
248
94.5k
    buf = xfer_buf;
249
94.5k
    bytestoread = xfer_blen;
250
251
94.5k
    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
94.5k
    rcvd_eagain = FALSE;
269
94.5k
    result = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &blen);
270
94.5k
    if(result) {
271
81.1k
      if(result != CURLE_AGAIN)
272
0
        goto out; /* real error */
273
81.1k
      rcvd_eagain = TRUE;
274
81.1k
      result = CURLE_OK;
275
81.1k
      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
81.1k
      else
283
81.1k
        break; /* get out of loop */
284
81.1k
    }
285
286
    /* We only get a 0-length receive at the end of the response */
287
13.4k
    is_eos = (blen == 0);
288
289
13.4k
    if(!blen) {
290
541
      result = Curl_req_stop_send_recv(data);
291
541
      if(result)
292
0
        goto out;
293
541
      if(k->eos_written) /* already did write this to client, leave */
294
0
        break;
295
541
    }
296
297
13.4k
    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
298
13.4k
    if(result || data->req.done)
299
911
      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
12.5k
    if((!is_multiplex && data->req.download_done) || is_eos) {
305
230
      CURL_REQ_CLEAR_RECV(data);
306
230
    }
307
    /* if we stopped receiving, leave the loop */
308
12.5k
    if(!CURL_REQ_WANT_RECV(data))
309
1.20k
      break;
310
311
12.5k
  } while(maxloops--);
312
313
82.4k
  if(!is_eos && !rate_limited && CURL_REQ_WANT_RECV(data) &&
314
81.2k
     (!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
31
    Curl_multi_mark_dirty(data);
318
31
    CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty");
319
31
  }
320
321
82.4k
  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
83.3k
out:
331
83.3k
  Curl_multi_xfer_buf_release(data, xfer_buf);
332
83.3k
  if(result)
333
923
    DEBUGF(infof(data, "sendrecv_dl() -> %d", (int)result));
334
83.3k
  return result;
335
82.4k
}
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
1.17k
{
342
  /* We should not get here when the sending is already done. */
343
1.17k
  DEBUGASSERT(!Curl_req_done_sending(data));
344
345
1.17k
  if(!Curl_req_done_sending(data))
346
1.17k
    return Curl_req_send_more(data);
347
0
  return CURLE_OK;
348
1.17k
}
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
83.3k
{
356
83.3k
  struct SingleRequest *k = &data->req;
357
83.3k
  const struct curltime *pnow = NULL;
358
83.3k
  CURLcode result = CURLE_OK;
359
360
83.3k
  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
83.3k
  if(CURL_REQ_WANT_RECV(data)) {
368
83.3k
    result = sendrecv_dl(data, k);
369
83.3k
    if(result || data->req.done)
370
923
      goto out;
371
83.3k
  }
372
373
  /* If we still have writing to do, we check if we have a writable socket. */
374
82.4k
  if(Curl_req_want_send(data)) {
375
1.17k
    result = sendrecv_ul(data);
376
1.17k
    if(result)
377
10
      goto out;
378
1.17k
  }
379
380
82.4k
  pnow = Curl_pgrs_now(data);
381
82.4k
  if(CURL_REQ_WANT_IO(data)) {
382
81.2k
    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
81.2k
  }
400
1.20k
  else {
401
    /*
402
     * The transfer has been performed. Make some general checks before
403
     * returning.
404
     */
405
1.20k
    if(!data->req.no_body && (k->size != -1) &&
406
0
       (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
1.20k
  }
413
414
  /* If there is nothing more to send/recv, the request is done */
415
82.4k
  if(!CURL_REQ_WANT_IO(data))
416
1.20k
    data->req.done = TRUE;
417
418
82.4k
  result = Curl_pgrsCheckX(data, pnow);
419
420
83.3k
out:
421
83.3k
  if(result)
422
933
    DEBUGF(infof(data, "Curl_sendrecv() -> %d", (int)result));
423
83.3k
  return result;
424
82.4k
}
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
11.7k
{
430
11.7k
  data->state.fread_func = data->set.fread_func_set;
431
11.7k
  data->state.in = data->set.in_set;
432
11.7k
  data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
433
11.7k
}
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
11.8k
{
442
11.8k
  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
11.8k
  data->state.retrycount = 0;
451
452
11.8k
  if(!CURL_EASY_STR(data, STRING_SET_URL) && !data->set.uh) {
453
    /* we cannot do anything without URL */
454
12
    failf(data, "No URL set");
455
12
    return CURLE_URL_MALFORMAT;
456
12
  }
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
11.8k
  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
11.8k
  Curl_bufref_set(&data->state.url, CURL_EASY_STR(data, STRING_SET_URL),
476
11.8k
                  0, NULL);
477
478
11.8k
  if(data->set.postfields && data->set.set_resume_from) {
479
    /* we cannot */
480
55
    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
481
55
    return CURLE_BAD_FUNCTION_ARGUMENT;
482
55
  }
483
484
11.7k
  data->state.prefer_ascii = data->set.prefer_ascii;
485
11.7k
#ifdef CURL_LIST_ONLY_PROTOCOL
486
11.7k
  data->state.list_only = data->set.list_only;
487
11.7k
#endif
488
11.7k
  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
11.7k
  Curl_peer_unlink(&data->state.initial_origin);
493
11.7k
  Curl_peer_unlink(&data->state.origin);
494
11.7k
  data->state.requests = 0;
495
11.7k
  data->state.followlocation = 0; /* reset the location-follow counter */
496
11.7k
  data->state.this_is_a_follow = FALSE; /* reset this */
497
11.7k
  data->state.http_ignorecustom = FALSE; /* use custom HTTP method */
498
11.7k
  data->state.errorbuf = FALSE; /* no error has occurred */
499
11.7k
#ifndef CURL_DISABLE_HTTP
500
11.7k
  Curl_http_neg_init(data, &data->state.http_neg);
501
11.7k
#endif
502
11.7k
  data->state.authproblem = FALSE;
503
11.7k
  data->state.authhost.want = data->set.httpauth;
504
11.7k
  data->state.authproxy.want = data->set.proxyauth;
505
11.7k
  curlx_safefree(data->info.wouldredirect);
506
11.7k
  curlx_safefree(data->info.effective_url);
507
11.7k
  Curl_data_priority_clear_state(data);
508
11.7k
  if(data->set.http_auto_referer)
509
11
    Curl_bufref_free(&data->state.referer);
510
11.7k
  if(CURL_EASY_STR(data, STRING_SET_REFERER))
511
79
    Curl_bufref_set(&data->state.referer,
512
79
                    CURL_EASY_STR(data, STRING_SET_REFERER), 0, NULL);
513
11.6k
  else
514
11.6k
    Curl_bufref_free(&data->state.referer);
515
516
11.7k
  if(data->state.httpreq == HTTPREQ_PUT)
517
285
    data->state.infilesize = data->set.filesize;
518
11.4k
  else if((data->state.httpreq != HTTPREQ_GET) &&
519
133
          (data->state.httpreq != HTTPREQ_HEAD)) {
520
92
    data->state.infilesize = data->set.postfieldsize;
521
92
    if(data->set.postfields && (data->state.infilesize == -1))
522
0
      data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
523
92
  }
524
11.3k
  else
525
11.3k
    data->state.infilesize = 0;
526
527
  /* If there is a list of cookie files to read, do it now! */
528
11.7k
  result = Curl_cookie_loadfiles(data,
529
11.7k
                                 data->set.cookiesession ?
530
11.7k
                                 COOKIE_NOSESSION : 0);
531
11.7k
  if(!result)
532
11.7k
    Curl_cookie_run(data); /* activate */
533
534
  /* If there is a list of host pairs to deal with */
535
11.7k
  if(!result && data->state.resolve)
536
0
    result = Curl_loadhostpairs(data);
537
538
11.7k
  if(!result)
539
    /* If there is a list of hsts files to read */
540
11.7k
    result = Curl_hsts_loadfiles(data);
541
542
11.7k
  if(!result) {
543
    /* Allow data->set.use_port to set which port to use. This needs to be
544
     * disabled for example when we follow Location: headers to URLs using
545
     * different ports! */
546
11.7k
    data->state.allow_port = TRUE;
547
548
#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(MSG_NOSIGNAL)
549
    /*************************************************************
550
     * Tell signal handler to ignore SIGPIPE
551
     *************************************************************/
552
    if(!data->set.no_signal)
553
      data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
554
#endif
555
556
11.7k
    Curl_initinfo(data); /* reset session-specific information "variables" */
557
11.7k
    Curl_pgrsResetTransferSizes(data);
558
11.7k
    Curl_pgrsStart(data, NULL);
559
560
    /* In case the handle is reused and an authentication method was picked
561
       in the session we need to make sure we only use the one(s) we now
562
       consider to be fine */
563
11.7k
    data->state.authhost.picked &= data->state.authhost.want;
564
11.7k
    data->state.authproxy.picked &= data->state.authproxy.want;
565
566
11.7k
#ifndef CURL_DISABLE_FTP
567
11.7k
    data->state.wildcardmatch = data->set.wildcard_enabled;
568
11.7k
#ifdef DEBUGBUILD
569
11.7k
  if(getenv("CURL_DBG_FTP_WILDCARD"))
570
0
    data->state.wildcardmatch = TRUE;
571
11.7k
#endif
572
11.7k
    if(data->state.wildcardmatch) {
573
0
      struct WildcardData *wc;
574
0
      if(!data->wildcard) {
575
0
        data->wildcard = curlx_calloc(1, sizeof(struct WildcardData));
576
0
        if(!data->wildcard)
577
0
          return CURLE_OUT_OF_MEMORY;
578
0
      }
579
0
      wc = data->wildcard;
580
0
      if(wc->state < CURLWC_INIT) {
581
0
        if(wc->ftpwc)
582
0
          wc->dtor(wc->ftpwc);
583
0
        curlx_safefree(wc->pattern);
584
0
        curlx_safefree(wc->path);
585
0
        Curl_wildcard_init(wc); /* init wildcard structures */
586
0
      }
587
0
    }
588
11.7k
#endif
589
11.7k
    result = Curl_hsts_loadcb(data, data->hsts);
590
11.7k
  }
591
592
11.7k
  data->req.headerbytecount = 0;
593
  /* a previous transfer on this handle may have ended with a rewind request
594
   * still pending (a follow or auth retry that failed). This is a new
595
   * transfer, so drop those readers now instead of letting a later upload
596
   * read from them. */
597
11.7k
  data->req.rewind_read = FALSE;
598
11.7k
  Curl_client_reset(data);
599
11.7k
  Curl_headers_cleanup(data);
600
11.7k
  return result;
601
11.7k
}
602
603
/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
604
605
   NOTE: that the *url is curlx_malloc()ed. */
606
CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
607
2.03k
{
608
2.03k
  struct connectdata *conn = data->conn;
609
2.03k
  bool retry = FALSE;
610
2.03k
  *url = NULL;
611
612
  /* if we are talking upload, we cannot do the checks below, unless the
613
     protocol is HTTP as when uploading over HTTP we will still get a
614
     response */
615
2.03k
  if(data->state.upload &&
616
42
     !(conn->scheme->protocol & (PROTO_FAMILY_HTTP | CURLPROTO_RTSP)))
617
0
    return CURLE_OK;
618
619
2.03k
  if(conn->bits.reuse &&
620
0
     (data->req.bytecount + data->req.headerbytecount == 0) &&
621
0
     ((!data->req.no_body && !data->req.done) ||
622
0
      (conn->scheme->protocol & PROTO_FAMILY_HTTP))
623
0
#ifndef CURL_DISABLE_RTSP
624
0
     && (data->set.rtspreq != RTSPREQ_RECEIVE)
625
2.03k
#endif
626
2.03k
    )
627
    /* We got no data, we attempted to reuse a connection. For HTTP this
628
       can be a retry so we try again regardless if we expected a body.
629
       For other protocols we only try again only if we expected a body.
630
631
       This might happen if the connection was left alive when we were
632
       done using it before, but that was closed when we wanted to read from
633
       it again. Bad luck. Retry the same request on a fresh connect! */
634
0
    retry = TRUE;
635
2.03k
  else if(data->state.refused_stream &&
636
0
          (data->req.bytecount + data->req.headerbytecount == 0)) {
637
    /* This was sent on a refused stream, safe to rerun. A refused stream
638
       error can typically only happen on HTTP/2 level if the stream is safe
639
       to issue again, but the nghttp2 API can deliver the message to other
640
       streams as well, which is why this adds the check the data counters
641
       too. */
642
0
    infof(data, "REFUSED_STREAM, retrying a fresh connect");
643
0
    data->state.refused_stream = FALSE; /* clear again */
644
0
    retry = TRUE;
645
0
  }
646
2.03k
  if(retry) {
647
0
#define CONN_MAX_RETRIES 5
648
0
    if(data->state.retrycount++ >= CONN_MAX_RETRIES) {
649
0
      failf(data, "Connection died, tried %d times before giving up",
650
0
            CONN_MAX_RETRIES);
651
0
      data->state.retrycount = 0;
652
0
      return CURLE_SEND_ERROR;
653
0
    }
654
0
    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
655
0
          data->state.retrycount);
656
0
    *url = Curl_bufref_dup(&data->state.url);
657
0
    if(!*url)
658
0
      return CURLE_OUT_OF_MEMORY;
659
660
0
    connclose(conn); /* close this connection */
661
0
    conn->bits.retry = TRUE; /* mark this as a connection we are about to
662
                                retry. Marking it this way should prevent i.e
663
                                HTTP transfers to return error because nothing
664
                                has been transferred! */
665
0
    Curl_creader_set_rewind(data, TRUE);
666
0
  }
667
2.03k
  return CURLE_OK;
668
2.03k
}
669
670
static void xfer_setup(
671
  struct Curl_easy *data,   /* transfer */
672
  int8_t send_idx,             /* sockindex to send on or -1 */
673
  int8_t recv_idx,             /* sockindex to receive on or -1 */
674
  curl_off_t recv_size      /* how much to receive, -1 if unknown */
675
  )
676
9.74k
{
677
9.74k
  struct SingleRequest *k = &data->req;
678
9.74k
  struct connectdata *conn = data->conn;
679
680
9.74k
  DEBUGASSERT(conn);
681
  /* indexes are in range */
682
9.74k
  DEBUGASSERT((send_idx <= 1) && (send_idx >= -1));
683
9.74k
  DEBUGASSERT((recv_idx <= 1) && (recv_idx >= -1));
684
  /* if request wants to send, switching off the send direction is wrong */
685
9.74k
  DEBUGASSERT((send_idx >= 0) || !Curl_req_want_send(data));
686
687
9.74k
  conn->send_idx = send_idx;
688
9.74k
  conn->recv_idx = recv_idx;
689
690
  /* without receiving, there should be not recv_size */
691
9.74k
  DEBUGASSERT((conn->recv_idx >= 0) || (recv_size == -1));
692
9.74k
  k->size = recv_size;
693
9.74k
  k->header = !!conn->scheme->run->write_resp_hd;
694
  /* by default, we do not shutdown at the end of the transfer */
695
9.74k
  k->shutdown = FALSE;
696
9.74k
  k->shutdown_err_ignore = FALSE;
697
698
  /* The code sequence below is placed in this function because all necessary
699
     input is not always known in do_complete() as this function may be called
700
     after that */
701
9.74k
  if(!k->header && (recv_size > 0))
702
0
    Curl_pgrsSetDownloadSize(data, recv_size);
703
704
  /* we want header and/or body, if neither then do not do this! */
705
9.74k
  if(conn->scheme->run->write_resp_hd || !data->req.no_body) {
706
9.74k
    if(conn->recv_idx != -1)
707
9.74k
      CURL_REQ_SET_RECV(data);
708
9.74k
    if(conn->send_idx != -1)
709
9.74k
      CURL_REQ_SET_SEND(data);
710
9.74k
  }
711
9.74k
  CURL_TRC_M(data, "xfer_setup: recv_idx=%d, send_idx=%d",
712
9.74k
             conn->recv_idx, conn->send_idx);
713
9.74k
}
714
715
void Curl_xfer_setup_nop(struct Curl_easy *data)
716
0
{
717
0
  xfer_setup(data, -1, -1, -1);
718
0
}
719
720
void Curl_xfer_setup_sendrecv(struct Curl_easy *data,
721
                              int8_t sockindex,
722
                              curl_off_t recv_size)
723
9.74k
{
724
9.74k
  xfer_setup(data, sockindex, sockindex, recv_size);
725
9.74k
}
726
727
void Curl_xfer_setup_send(struct Curl_easy *data,
728
                          int8_t sockindex)
729
0
{
730
0
  xfer_setup(data, sockindex, -1, -1);
731
0
}
732
733
void Curl_xfer_setup_recv(struct Curl_easy *data,
734
                          int8_t sockindex,
735
                          curl_off_t recv_size)
736
0
{
737
0
  xfer_setup(data, -1, sockindex, recv_size);
738
0
}
739
740
void Curl_xfer_set_shutdown(struct Curl_easy *data,
741
                            bool shutdown,
742
                            bool ignore_errors)
743
0
{
744
  /* Shutdown should only be set when the transfer only sends or receives. */
745
0
  DEBUGASSERT(!shutdown ||
746
0
              (data->conn->send_idx < 0) || (data->conn->recv_idx < 0));
747
0
  data->req.shutdown = shutdown;
748
0
  data->req.shutdown_err_ignore = ignore_errors;
749
0
}
750
751
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
752
                              const char *buf, size_t blen,
753
                              bool is_eos)
754
13.4k
{
755
13.4k
  CURLcode result = CURLE_OK;
756
757
13.4k
  if(data->conn->scheme->run->write_resp) {
758
    /* protocol handlers offering this function take full responsibility
759
     * for writing all received download data to the client. */
760
13.4k
    result = data->conn->scheme->run->write_resp(data, buf, blen, is_eos);
761
13.4k
  }
762
0
  else {
763
    /* No special handling by protocol handler, write all received data
764
     * as BODY to the client. */
765
0
    if(blen || is_eos) {
766
0
      int cwtype = CLIENTWRITE_BODY;
767
0
      if(is_eos)
768
0
        cwtype |= CLIENTWRITE_EOS;
769
0
      result = Curl_client_write(data, cwtype, buf, blen);
770
0
    }
771
0
  }
772
773
13.4k
  if(!result && is_eos) {
774
    /* If we wrote the EOS, we are definitely done */
775
207
    data->req.eos_written = TRUE;
776
207
    data->req.download_done = TRUE;
777
207
  }
778
13.4k
  CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
779
13.4k
                 blen, is_eos, (int)result);
780
13.4k
  return result;
781
13.4k
}
782
783
bool Curl_xfer_write_is_paused(struct Curl_easy *data)
784
0
{
785
0
  return Curl_cwriter_is_paused(data);
786
0
}
787
788
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
789
                                 const char *hd0, size_t hdlen, bool is_eos)
790
0
{
791
0
  if(data->conn->scheme->run->write_resp_hd) {
792
0
    DEBUGASSERT(!hd0[hdlen]); /* null-terminated */
793
    /* protocol handlers offering this function take full responsibility
794
     * for writing all received download data to the client. */
795
0
    return data->conn->scheme->run->write_resp_hd(data, hd0, hdlen, is_eos);
796
0
  }
797
  /* No special handling by protocol handler, write as response bytes */
798
0
  return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
799
0
}
800
801
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
802
11.5k
{
803
11.5k
  (void)premature;
804
11.5k
  return Curl_cw_out_done(data);
805
11.5k
}
806
807
bool Curl_xfer_needs_flush(struct Curl_easy *data)
808
82.6k
{
809
82.6k
  return Curl_conn_needs_flush(data, data->conn->send_idx);
810
82.6k
}
811
812
CURLcode Curl_xfer_flush(struct Curl_easy *data)
813
0
{
814
0
  return Curl_conn_flush(data, data->conn->send_idx);
815
0
}
816
817
CURLcode Curl_xfer_send(struct Curl_easy *data,
818
                        const void *buf, size_t blen, bool eos,
819
                        size_t *pnwritten)
820
10.8k
{
821
10.8k
  CURLcode result;
822
823
10.8k
  DEBUGASSERT(data);
824
10.8k
  DEBUGASSERT(data->conn);
825
826
10.8k
  result = Curl_conn_send(data, data->conn->send_idx,
827
10.8k
                          buf, blen, eos, pnwritten);
828
10.8k
  if(result == CURLE_AGAIN) {
829
0
    result = CURLE_OK;
830
0
    *pnwritten = 0;
831
0
  }
832
10.8k
  else if(!result && *pnwritten)
833
10.8k
    data->info.request_size += *pnwritten;
834
835
10.8k
  DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
836
10.8k
               blen, eos, (int)result, *pnwritten));
837
10.8k
  return result;
838
10.8k
}
839
840
CURLcode Curl_xfer_recv(struct Curl_easy *data,
841
                        char *buf, size_t blen,
842
                        size_t *pnrcvd)
843
94.5k
{
844
94.5k
  DEBUGASSERT(data);
845
94.5k
  DEBUGASSERT(data->conn);
846
94.5k
  DEBUGASSERT(data->set.buffer_size > 0);
847
848
94.5k
  if(curlx_uitouz(data->set.buffer_size) < blen)
849
0
    blen = curlx_uitouz(data->set.buffer_size);
850
94.5k
  return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
851
94.5k
}
852
853
CURLcode Curl_xfer_send_close(struct Curl_easy *data)
854
9.99k
{
855
9.99k
  Curl_conn_ev_data_done_send(data);
856
9.99k
  return CURLE_OK;
857
9.99k
}
858
859
bool Curl_xfer_is_blocked(struct Curl_easy *data)
860
83.3k
{
861
83.3k
  bool want_send = CURL_REQ_WANT_SEND(data);
862
83.3k
  bool want_recv = CURL_REQ_WANT_RECV(data);
863
83.3k
  if(!want_send)
864
82.4k
    return want_recv && Curl_xfer_recv_is_paused(data);
865
923
  else if(!want_recv)
866
0
    return want_send && Curl_xfer_send_is_paused(data);
867
923
  else
868
923
    return Curl_xfer_recv_is_paused(data) && Curl_xfer_send_is_paused(data);
869
83.3k
}
870
871
bool Curl_xfer_send_is_paused(struct Curl_easy *data)
872
1.21k
{
873
1.21k
  return Curl_rlimit_is_blocked(&data->progress.ul.rlimit);
874
1.21k
}
875
876
bool Curl_xfer_recv_is_paused(struct Curl_easy *data)
877
106k
{
878
106k
  return Curl_rlimit_is_blocked(&data->progress.dl.rlimit);
879
106k
}
880
881
CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable)
882
0
{
883
0
  CURLcode result = CURLE_OK;
884
0
  Curl_rlimit_block(&data->progress.ul.rlimit, enable, Curl_pgrs_now(data));
885
0
  if(!enable && Curl_creader_is_paused(data))
886
0
    result = Curl_creader_unpause(data);
887
0
  Curl_pgrsSendPause(data, enable);
888
0
  return result;
889
0
}
890
891
CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable)
892
0
{
893
0
  CURLcode result = CURLE_OK;
894
0
  Curl_rlimit_block(&data->progress.dl.rlimit, enable, Curl_pgrs_now(data));
895
0
  if(!enable && Curl_cwriter_is_paused(data))
896
0
    result = Curl_cwriter_unpause(data);
897
0
  Curl_conn_ev_data_pause(data, enable);
898
0
  Curl_pgrsRecvPause(data, enable);
899
0
  return result;
900
0
}
901
902
bool Curl_xfer_is_secure(struct Curl_easy *data)
903
19.4k
{
904
19.4k
#ifndef CURL_DISABLE_PROXY
905
19.4k
  if(data->conn && data->conn->bits.origin_is_proxy) {
906
    /* talking to a forward proxy, not secure. we do not use
907
     * a forward proxy for https: and other 's' URLs. Let's just check that
908
     * this did not fail somewhere. */
909
0
    DEBUGASSERT(!(data->state.origin->scheme->flags & PROTOPT_SSL));
910
0
    return FALSE;
911
0
  }
912
19.4k
#endif
913
19.4k
  return (data->state.origin->scheme->flags & PROTOPT_SSL);
914
19.4k
}