Coverage Report

Created: 2025-06-09 08:44

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