Coverage Report

Created: 2025-08-26 07:08

/src/PROJ/curl/lib/connect.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#ifdef HAVE_NETINET_IN_H
28
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
29
#endif
30
#ifdef HAVE_SYS_UN_H
31
#include <sys/un.h> /* for sockaddr_un */
32
#endif
33
#ifdef HAVE_LINUX_TCP_H
34
#include <linux/tcp.h>
35
#elif defined(HAVE_NETINET_TCP_H)
36
#include <netinet/tcp.h>
37
#endif
38
#ifdef HAVE_SYS_IOCTL_H
39
#include <sys/ioctl.h>
40
#endif
41
#ifdef HAVE_NETDB_H
42
#include <netdb.h>
43
#endif
44
#ifdef HAVE_FCNTL_H
45
#include <fcntl.h>
46
#endif
47
#ifdef HAVE_ARPA_INET_H
48
#include <arpa/inet.h>
49
#endif
50
51
#ifdef __VMS
52
#include <in.h>
53
#include <inet.h>
54
#endif
55
56
#include "urldata.h"
57
#include "sendf.h"
58
#include "if2ip.h"
59
#include "strerror.h"
60
#include "cfilters.h"
61
#include "connect.h"
62
#include "cf-haproxy.h"
63
#include "cf-https-connect.h"
64
#include "cf-ip-happy.h"
65
#include "cf-socket.h"
66
#include "select.h"
67
#include "url.h" /* for Curl_safefree() */
68
#include "multiif.h"
69
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
70
#include "curlx/inet_ntop.h"
71
#include "curlx/inet_pton.h"
72
#include "vtls/vtls.h" /* for vtsl cfilters */
73
#include "progress.h"
74
#include "curlx/warnless.h"
75
#include "conncache.h"
76
#include "multihandle.h"
77
#include "share.h"
78
#include "http_proxy.h"
79
#include "socks.h"
80
81
/* The last 3 #include files should be in this order */
82
#include "curl_printf.h"
83
#include "curl_memory.h"
84
#include "memdebug.h"
85
86
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
87
88
enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
89
0
{
90
0
  if(len == 2) {
91
0
    if(curl_strnequal(name, "h1", 2))
92
0
      return ALPN_h1;
93
0
    if(curl_strnequal(name, "h2", 2))
94
0
      return ALPN_h2;
95
0
    if(curl_strnequal(name, "h3", 2))
96
0
      return ALPN_h3;
97
0
  }
98
0
  else if(len == 8) {
99
0
    if(curl_strnequal(name, "http/1.1", 8))
100
0
      return ALPN_h1;
101
0
  }
102
0
  return ALPN_none; /* unknown, probably rubbish input */
103
0
}
104
105
#endif
106
107
/*
108
 * Curl_timeleft() returns the amount of milliseconds left allowed for the
109
 * transfer/connection. If the value is 0, there is no timeout (ie there is
110
 * infinite time left). If the value is negative, the timeout time has already
111
 * elapsed.
112
 * @param data the transfer to check on
113
 * @param nowp timestamp to use for calculation, NULL to use curlx_now()
114
 * @param duringconnect TRUE iff connect timeout is also taken into account.
115
 * @unittest: 1303
116
 */
117
timediff_t Curl_timeleft(struct Curl_easy *data,
118
                         struct curltime *nowp,
119
                         bool duringconnect)
