Coverage Report

Created: 2026-01-09 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/curl_share.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
#include "urldata.h"
27
#include "connect.h"
28
#include "curl_share.h"
29
#include "vtls/vtls.h"
30
#include "vtls/vtls_scache.h"
31
#include "hsts.h"
32
#include "url.h"
33
34
CURLSH *curl_share_init(void)
35
0
{
36
0
  struct Curl_share *share = curlx_calloc(1, sizeof(struct Curl_share));
37
0
  if(share) {
38
0
    share->magic = CURL_GOOD_SHARE;
39
0
    share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
40
0
    Curl_dnscache_init(&share->dnscache, 23);
41
0
    share->admin = curl_easy_init();
42
0
    if(!share->admin) {
43
0
      curlx_free(share);
44
0
      return NULL;
45
0
    }
46
    /* admin handles have mid 0 */
47
0
    share->admin->mid = 0;
48
0
    share->admin->state.internal = TRUE;
49
0
#ifdef DEBUGBUILD
50
0
    if(getenv("CURL_DEBUG"))
51
0
      share->admin->set.verbose = TRUE;
52
0
#endif
53
0
  }
54
55
0
  return share;
56
0
}
57
58
#undef curl_share_setopt
59
CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
60
0
{
61
0
  va_list param;
62
0
  int type;
63
0
  curl_lock_function lockfunc;
64
0
  curl_unlock_function unlockfunc;
65
0
  void *ptr;
66
0
  CURLSHcode res = CURLSHE_OK;
67
0
  struct Curl_share *share = sh;
68
69
0
  if(!GOOD_SHARE_HANDLE(share))
70
0
    return CURLSHE_INVALID;
71
72
0
  if(share->dirty)
73
    /* do not allow setting options while one or more handles are already
74
       using this share */
75
0
    return CURLSHE_IN_USE;
76
77
0
  va_start(param, option);
78
79
0
  switch(option) {
80
0
  case CURLSHOPT_SHARE:
81
    /* this is a type this share will share */
82
0
    type = va_arg(param, int);
83
84
0
    switch(type) {
85
0
    case CURL_LOCK_DATA_DNS:
86
0
      break;
87
88
0
    case CURL_LOCK_DATA_COOKIE:
89
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
90
0
      if(!share->cookies) {
91
0
        share->cookies = Curl_cookie_init();
92
0
        if(!share->cookies)
93
0
          res = CURLSHE_NOMEM;
94
0
      }
95
#else /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
96
      res = CURLSHE_NOT_BUILT_IN;
97
#endif
98
0
      break;
99
100
0
    case CURL_LOCK_DATA_HSTS:
101
0
#ifndef CURL_DISABLE_HSTS
102
0
      if(!share->hsts) {
103
0
        share->hsts = Curl_hsts_init();
104
0
        if(!share->hsts)
105
0
          res = CURLSHE_NOMEM;
106
0
      }
107
#else /* CURL_DISABLE_HSTS */
108
      res = CURLSHE_NOT_BUILT_IN;
109
#endif
110
0
      break;
111
112
0
    case CURL_LOCK_DATA_SSL_SESSION:
113
0
#ifdef USE_SSL
114
0
      if(!share->ssl_scache) {
115
        /* There is no way (yet) for the application to configure the
116
         * session cache size, shared between many transfers. As for curl
117
         * itself, a high session count will impact startup time. Also, the
118
         * scache is not optimized for several hundreds of peers. So,
119
         * keep it at a reasonable level. */
120
0
        if(Curl_ssl_scache_create(25, 2, &share->ssl_scache))
121
0
          res = CURLSHE_NOMEM;
122
0
      }
123
#else
124
      res = CURLSHE_NOT_BUILT_IN;
125
#endif
126
0
      break;
127
128
0
    case CURL_LOCK_DATA_CONNECT:
129
      /* It is safe to set this option several times on a share. */
130
0
      if(!share->cpool.initialised) {
131
0
        Curl_cpool_init(&share->cpool, share->admin, share, 103);
132
0
      }
133
0
      break;
134
135
0
    case CURL_LOCK_DATA_PSL:
136
0
#ifndef USE_LIBPSL
137
0
      res = CURLSHE_NOT_BUILT_IN;
138
0
#endif
139
0
      break;
140
141
0
    default:
142
0
      res = CURLSHE_BAD_OPTION;
143
0
    }
144
0
    if(!res)
145
0
      share->specifier |= (unsigned int)(1 << type);
146
0
    break;
147
148
0
  case CURLSHOPT_UNSHARE:
149
    /* this is a type this share will no longer share */
150
0
    type = va_arg(param, int);
151
0
    share->specifier &= ~(unsigned int)(1 << type);
152
0
    switch(type) {
153
0
    case CURL_LOCK_DATA_DNS:
154
0
      break;
155
156
0
    case CURL_LOCK_DATA_COOKIE:
157
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
158
0
      if(share->cookies) {
159
0
        Curl_cookie_cleanup(share->cookies);
160
0
        share->cookies = NULL;
161
0
      }
162
#else /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
163
      res = CURLSHE_NOT_BUILT_IN;
164
#endif
165
0
      break;
166
167
0
    case CURL_LOCK_DATA_HSTS:
168
0
#ifndef CURL_DISABLE_HSTS
169
0
      if(share->hsts) {
170
0
        Curl_hsts_cleanup(&share->hsts);
171
0
      }
172
#else /* CURL_DISABLE_HSTS */
173
      res = CURLSHE_NOT_BUILT_IN;
174
#endif
175
0
      break;
176
177
0
    case CURL_LOCK_DATA_SSL_SESSION:
178
0
#ifdef USE_SSL
179
0
      if(share->ssl_scache) {
180
0
        Curl_ssl_scache_destroy(share->ssl_scache);
181
0
        share->ssl_scache = NULL;
182
0
      }
183
#else
184
      res = CURLSHE_NOT_BUILT_IN;
185
#endif
186
0
      break;
187
188
0
    case CURL_LOCK_DATA_CONNECT:
189
0
      break;
190
191
0
    default:
192
0
      res = CURLSHE_BAD_OPTION;
193
0
      break;
194
0
    }
195
0
    break;
196
197
0
  case CURLSHOPT_LOCKFUNC:
198
0
    lockfunc = va_arg(param, curl_lock_function);
199
0
    share->lockfunc = lockfunc;
200
0
    break;
201
202
0
  case CURLSHOPT_UNLOCKFUNC:
203
0
    unlockfunc = va_arg(param, curl_unlock_function);
204
0
    share->unlockfunc = unlockfunc;
205
0
    break;
206
207
0
  case CURLSHOPT_USERDATA:
208
0
    ptr = va_arg(param, void *);
209
0
    share->clientdata = ptr;
210
0
    break;
211
212
0
  default:
213
0
    res = CURLSHE_BAD_OPTION;
214
0
    break;
215
0
  }
216
217
0
  va_end(param);
218
219
0
  return res;
220
0
}
221
222
CURLSHcode curl_share_cleanup(CURLSH *sh)
223
0
{
224
0
  struct Curl_share *share = sh;
225
0
  if(!GOOD_SHARE_HANDLE(share))
226
0
    return CURLSHE_INVALID;
227
228
0
  if(share->lockfunc)
229
0
    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
230
0
                    share->clientdata);
