Coverage Report

Created: 2025-12-04 07:04

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