120
0
{
121
0
  timediff_t timeleft_ms = 0;
122
0
  timediff_t ctimeleft_ms = 0;
123
0
  struct curltime now;
124
125
  /* The duration of a connect and the total transfer are calculated from two
126
     different time-stamps. It can end up with the total timeout being reached
127
     before the connect timeout expires and we must acknowledge whichever
128
     timeout that is reached first. The total timeout is set per entire
129
     operation, while the connect timeout is set per connect. */
130
0
  if(data->set.timeout <= 0 && !duringconnect)
131
0
    return 0; /* no timeout in place or checked, return "no limit" */
132
133
0
  if(!nowp) {
134
0
    now = curlx_now();
135
0
    nowp = &now;
136
0
  }
137
138
0
  if(data->set.timeout > 0) {
139
0
    timeleft_ms = data->set.timeout -
140
0
                  curlx_timediff(*nowp, data->progress.t_startop);
141
0
    if(!timeleft_ms)
142
0
      timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
143
0
    if(!duringconnect)
144
0
      return timeleft_ms; /* no connect check, this is it */
145
0
  }
146
147
0
  if(duringconnect) {
148
0
    timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
149
0
      data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
150
0
    ctimeleft_ms = ctimeout_ms -
151
0
                   curlx_timediff(*nowp, data->progress.t_startsingle);
152
0
    if(!ctimeleft_ms)
153
0
      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
154
0
    if(!timeleft_ms)
155
0
      return ctimeleft_ms; /* no general timeout, this is it */
156
0
  }
157
  /* return minimal time left or max amount already expired */
158
0
  return (ctimeleft_ms < timeleft_ms) ? ctimeleft_ms : timeleft_ms;
159
0
}
160
161
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
162
                         int timeout_ms, struct curltime *nowp)
163
0
{
164
0
  struct curltime now;
165
166
0
  DEBUGASSERT(data->conn);
167
0
  if(!nowp) {
168
0
    now = curlx_now();
169
0
    nowp = &now;
170
0
  }
171
0
  data->conn->shutdown.start[sockindex] = *nowp;
172
0
  data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
173
0
    (timediff_t)timeout_ms :
174
0
    ((data->set.shutdowntimeout > 0) ?
175
0
     data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
176
  /* Set a timer, unless we operate on the admin handle */
177
0
  if(data->mid && (data->conn->shutdown.timeout_ms > 0))
178
0
    Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
179
0
                   EXPIRE_SHUTDOWN);
180
0
}
181
182
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
183
                                  struct curltime *nowp)
184
0
{
185
0
  struct curltime now;
186
0
  timediff_t left_ms;
187
188
0
  if(!conn->shutdown.start[sockindex].tv_sec ||
189
0
     (conn->shutdown.timeout_ms <= 0))
190
0
    return 0; /* not started or no limits */
191
192
0
  if(!nowp) {
193
0
    now = curlx_now();
194
0
    nowp = &now;
195
0
  }
196
0
  left_ms = conn->shutdown.timeout_ms -
197
0
            curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
198
0
  return left_ms ? left_ms : -1;
199
0
}
200
201
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
202
                                       struct curltime *nowp)
203
0
{
204
0
  timediff_t left_ms = 0, ms;
205
0
  struct curltime now;
206
0
  int i;
207
208
0
  for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
209
0
    if(!conn->shutdown.start[i].tv_sec)
210
0
      continue;
211
0
    if(!nowp) {
212
0
      now = curlx_now();
213
0
      nowp = &now;
214
0
    }
215
0
    ms = Curl_shutdown_timeleft(conn, i, nowp);
216
0
    if(ms && (!left_ms || ms < left_ms))
217
0
      left_ms = ms;
218
0
  }
219
0
  return left_ms;
220
0
}
221
222
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
223
0
{
224
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
225
0
  memset(pt, 0, sizeof(*pt));
226
0
}
227
228
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
229
0
{
230
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
231
0
  return (pt->tv_sec > 0) || (pt->tv_usec > 0);
232
0
}
233
234
/* retrieves ip address and port from a sockaddr structure. note it calls
235
   curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
236
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
237
                      char *addr, int *port)
238
0
{
239
0
  struct sockaddr_in *si = NULL;
240
0
#ifdef USE_IPV6
241
0
  struct sockaddr_in6 *si6 = NULL;
242
0
#endif
243
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
244
0
  struct sockaddr_un *su = NULL;
245
#else
246
  (void)salen;
247
#endif
248
249
0
  switch(sa->sa_family) {
250
0
    case AF_INET:
251
0
      si = (struct sockaddr_in *)(void *) sa;
252
0
      if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
253
0
        unsigned short us_port = ntohs(si->sin_port);
254
0
        *port = us_port;
255
0
        return TRUE;
256
0
      }
257
0
      break;
258
0
#ifdef USE_IPV6
259
0
    case AF_INET6:
260
0
      si6 = (struct sockaddr_in6 *)(void *) sa;
261
0
      if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
262
0
                         MAX_IPADR_LEN)) {
263
0
        unsigned short us_port = ntohs(si6->sin6_port);
264
0
        *port = us_port;
265
0
        return TRUE;
266
0
      }
267
0
      break;
268
0
#endif
269
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
270
0
    case AF_UNIX:
271
0
      if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
272
0
        su = (struct sockaddr_un*)sa;
273
0
        msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
274
0
      }
275
0
      else
276
0
        addr[0] = 0; /* socket with no name */