231
232
0
  if(share->dirty) {
233
0
    if(share->unlockfunc)
234
0
      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
235
0
    return CURLSHE_IN_USE;
236
0
  }
237
238
0
  if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
239
0
    Curl_cpool_destroy(&share->cpool);
240
0
  }
241
242
0
  Curl_dnscache_destroy(&share->dnscache);
243
244
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
245
0
  Curl_cookie_cleanup(share->cookies);
246
0
#endif
247
248
0
#ifndef CURL_DISABLE_HSTS
249
0
  Curl_hsts_cleanup(&share->hsts);
250
0
#endif
251
252
0
#ifdef USE_SSL
253
0
  if(share->ssl_scache) {
254
0
    Curl_ssl_scache_destroy(share->ssl_scache);
255
0
    share->ssl_scache = NULL;
256
0
  }
257
0
#endif
258
259
0
  Curl_psl_destroy(&share->psl);
260
0
  Curl_close(&share->admin);
261
262
0
  if(share->unlockfunc)
263
0
    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
264
0
  share->magic = 0;
265
0
  curlx_free(share);
266
267
0
  return CURLSHE_OK;
268
0
}
269
270
CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
271
                           curl_lock_access accesstype)
272
7.92k
{
273
7.92k
  struct Curl_share *share = data->share;
274
275
7.92k
  if(!share)
276
7.92k
    return CURLSHE_INVALID;
277
278
0
  if(share->specifier & (unsigned int)(1 << type)) {
279
0
    if(share->lockfunc) /* only call this if set! */
280
0
      share->lockfunc(data, type, accesstype, share->clientdata);
281
0
  }
282
  /* else if we do not share this, pretend successful lock */
283
284
0
  return CURLSHE_OK;
285
7.92k
}
286
287
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
288
7.92k
{
289
7.92k
  struct Curl_share *share = data->share;
290
291
7.92k
  if(!share)
292
7.92k
    return CURLSHE_INVALID;
293
294
0
  if(share->specifier & (unsigned int)(1 << type)) {
295
0
    if(share->unlockfunc) /* only call this if set! */
296
0
      share->unlockfunc(data, type, share->clientdata);
297
0
  }
298
299
0
  return CURLSHE_OK;
300
7.92k
}