Coverage Report

Created: 2026-10-15 06:18

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