Coverage Report

Created: 2026-02-26 06:33

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