277
0
      *port = 0;
278
0
      return TRUE;
279
0
#endif
280
0
    default:
281
0
      break;
282
0
  }
283
284
0
  addr[0] = '\0';
285
0
  *port = 0;
286
0
  CURL_SETERRNO(SOCKEAFNOSUPPORT);
287
0
  return FALSE;
288
0
}
289
290
/*
291
 * Used to extract socket and connectdata struct for the most recent
292
 * transfer on the given Curl_easy.
293
 *
294
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
295
 */
296
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
297
                                  struct connectdata **connp)
298
0
{
299
0
  DEBUGASSERT(data);
300
301
  /* this works for an easy handle:
302
   * - that has been used for curl_easy_perform()
303
   * - that is associated with a multi handle, and whose connection
304
   *   was detached with CURLOPT_CONNECT_ONLY
305
   */
306
0
  if(data->state.lastconnect_id != -1) {
307
0
    struct connectdata *conn;
308
309
0
    conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
310
0
    if(!conn) {
311
0
      data->state.lastconnect_id = -1;
312
0
      return CURL_SOCKET_BAD;
313
0
    }
314
315
0
    if(connp)
316
      /* only store this if the caller cares for it */
317
0
      *connp = conn;
318
0
    return conn->sock[FIRSTSOCKET];
319
0
  }
320
0
  return CURL_SOCKET_BAD;
321
0
}
322
323
/*
324
 * Curl_conncontrol() marks streams or connection for closure.
325
 */
326
void Curl_conncontrol(struct connectdata *conn,
327
                      int ctrl /* see defines in header */
328
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
329
                      , const char *reason
330
#endif
331
  )
332
0
{
333
  /* close if a connection, or a stream that is not multiplexed. */
334
  /* This function will be called both before and after this connection is
335
     associated with a transfer. */
336
0
  bool closeit, is_multiplex;
337
0
  DEBUGASSERT(conn);
338
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
339
  (void)reason; /* useful for debugging */
340
#endif
341
0
  is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
342
0
  closeit = (ctrl == CONNCTRL_CONNECTION) ||
343
0
    ((ctrl == CONNCTRL_STREAM) && !is_multiplex);
344
0
  if((ctrl == CONNCTRL_STREAM) && is_multiplex)
345
0
    ;  /* stream signal on multiplex conn never affects close state */
346
0
  else if((bit)closeit != conn->bits.close) {
347
0
    conn->bits.close = closeit; /* the only place in the source code that
348
                                   should assign this bit */
349
0
  }
350
0
}
351
352
typedef enum {
353
  CF_SETUP_INIT,
354
  CF_SETUP_CNNCT_EYEBALLS,
355
  CF_SETUP_CNNCT_SOCKS,
356
  CF_SETUP_CNNCT_HTTP_PROXY,
357
  CF_SETUP_CNNCT_HAPROXY,
358
  CF_SETUP_CNNCT_SSL,
359
  CF_SETUP_DONE
360
} cf_setup_state;
361
362
struct cf_setup_ctx {
363
  cf_setup_state state;
364
  int ssl_mode;
365
  int transport;
366
};
367
368
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
369
                                 struct Curl_easy *data,
370
                                 bool *done)
371
0
{
372
0
  struct cf_setup_ctx *ctx = cf->ctx;
373
0
  CURLcode result = CURLE_OK;
374
0
  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
375
376
0
  if(cf->connected) {
377
0
    *done = TRUE;
378
0
    return CURLE_OK;
379
0
  }
380
381
  /* connect current sub-chain */
382
0
connect_sub_chain:
383
0
  if(!dns)
384
0
    return CURLE_FAILED_INIT;
385
386
0
  if(cf->next && !cf->next->connected) {
387
0
    result = Curl_conn_cf_connect(cf->next, data, done);
388
0
    if(result || !*done)
389
0
      return result;
390
0
  }
391
392
0
  if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
393
0
    result = cf_ip_happy_insert_after(cf, data, ctx->transport);
394
0
    if(result)
395
0
      return result;
396
0
    ctx->state = CF_SETUP_CNNCT_EYEBALLS;
397
0
    if(!cf->next || !cf->next->connected)
398
0
      goto connect_sub_chain;
399
0
  }
