Coverage Report

Created: 2026-09-04 07:16

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.9k
{
88
73.9k
  struct curl_slist *head;
89
73.9k
  DEBUGASSERT(thislen);
90
73.9k
  DEBUGASSERT(thisheader[thislen - 1] != ':');
91
92
394k
  for(head = data->set.headers; head; head = head->next) {
93
322k
    if(curl_strnequal(head->data, thisheader, thislen) &&
94
3.73k
       Curl_headersep(head->data[thislen]))
95
2.40k
      return head->data;
96
322k
  }
97
98
71.4k
  return NULL;
99
73.9k
}
100
#endif
101
102
static int data_pending(struct Curl_easy *data, bool rcvd_eagain)
103
4.04k
{
104
4.04k
  struct connectdata *conn = data->conn;
105
106
4.04k
  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
4.04k
  return (!rcvd_eagain &&
112
0
          conn->scheme->protocol & (CURLPROTO_SCP | CURLPROTO_SFTP)) ||
113
4.04k
         Curl_conn_data_pending(data, FIRSTSOCKET);
114
4.04k
}
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
6
{
122
6
  if((timeofdoc == 0) || (data->set.timevalue == 0))
123
6
    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_conn_shutdown(data, data->conn->recv_idx, done);
151
0
}
152
153
static bool xfer_recv_shutdown_started(struct Curl_easy *data)
154
21.7k
{
155
21.7k
  if(!data || !data->conn)
156
0
    return FALSE;
157
21.7k
  return Curl_shutdown_started(data->conn, data->conn->recv_idx);
158
21.7k
}
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_conn_shutdown(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.0k
{
180
22.0k
  CURLcode result;
181
182
22.0k
  DEBUGASSERT(blen > 0);
183
22.0k
  *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.0k
  if(!eos_reliable && !data->req.header && data->req.size != -1) {
187
363
    blen = curlx_sotouz_range(data->req.size - data->req.bytecount, 0, blen);
188
363
  }
189
21.7k
  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.0k
  if(blen) {
195
22.0k
    result = Curl_xfer_recv(data, buf, blen, pnread);
196
22.0k
    if(result)
197
10.6k
      return result;
198
22.0k
  }
199
200
11.4k
  if(*pnread == 0) {
201
4.09k
    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
4.09k
    DEBUGF(infof(data, "sendrecv_dl: we are done"));
211
4.09k
  }
212
11.4k
  return CURLE_OK;
213
11.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
16.5k
{
223
16.5k
  struct connectdata *conn = data->conn;
224
16.5k
  CURLcode result = CURLE_OK;
225
16.5k
  char *buf, *xfer_buf;
226
16.5k
  size_t blen, xfer_blen;
227
16.5k
  int maxloops = 10;
228
16.5k
  bool is_multiplex = FALSE;
229
16.5k
  bool rcvd_eagain = FALSE;
230
16.5k
  bool is_eos = FALSE, rate_limited = FALSE;
231
232
16.5k
  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
233
16.5k
  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.1k
  do {
239
22.1k
    size_t bytestoread;
240
241
22.1k
    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.1k
      is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
246
22.1k
    }
247
248
22.1k
    buf = xfer_buf;
249
22.1k
    bytestoread = xfer_blen;
250
251
22.1k
    if(bytestoread && Curl_rlimit_active(&data->progress.dl.rlimit)) {
252
5.33k
      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
5.33k
      if(dl_avail <= 0) {
261
34
        rate_limited = TRUE;
262
34
        break;
263
34
      }
264
5.29k
      if(dl_avail < (curl_off_t)bytestoread)
265
4.52k
        bytestoread = (size_t)dl_avail;
266
5.29k
    }
267
268
22.0k
    rcvd_eagain = FALSE;
269
22.0k
    result = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &blen);
270
22.0k
    if(result) {
271
10.6k
      if(result != CURLE_AGAIN)
272
6.61k
        goto out; /* real error */
273
4.04k
      rcvd_eagain = TRUE;
274
4.04k
      result = CURLE_OK;
275
4.04k
      if(data->req.download_done && data->req.no_body &&
276
2
         !data->req.resp_trailer) {
277
2
        DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
278
2
                     "not waiting for EOS"));
279
2
        blen = 0;
280
        /* continue as if we received the EOS */
281
2
      }
282
4.04k
      else
283
4.04k
        break; /* get out of loop */
284
4.04k
    }
285
286
    /* We only get a 0-length receive at the end of the response */
287
11.4k
    is_eos = (blen == 0);