400
401
  /* sub-chain connected, do we need to add more? */
402
0
#ifndef CURL_DISABLE_PROXY
403
0
  if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
404
0
    result = Curl_cf_socks_proxy_insert_after(cf, data);
405
0
    if(result)
406
0
      return result;
407
0
    ctx->state = CF_SETUP_CNNCT_SOCKS;
408
0
    if(!cf->next || !cf->next->connected)
409
0
      goto connect_sub_chain;
410
0
  }
411
412
0
  if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
413
0
#ifdef USE_SSL
414
0
    if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype)
415
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
416
0
      result = Curl_cf_ssl_proxy_insert_after(cf, data);
417
0
      if(result)
418
0
        return result;
419
0
    }
420
0
#endif /* USE_SSL */
421
422
0
#ifndef CURL_DISABLE_HTTP
423
0
    if(cf->conn->bits.tunnel_proxy) {
424
0
      result = Curl_cf_http_proxy_insert_after(cf, data);
425
0
      if(result)
426
0
        return result;
427
0
    }
428
0
#endif /* !CURL_DISABLE_HTTP */
429
0
    ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
430
0
    if(!cf->next || !cf->next->connected)
431
0
      goto connect_sub_chain;
432
0
  }
433
0
#endif /* !CURL_DISABLE_PROXY */
434
435
0
  if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
436
0
#ifndef CURL_DISABLE_PROXY
437
0
    if(data->set.haproxyprotocol) {
438
0
      if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
439
0
        failf(data, "haproxy protocol not support with SSL "
440
0
              "encryption in place (QUIC?)");
441
0
        return CURLE_UNSUPPORTED_PROTOCOL;
442
0
      }
443
0
      result = Curl_cf_haproxy_insert_after(cf, data);
444
0
      if(result)
445
0
        return result;
446
0
    }
447
0
#endif /* !CURL_DISABLE_PROXY */
448
0
    ctx->state = CF_SETUP_CNNCT_HAPROXY;
449
0
    if(!cf->next || !cf->next->connected)
450
0
      goto connect_sub_chain;
451
0
  }
452
453
0
  if(ctx->state < CF_SETUP_CNNCT_SSL) {
454
0
#ifdef USE_SSL
455
0
    if((ctx->ssl_mode == CURL_CF_SSL_ENABLE
456
0
        || (ctx->ssl_mode != CURL_CF_SSL_DISABLE
457
0
           && cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */
458
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
459
0
      result = Curl_cf_ssl_insert_after(cf, data);
460
0
      if(result)
461
0
        return result;
462
0
    }
463
0
#endif /* USE_SSL */
464
0
    ctx->state = CF_SETUP_CNNCT_SSL;
465
0
    if(!cf->next || !cf->next->connected)
466
0
      goto connect_sub_chain;
467
0
  }
468
469
0
  ctx->state = CF_SETUP_DONE;
470
0
  cf->connected = TRUE;
471
0
  *done = TRUE;
472
0
  return CURLE_OK;
473
0
}
474
475
static void cf_setup_close(struct Curl_cfilter *cf,
476
                           struct Curl_easy *data)
477
0
{
478
0
  struct cf_setup_ctx *ctx = cf->ctx;
479
480
0
  CURL_TRC_CF(data, cf, "close");
481
0
  cf->connected = FALSE;
482
0
  ctx->state = CF_SETUP_INIT;
483
484
0
  if(cf->next) {
485
0
    cf->next->cft->do_close(cf->next, data);
486
0
    Curl_conn_cf_discard_chain(&cf->next, data);
487
0
  }
488
0
}
489
490
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
491
0
{
492
0
  struct cf_setup_ctx *ctx = cf->ctx;
493
494
0
  (void)data;
495
0
  CURL_TRC_CF(data, cf, "destroy");
496
0
  Curl_safefree(ctx);
497
0
}
498
499
500
struct Curl_cftype Curl_cft_setup = {
501
  "SETUP",
502
  0,
503
  CURL_LOG_LVL_NONE,
504
  cf_setup_destroy,
505
  cf_setup_connect,
506
  cf_setup_close,
507
  Curl_cf_def_shutdown,
508
  Curl_cf_def_adjust_pollset,
509
  Curl_cf_def_data_pending,
510
  Curl_cf_def_send,
511
  Curl_cf_def_recv,
512
  Curl_cf_def_cntrl,
513
  Curl_cf_def_conn_is_alive,
514
  Curl_cf_def_conn_keep_alive,
515
  Curl_cf_def_query,
516
};
517
518
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
519
                                struct Curl_easy *data,
520
                                int transport,
521
                                int ssl_mode)