288
289
11.4k
    if(!blen) {
290
4.09k
      result = Curl_req_stop_send_recv(data);
291
4.09k
      if(result)
292
0
        goto out;
293
4.09k
      if(k->eos_written) /* already did write this to client, leave */
294
0
        break;
295
4.09k
    }
296
297
11.4k
    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
298
11.4k
    if(result || data->req.done)
299
1.47k
      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
9.94k
    if((!is_multiplex && data->req.download_done) || is_eos) {
305
4.13k
      CURL_REQ_CLEAR_RECV(data);
306
4.13k
    }
307
    /* if we stopped receiving, leave the loop */
308
9.94k
    if(!CURL_REQ_WANT_RECV(data))
309
4.13k
      break;
310
311
9.94k
  } while(maxloops--);
312
313
8.50k
  if(!is_eos && !rate_limited && CURL_REQ_WANT_RECV(data) &&
314
4.33k
     (!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
289
    Curl_multi_mark_dirty(data);
318
289
    CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty");
319
289
  }
320
321
8.50k
  if(!CURL_REQ_WANT_RECV(data) && CURL_REQ_WANT_SEND(data) &&
322
106
     (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
2
    infof(data, "we are done reading and this is set to close, stop send");
327
2
    Curl_req_abort_sending(data);
328
2
  }
329
330
16.5k
out:
331
16.5k
  Curl_multi_xfer_buf_release(data, xfer_buf);
332
16.5k
  if(result)
333
7.93k
    DEBUGF(infof(data, "sendrecv_dl() -> %d", (int)result));
334
16.5k
  return result;
335
8.50k
}
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.03k
{
342
  /* We should not get here when the sending is already done. */
343
1.03k
  DEBUGASSERT(!Curl_req_done_sending(data));
344
345
1.03k
  if(!Curl_req_done_sending(data))
346
1.03k
    return Curl_req_send_more(data);
347
0
  return CURLE_OK;
348
1.03k
}
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
16.7k
{
356
16.7k
  struct SingleRequest *k = &data->req;
357
16.7k
  const struct curltime *pnow = NULL;
358
16.7k
  CURLcode result = CURLE_OK;
359
360
16.7k
  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
16.7k
  if(CURL_REQ_WANT_RECV(data)) {
368
16.5k
    result = sendrecv_dl(data, k);
369
16.5k
    if(result || data->req.done)
370
8.09k
      goto out;
371
16.5k
  }
372
373
  /* If we still have writing to do, we check if we have a writable socket. */
374
8.64k
  if(Curl_req_want_send(data)) {
375
1.03k
    result = sendrecv_ul(data);
376
1.03k
    if(result)
377
29
      goto out;
378
1.03k
  }
379
380
8.61k
  pnow = Curl_pgrs_now(data);
381
8.61k
  if(CURL_REQ_WANT_IO(data)) {
382
4.55k
    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
4.55k
  }
400
4.06k
  else {
401
    /*
402
     * The transfer has been performed. Make some general checks before
403
     * returning.
404
     */
405
4.06k
    if(!data->req.no_body && (k->size != -1) &&
406
416
       (k->bytecount != k->size) && !k->newurl) {
407
51
      failf(data, "transfer closed with %" FMT_OFF_T
408
51
            " bytes remaining to read", k->size - k->bytecount);
409
51
      result = CURLE_PARTIAL_FILE;
410
51
      goto out;
411
51
    }
412
4.06k
  }
413
414
  /* If there is nothing more to send/recv, the request is done */
415
8.56k
  if(!CURL_REQ_WANT_IO(data))
416
4.00k
    data->req.done = TRUE;
417
418
8.56k
  result = Curl_pgrsCheckX(data, pnow);
419
420
16.7k
out:
421
16.7k
  if(result)
422
8.01k
    DEBUGF(infof(data, "Curl_sendrecv() -> %d", (int)result));
423
16.7k
  return result;
424
8.56k
}
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
17.0k
{
430
17.0k
  data->state.fread_func = data->set.fread_func_set;
431
17.0k
  data->state.in = data->set.in_set;
432
17.0k
  data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
433
17.0k
}
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
17.0k
{
442
17.0k
  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
17.0k
  data->state.retrycount = 0;
451
452
17.0k
  if(!CURL_EASY_STR(data, STRING_SET_URL) && !data->set.uh) {
453
    /* we cannot do anything without URL */
454
2.45k
    failf(data, "No URL set");
455
2.45k
    return CURLE_URL_MALFORMAT;
456
2.45k
  }
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
14.5k
  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
14.5k
  Curl_bufref_set(&data->state.url, CURL_EASY_STR(data, STRING_SET_URL),
476
14.5k
                  0, NULL);
477
478
14.5k
  if(data->set.postfields && data->set.set_resume_from) {
479
    /* we cannot */
480
5
    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
481
5
    return CURLE_BAD_FUNCTION_ARGUMENT;
482
5
  }
483
484
14.5k
  data->state.prefer_ascii = data->set.prefer_ascii;
485
14.5k
#ifdef CURL_LIST_ONLY_PROTOCOL
486
14.5k
  data->state.list_only = data->set.list_only;
487
14.5k
#endif
488
14.5k
  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
14.5k
  Curl_peer_unlink(&data->state.initial_origin);
493
14.5k
  Curl_peer_unlink(&data->state.origin);
494
14.5k
  data->state.requests = 0;
495
14.5k
  data->state.followlocation = 0; /* reset the location-follow counter */
496
14.5k
  data->state.this_is_a_follow = FALSE; /* reset this */
497
14.5k
  data->state.http_ignorecustom = FALSE; /* use custom HTTP method */
498
14.5k
  data->state.errorbuf = FALSE; /* no error has occurred */
499
14.5k
#ifndef CURL_DISABLE_HTTP
500
14.5k
  Curl_http_neg_init(data, &data->state.http_neg);
501
14.5k
#endif
502
14.5k
  data->state.authproblem = FALSE;
503
14.5k
  data->state.authhost.want = data->set.httpauth;
504
14.5k
  data->state.authproxy.want = data->set.proxyauth;
505
14.5k
  curlx_safefree(data->info.wouldredirect);
506
14.5k
  Curl_data_priority_clear_state(data);
507
14.5k
  if(data->set.http_auto_referer)
508
93
    Curl_bufref_free(&data->state.referer);
509
14.5k
  if(CURL_EASY_STR(data, STRING_SET_REFERER))
510
90
    Curl_bufref_set(&data->state.referer,
511
90
                    CURL_EASY_STR(data, STRING_SET_REFERER), 0, NULL);
512
14.4k
  else
513
14.4k
    Curl_bufref_free(&data->state.referer);
514
515
14.5k
  if(data->state.httpreq == HTTPREQ_PUT)
516
192
    data->state.infilesize = data->set.filesize;
517
14.3k
  else if((data->state.httpreq != HTTPREQ_GET) &&
518
2.14k
          (data->state.httpreq != HTTPREQ_HEAD)) {
519
2.04k
    data->state.infilesize = data->set.postfieldsize;
520
2.04k
    if(data->set.postfields && (data->state.infilesize == -1))
521
146
      data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
522
2.04k
  }
523
12.3k
  else
524
12.3k
    data->state.infilesize = 0;
525
526
  /* If there is a list of cookie files to read, do it now! */
527
14.5k
  result = Curl_cookie_loadfiles(data,
528
14.5k
                                 data->set.cookiesession ?
529
14.5k
                                 COOKIE_NOSESSION : 0);
530
14.5k
  if(!result)
531
14.5k
    Curl_cookie_run(data); /* activate */
532
533
  /* If there is a list of host pairs to deal with */
534
14.5k
  if(!result && data->state.resolve)
535
0
    result = Curl_loadhostpairs(data);
536
537
14.5k
  if(!result)
538
    /* If there is a list of hsts files to read */
539
14.5k
    result = Curl_hsts_loadfiles(data);
540
541
14.5k
  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
14.5k
    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
14.5k
    Curl_initinfo(data); /* reset session-specific information "variables" */
556
14.5k
    Curl_pgrsResetTransferSizes(data);
557
14.5k
    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
14.5k
    data->state.authhost.picked &= data->state.authhost.want;
563
14.5k
    data->state.authproxy.picked &= data->state.authproxy.want;
564
565
14.5k
#ifndef CURL_DISABLE_FTP
566
14.5k
    data->state.wildcardmatch = data->set.wildcard_enabled;
567
14.5k
    if(data->state.wildcardmatch) {
568
41
      struct WildcardData *wc;
569
41
      if(!data->wildcard) {
570
41
        data->wildcard = curlx_calloc(1, sizeof(struct WildcardData));
571
41
        if(!data->wildcard)
572
0
          return CURLE_OUT_OF_MEMORY;
573
41
      }
574
41
      wc = data->wildcard;
575
41
      if(wc->state < CURLWC_INIT) {
576
41
        if(wc->ftpwc)
577
0
          wc->dtor(wc->ftpwc);
578
41
        curlx_safefree(wc->pattern);
579
41
        curlx_safefree(wc->path);
580
41
        Curl_wildcard_init(wc); /* init wildcard structures */
581
41
      }
582
41
    }
583
14.5k
#endif
584
14.5k
    result = Curl_hsts_loadcb(data, data->hsts);
585
14.5k
  }
586
587
14.5k
  data->req.headerbytecount = 0;
588
14.5k
  Curl_headers_cleanup(data);
589
14.5k
  return result;
590
14.5k
}
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
6.00k
{
597
6.00k
  struct connectdata *conn = data->conn;
598
6.00k
  bool retry = FALSE;
599
6.00k
  *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
6.00k
  if(data->state.upload &&
605
116
     !(conn->scheme->protocol & (PROTO_FAMILY_HTTP | CURLPROTO_RTSP)))
606
0
    return CURLE_OK;
607
608
6.00k
  if(conn->bits.reuse &&
609
0
     (data->req.bytecount + data->req.headerbytecount == 0) &&
610
0
     ((!data->req.no_body && !data->req.done) ||
611
0
      (conn->scheme->protocol & PROTO_FAMILY_HTTP))
612
0
#ifndef CURL_DISABLE_RTSP
613
0
     && (data->set.rtspreq != RTSPREQ_RECEIVE)
614
6.00k
#endif
615
6.00k
    )
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
0
    retry = TRUE;
624
6.00k
  else if(data->state.refused_stream &&
625
1.73k
          (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
1.73k
    infof(data, "REFUSED_STREAM, retrying a fresh connect");
632
1.73k
    data->state.refused_stream = FALSE; /* clear again */
633
1.73k
    retry = TRUE;
634
1.73k
  }
635
6.00k
  if(retry) {
636
1.73k
#define CONN_MAX_RETRIES 5
637
1.73k
    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
1.73k
    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
644
1.73k
          data->state.retrycount);
645
1.73k
    *url = Curl_bufref_dup(&data->state.url);
646
1.73k
    if(!*url)
647
0
      return CURLE_OUT_OF_MEMORY;
648
649
1.73k
    connclose(conn); /* close this connection */
650
1.73k
    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
1.73k
    Curl_creader_set_rewind(data, TRUE);
655
1.73k
  }
656
6.00k
  return CURLE_OK;
657
6.00k
}
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
12.6k
{
666
12.6k
  struct SingleRequest *k = &data->req;
667
12.6k
  struct connectdata *conn = data->conn;
668
669
12.6k
  DEBUGASSERT(conn);
670
  /* indexes are in range */
671
12.6k
  DEBUGASSERT((send_idx <= 1) && (send_idx >= -1));
672
12.6k
  DEBUGASSERT((recv_idx <= 1) && (recv_idx >= -1));
673
  /* if request wants to send, switching off the send direction is wrong */
674
12.6k
  DEBUGASSERT((send_idx >= 0) || !Curl_req_want_send(data));
675
676
12.6k
  conn->send_idx = send_idx;
677
12.6k
  conn->recv_idx = recv_idx;
678
679
  /* without receiving, there should be not recv_size */
680
12.6k
  DEBUGASSERT((conn->recv_idx >= 0) || (recv_size == -1));
681
12.6k
  k->size = recv_size;
682
12.6k
  k->header = !!conn->scheme->run->write_resp_hd;
683
  /* by default, we do not shutdown at the end of the transfer */
684
12.6k
  k->shutdown = FALSE;
685
12.6k
  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
12.6k
  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
12.6k
  if(conn->scheme->run->write_resp_hd || !data->req.no_body) {
695
12.6k
    if(conn->recv_idx != -1)
696
12.6k
      CURL_REQ_SET_RECV(data);
697
12.6k
    if(conn->send_idx != -1)
698
12.6k
      CURL_REQ_SET_SEND(data);
699
12.6k
  }
700
12.6k
  CURL_TRC_M(data, "xfer_setup: recv_idx=%d, send_idx=%d",
701
12.6k
             conn->recv_idx, conn->send_idx);
702
12.6k
}
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
12.6k
{
713
12.6k
  xfer_setup(data, sockindex, sockindex, recv_size);
714
12.6k
}
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
11.6k
{
744
11.6k
  CURLcode result = CURLE_OK;
745
746
11.6k
  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
11.6k
    result = data->conn->scheme->run->write_resp(data, buf, blen, is_eos);
750
11.6k
  }
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
11.6k
  if(!result && is_eos) {
763
    /* If we wrote the EOS, we are definitely done */
764
3.73k
    data->req.eos_written = TRUE;
765
3.73k
    data->req.download_done = TRUE;
766
3.73k
  }