522
0
{
523
0
  struct Curl_cfilter *cf = NULL;
524
0
  struct cf_setup_ctx *ctx;
525
0
  CURLcode result = CURLE_OK;
526
527
0
  (void)data;
528
0
  ctx = calloc(1, sizeof(*ctx));
529
0
  if(!ctx) {
530
0
    result = CURLE_OUT_OF_MEMORY;
531
0
    goto out;
532
0
  }
533
0
  ctx->state = CF_SETUP_INIT;
534
0
  ctx->ssl_mode = ssl_mode;
535
0
  ctx->transport = transport;
536
537
0
  result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
538
0
  if(result)
539
0
    goto out;
540
0
  ctx = NULL;
541
542
0
out:
543
0
  *pcf = result ? NULL : cf;
544
0
  if(ctx) {
545
0
    free(ctx);
546
0
  }
547
0
  return result;
548
0
}
549
550
static CURLcode cf_setup_add(struct Curl_easy *data,
551
                             struct connectdata *conn,
552
                             int sockindex,
553
                             int transport,
554
                             int ssl_mode)
555
0
{
556
0
  struct Curl_cfilter *cf;
557
0
  CURLcode result = CURLE_OK;
558
559
0
  DEBUGASSERT(data);
560
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
561
0
  if(result)
562
0
    goto out;
563
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
564
0
out:
565
0
  return result;
566
0
}
567
568
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
569
                                    struct Curl_easy *data,
570
                                    int transport,
571
                                    int ssl_mode)
572
0
{
573
0
  struct Curl_cfilter *cf;
574
0
  CURLcode result;
575
576
0
  DEBUGASSERT(data);
577
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
578
0
  if(result)
579
0
    goto out;
580
0
  Curl_conn_cf_insert_after(cf_at, cf);
581
0
out:
582
0
  return result;
583
0
}
584
585
CURLcode Curl_conn_setup(struct Curl_easy *data,
586
                         struct connectdata *conn,
587
                         int sockindex,
588
                         struct Curl_dns_entry *dns,
589
                         int ssl_mode)
590
0
{
591
0
  CURLcode result = CURLE_OK;
592
593
0
  DEBUGASSERT(data);
594
0
  DEBUGASSERT(conn->handler);
595
0
  DEBUGASSERT(dns);
596
597
0
  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
598
0
  data->state.dns[sockindex] = dns;
599
600
0
#ifndef CURL_DISABLE_HTTP
601
0
  if(!conn->cfilter[sockindex] &&
602
0
     conn->handler->protocol == CURLPROTO_HTTPS) {
603
0
    DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
604
0
    result = Curl_cf_https_setup(data, conn, sockindex);
605
0
    if(result)
606
0
      goto out;
607
0
  }
608
0
#endif /* !CURL_DISABLE_HTTP */
609
610
  /* Still no cfilter set, apply default. */
611
0
  if(!conn->cfilter[sockindex]) {
612
0
    result = cf_setup_add(data, conn, sockindex,
613
0
                          conn->transport_wanted, ssl_mode);
614
0
    if(result)
615
0
      goto out;
616
0
  }
617
618
0
  DEBUGASSERT(conn->cfilter[sockindex]);
619
0
out:
620
0
  if(result)
621
0
    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
622
0
  return result;
623
0
}