767
11.6k
  CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
768
11.6k
                 blen, is_eos, (int)result);
769
11.6k
  return result;
770
11.6k
}
771
772
bool Curl_xfer_write_is_paused(struct Curl_easy *data)
773
271
{
774
271
  return Curl_cwriter_is_paused(data);
775
271
}
776
777
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
778
                                 const char *hd0, size_t hdlen, bool is_eos)
779
39.3k
{
780
39.3k
  if(data->conn->scheme->run->write_resp_hd) {
781
39.3k
    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
39.3k
    return data->conn->scheme->run->write_resp_hd(data, hd0, hdlen, is_eos);
785
39.3k
  }
786
  /* No special handling by protocol handler, write as response bytes */
787
0
  return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
788
39.3k
}
789
790
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
791
16.0k
{
792
16.0k
  (void)premature;
793
16.0k
  return Curl_cw_out_done(data);
794
16.0k
}
795
796
bool Curl_xfer_needs_flush(struct Curl_easy *data)
797
17.7k
{
798
17.7k
  return Curl_conn_needs_flush(data, data->conn->send_idx);
799
17.7k
}
800
801
CURLcode Curl_xfer_flush(struct Curl_easy *data)
802
154
{
803
154
  return Curl_conn_flush(data, data->conn->send_idx);
804
154
}
805
806
CURLcode Curl_xfer_send(struct Curl_easy *data,
807
                        const void *buf, size_t blen, bool eos,
808
                        size_t *pnwritten)
809
14.8k
{
810
14.8k
  CURLcode result;
811
812
14.8k
  DEBUGASSERT(data);
813
14.8k
  DEBUGASSERT(data->conn);
814
815
14.8k
  result = Curl_conn_send(data, data->conn->send_idx,
816
14.8k
                          buf, blen, eos, pnwritten);
817
14.8k
  if(result == CURLE_AGAIN) {
818
257
    result = CURLE_OK;
819
257
    *pnwritten = 0;
820
257
  }
821
14.6k
  else if(!result && *pnwritten)
822
14.4k
    data->info.request_size += *pnwritten;
823
824
14.8k
  DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
825
14.8k
               blen, eos, (int)result, *pnwritten));
826
14.8k
  return result;
827
14.8k
}
828
829
CURLcode Curl_xfer_recv(struct Curl_easy *data,
830
                        char *buf, size_t blen,
831
                        size_t *pnrcvd)
832
22.0k
{
833
22.0k
  DEBUGASSERT(data);
834
22.0k
  DEBUGASSERT(data->conn);
835
22.0k
  DEBUGASSERT(data->set.buffer_size > 0);
836
837
22.0k
  if(curlx_uitouz(data->set.buffer_size) < blen)
838
0
    blen = curlx_uitouz(data->set.buffer_size);
839
22.0k
  return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
840
22.0k
}
841
842
CURLcode Curl_xfer_send_close(struct Curl_easy *data)
843
11.9k
{
844
11.9k
  Curl_conn_ev_data_done_send(data);
845
11.9k
  return CURLE_OK;
846
11.9k
}
847
848
bool Curl_xfer_is_blocked(struct Curl_easy *data)
849
16.7k
{
850
16.7k
  bool want_send = CURL_REQ_WANT_SEND(data);
851
16.7k
  bool want_recv = CURL_REQ_WANT_RECV(data);
852
16.7k
  if(!want_send)
853
15.3k
    return want_recv && Curl_xfer_recv_is_paused(data);
854
1.42k
  else if(!want_recv)
855
141
    return want_send && Curl_xfer_send_is_paused(data);
856
1.28k
  else
857
1.28k
    return Curl_xfer_recv_is_paused(data) && Curl_xfer_send_is_paused(data);
858
16.7k
}
859
860
bool Curl_xfer_send_is_paused(struct Curl_easy *data)
861
3.34k
{
862
3.34k
  return Curl_rlimit_is_blocked(&data->progress.ul.rlimit);
863
3.34k
}
864
865
bool Curl_xfer_recv_is_paused(struct Curl_easy *data)
866
33.2k
{
867
33.2k
  return Curl_rlimit_is_blocked(&data->progress.dl.rlimit);
868
33.2k
}
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
34.9k
{
893
34.9k
#ifndef CURL_DISABLE_PROXY
894
34.9k
  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
387
    DEBUGASSERT(!(data->state.origin->scheme->flags & PROTOPT_SSL));
899
387
    return FALSE;
900
387
  }
901
34.5k
#endif
902
34.5k
  return (data->state.origin->scheme->flags & PROTOPT_SSL);
903
34.9k
}