Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/altsvc.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 2019, 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.haxx.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 ***************************************************************************/ | |
| 22 /* | |
| 23 * The Alt-Svc: header is defined in RFC 7838: | |
| 24 * https://tools.ietf.org/html/rfc7838 | |
| 25 */ | |
| 26 #include "curl_setup.h" | |
| 27 | |
| 28 #if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC) | |
| 29 #include <curl/curl.h> | |
| 30 #include "urldata.h" | |
| 31 #include "altsvc.h" | |
| 32 #include "curl_get_line.h" | |
| 33 #include "strcase.h" | |
| 34 #include "parsedate.h" | |
| 35 #include "sendf.h" | |
| 36 #include "warnless.h" | |
| 37 | |
| 38 /* The last 3 #include files should be in this order */ | |
| 39 #include "curl_printf.h" | |
| 40 #include "curl_memory.h" | |
| 41 #include "memdebug.h" | |
| 42 | |
| 43 #define MAX_ALTSVC_LINE 4095 | |
| 44 #define MAX_ALTSVC_DATELENSTR "64" | |
| 45 #define MAX_ALTSVC_DATELEN 64 | |
| 46 #define MAX_ALTSVC_HOSTLENSTR "512" | |
| 47 #define MAX_ALTSVC_HOSTLEN 512 | |
| 48 #define MAX_ALTSVC_ALPNLENSTR "10" | |
| 49 #define MAX_ALTSVC_ALPNLEN 10 | |
| 50 | |
| 51 static enum alpnid alpn2alpnid(char *name) | |
| 52 { | |
| 53 if(strcasecompare(name, "h1")) | |
| 54 return ALPN_h1; | |
| 55 if(strcasecompare(name, "h2")) | |
| 56 return ALPN_h2; | |
| 57 #if (defined(USE_QUICHE) || defined(USE_NGHTTP2)) && !defined(UNITTESTS) | |
| 58 if(strcasecompare(name, "h3-22")) | |
| 59 return ALPN_h3; | |
| 60 #else | |
| 61 if(strcasecompare(name, "h3")) | |
| 62 return ALPN_h3; | |
| 63 #endif | |
| 64 return ALPN_none; /* unknown, probably rubbish input */ | |
| 65 } | |
| 66 | |
| 67 /* Given the ALPN ID, return the name */ | |
| 68 const char *Curl_alpnid2str(enum alpnid id) | |
| 69 { | |
| 70 switch(id) { | |
| 71 case ALPN_h1: | |
| 72 return "h1"; | |
| 73 case ALPN_h2: | |
| 74 return "h2"; | |
| 75 case ALPN_h3: | |
| 76 #if (defined(USE_QUICHE) || defined(USE_NGHTTP2)) && !defined(UNITTESTS) | |
| 77 return "h3-22"; | |
| 78 #else | |
| 79 return "h3"; | |
| 80 #endif | |
| 81 default: | |
| 82 return ""; /* bad */ | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 | |
| 87 static void altsvc_free(struct altsvc *as) | |
| 88 { | |
| 89 free(as->src.host); | |
| 90 free(as->dst.host); | |
| 91 free(as); | |
| 92 } | |
| 93 | |
| 94 static struct altsvc *altsvc_createid(const char *srchost, | |
| 95 const char *dsthost, | |
| 96 enum alpnid srcalpnid, | |
| 97 enum alpnid dstalpnid, | |
| 98 unsigned int srcport, | |
| 99 unsigned int dstport) | |
| 100 { | |
| 101 struct altsvc *as = calloc(sizeof(struct altsvc), 1); | |
| 102 if(!as) | |
| 103 return NULL; | |
| 104 | |
| 105 as->src.host = strdup(srchost); | |
| 106 if(!as->src.host) | |
| 107 goto error; | |
| 108 as->dst.host = strdup(dsthost); | |
| 109 if(!as->dst.host) | |
| 110 goto error; | |
| 111 | |
| 112 as->src.alpnid = srcalpnid; | |
| 113 as->dst.alpnid = dstalpnid; | |
| 114 as->src.port = curlx_ultous(srcport); | |
| 115 as->dst.port = curlx_ultous(dstport); | |
| 116 | |
| 117 return as; | |
| 118 error: | |
| 119 altsvc_free(as); | |
| 120 return NULL; | |
| 121 } | |
| 122 | |
| 123 static struct altsvc *altsvc_create(char *srchost, | |
| 124 char *dsthost, | |
| 125 char *srcalpn, | |
| 126 char *dstalpn, | |
| 127 unsigned int srcport, | |
| 128 unsigned int dstport) | |
| 129 { | |
| 130 enum alpnid dstalpnid = alpn2alpnid(dstalpn); | |
| 131 enum alpnid srcalpnid = alpn2alpnid(srcalpn); | |
| 132 if(!srcalpnid || !dstalpnid) | |
| 133 return NULL; | |
| 134 return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, | |
| 135 srcport, dstport); | |
| 136 } | |
| 137 | |
| 138 /* only returns SERIOUS errors */ | |
| 139 static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) | |
| 140 { | |
| 141 /* Example line: | |
| 142 h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1 | |
| 143 */ | |
| 144 char srchost[MAX_ALTSVC_HOSTLEN + 1]; | |
| 145 char dsthost[MAX_ALTSVC_HOSTLEN + 1]; | |
| 146 char srcalpn[MAX_ALTSVC_ALPNLEN + 1]; | |
| 147 char dstalpn[MAX_ALTSVC_ALPNLEN + 1]; | |
| 148 char date[MAX_ALTSVC_DATELEN + 1]; | |
| 149 unsigned int srcport; | |
| 150 unsigned int dstport; | |
| 151 unsigned int prio; | |
| 152 unsigned int persist; | |
| 153 int rc; | |
| 154 | |
| 155 rc = sscanf(line, | |
| 156 "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " | |
| 157 "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " | |
| 158 "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u", | |
| 159 srcalpn, srchost, &srcport, | |
| 160 dstalpn, dsthost, &dstport, | |
| 161 date, &persist, &prio); | |
| 162 if(9 == rc) { | |
| 163 struct altsvc *as; | |
| 164 time_t expires = curl_getdate(date, NULL); | |
| 165 as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport); | |
| 166 if(as) { | |
| 167 as->expires = expires; | |
| 168 as->prio = prio; | |
| 169 as->persist = persist ? 1 : 0; | |
| 170 Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); | |
| 171 asi->num++; /* one more entry */ | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 return CURLE_OK; | |
| 176 } | |
| 177 | |
| 178 /* | |
| 179 * Load alt-svc entries from the given file. The text based line-oriented file | |
| 180 * format is documented here: | |
| 181 * https://github.com/curl/curl/wiki/QUIC-implementation | |
| 182 * | |
| 183 * This function only returns error on major problems that prevents alt-svc | |
| 184 * handling to work completely. It will ignore individual syntactical errors | |
| 185 * etc. | |
| 186 */ | |
| 187 static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) | |
| 188 { | |
| 189 CURLcode result = CURLE_OK; | |
| 190 char *line = NULL; | |
| 191 FILE *fp = fopen(file, FOPEN_READTEXT); | |
| 192 if(fp) { | |
| 193 line = malloc(MAX_ALTSVC_LINE); | |
| 194 if(!line) | |
| 195 goto fail; | |
| 196 while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) { | |
| 197 char *lineptr = line; | |
| 198 while(*lineptr && ISBLANK(*lineptr)) | |
| 199 lineptr++; | |
| 200 if(*lineptr == '#') | |
| 201 /* skip commented lines */ | |
| 202 continue; | |
| 203 | |
| 204 altsvc_add(asi, lineptr); | |
| 205 } | |
| 206 free(line); /* free the line buffer */ | |
| 207 fclose(fp); | |
| 208 } | |
| 209 return result; | |
| 210 | |
| 211 fail: | |
| 212 free(line); | |
| 213 fclose(fp); | |
| 214 return CURLE_OUT_OF_MEMORY; | |
| 215 } | |
| 216 | |
| 217 /* | |
| 218 * Write this single altsvc entry to a single output line | |
| 219 */ | |
| 220 | |
| 221 static CURLcode altsvc_out(struct altsvc *as, FILE *fp) | |
| 222 { | |
| 223 struct tm stamp; | |
| 224 CURLcode result = Curl_gmtime(as->expires, &stamp); | |
| 225 if(result) | |
| 226 return result; | |
| 227 | |
| 228 fprintf(fp, | |
| 229 "%s %s %u " | |
| 230 "%s %s %u " | |
| 231 "\"%d%02d%02d " | |
| 232 "%02d:%02d:%02d\" " | |
| 233 "%u %d\n", | |
| 234 Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port, | |
| 235 Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port, | |
| 236 stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, | |
| 237 stamp.tm_hour, stamp.tm_min, stamp.tm_sec, | |
| 238 as->persist, as->prio); | |
| 239 return CURLE_OK; | |
| 240 } | |
| 241 | |
| 242 /* ---- library-wide functions below ---- */ | |
| 243 | |
| 244 /* | |
| 245 * Curl_altsvc_init() creates a new altsvc cache. | |
| 246 * It returns the new instance or NULL if something goes wrong. | |
| 247 */ | |
| 248 struct altsvcinfo *Curl_altsvc_init(void) | |
| 249 { | |
| 250 struct altsvcinfo *asi = calloc(sizeof(struct altsvcinfo), 1); | |
| 251 if(!asi) | |
| 252 return NULL; | |
| 253 Curl_llist_init(&asi->list, NULL); | |
| 254 | |
| 255 /* set default behavior */ | |
| 256 asi->flags = CURLALTSVC_H1 | |
| 257 #ifdef USE_NGHTTP2 | |
| 258 | CURLALTSVC_H2 | |
| 259 #endif | |
| 260 #ifdef ENABLE_QUIC | |
| 261 | CURLALTSVC_H3 | |
| 262 #endif | |
| 263 ; | |
| 264 return asi; | |
| 265 } | |
| 266 | |
| 267 /* | |
| 268 * Curl_altsvc_load() loads alt-svc from file. | |
| 269 */ | |
| 270 CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file) | |
| 271 { | |
| 272 CURLcode result; | |
| 273 DEBUGASSERT(asi); | |
| 274 result = altsvc_load(asi, file); | |
| 275 return result; | |
| 276 } | |
| 277 | |
| 278 /* | |
| 279 * Curl_altsvc_ctrl() passes on the external bitmask. | |
| 280 */ | |
| 281 CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl) | |
| 282 { | |
| 283 DEBUGASSERT(asi); | |
| 284 if(!ctrl) | |
| 285 /* unexpected */ | |
| 286 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 287 asi->flags = ctrl; | |
| 288 return CURLE_OK; | |
| 289 } | |
| 290 | |
| 291 /* | |
| 292 * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated | |
| 293 * resources. | |
| 294 */ | |
| 295 void Curl_altsvc_cleanup(struct altsvcinfo *altsvc) | |
| 296 { | |
| 297 struct curl_llist_element *e; | |
| 298 struct curl_llist_element *n; | |
| 299 if(altsvc) { | |
| 300 for(e = altsvc->list.head; e; e = n) { | |
| 301 struct altsvc *as = e->ptr; | |
| 302 n = e->next; | |
| 303 altsvc_free(as); | |
| 304 } | |
| 305 free(altsvc); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 /* | |
| 310 * Curl_altsvc_save() writes the altsvc cache to a file. | |
| 311 */ | |
| 312 CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file) | |
| 313 { | |
| 314 struct curl_llist_element *e; | |
| 315 struct curl_llist_element *n; | |
| 316 CURLcode result = CURLE_OK; | |
| 317 FILE *out; | |
| 318 | |
| 319 if(!altsvc) | |
| 320 /* no cache activated */ | |
| 321 return CURLE_OK; | |
| 322 | |
| 323 if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file[0]) | |
| 324 /* marked as read-only or zero length file name */ | |
| 325 return CURLE_OK; | |
| 326 out = fopen(file, FOPEN_WRITETEXT); | |
| 327 if(!out) | |
| 328 return CURLE_WRITE_ERROR; | |
| 329 fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n" | |
| 330 "# This file was generated by libcurl! Edit at your own risk.\n", | |
| 331 out); | |
| 332 for(e = altsvc->list.head; e; e = n) { | |
| 333 struct altsvc *as = e->ptr; | |
| 334 n = e->next; | |
| 335 result = altsvc_out(as, out); | |
| 336 if(result) | |
| 337 break; | |
| 338 } | |
| 339 fclose(out); | |
| 340 return result; | |
| 341 } | |
| 342 | |
| 343 static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen) | |
| 344 { | |
| 345 size_t len; | |
| 346 const char *protop; | |
| 347 const char *p = *ptr; | |
| 348 while(*p && ISBLANK(*p)) | |
| 349 p++; | |
| 350 protop = p; | |
| 351 while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '=')) | |
| 352 p++; | |
| 353 len = p - protop; | |
| 354 | |
| 355 if(!len || (len >= buflen)) | |
| 356 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 357 memcpy(alpnbuf, protop, len); | |
| 358 alpnbuf[len] = 0; | |
| 359 *ptr = p; | |
| 360 return CURLE_OK; | |
| 361 } | |
| 362 | |
| 363 /* altsvc_flush() removes all alternatives for this source origin from the | |
| 364 list */ | |
| 365 static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, | |
| 366 const char *srchost, unsigned short srcport) | |
| 367 { | |
| 368 struct curl_llist_element *e; | |
| 369 struct curl_llist_element *n; | |
| 370 for(e = asi->list.head; e; e = n) { | |
| 371 struct altsvc *as = e->ptr; | |
| 372 n = e->next; | |
| 373 if((srcalpnid == as->src.alpnid) && | |
| 374 (srcport == as->src.port) && | |
| 375 strcasecompare(srchost, as->src.host)) { | |
| 376 Curl_llist_remove(&asi->list, e, NULL); | |
| 377 altsvc_free(as); | |
| 378 asi->num--; | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 #ifdef DEBUGBUILD | |
| 384 /* to play well with debug builds, we can *set* a fixed time this will | |
| 385 return */ | |
| 386 static time_t debugtime(void *unused) | |
| 387 { | |
| 388 char *timestr = getenv("CURL_TIME"); | |
| 389 (void)unused; | |
| 390 if(timestr) { | |
| 391 unsigned long val = strtol(timestr, NULL, 10); | |
| 392 return (time_t)val; | |
| 393 } | |
| 394 return time(NULL); | |
| 395 } | |
| 396 #define time(x) debugtime(x) | |
| 397 #endif | |
| 398 | |
| 399 /* | |
| 400 * Curl_altsvc_parse() takes an incoming alt-svc response header and stores | |
| 401 * the data correctly in the cache. | |
| 402 * | |
| 403 * 'value' points to the header *value*. That's contents to the right of the | |
| 404 * header name. | |
| 405 */ | |
| 406 CURLcode Curl_altsvc_parse(struct Curl_easy *data, | |
| 407 struct altsvcinfo *asi, const char *value, | |
| 408 enum alpnid srcalpnid, const char *srchost, | |
| 409 unsigned short srcport) | |
| 410 { | |
| 411 const char *p = value; | |
| 412 size_t len; | |
| 413 enum alpnid dstalpnid = srcalpnid; /* the same by default */ | |
| 414 char namebuf[MAX_ALTSVC_HOSTLEN] = ""; | |
| 415 char alpnbuf[MAX_ALTSVC_ALPNLEN] = ""; | |
| 416 struct altsvc *as; | |
| 417 unsigned short dstport = srcport; /* the same by default */ | |
| 418 const char *semip; | |
| 419 time_t maxage = 24 * 3600; /* default is 24 hours */ | |
| 420 bool persist = FALSE; | |
| 421 CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); | |
| 422 if(result) | |
| 423 return result; | |
| 424 | |
| 425 DEBUGASSERT(asi); | |
| 426 | |
| 427 /* Flush all cached alternatives for this source origin, if any */ | |
| 428 altsvc_flush(asi, srcalpnid, srchost, srcport); | |
| 429 | |
| 430 /* "clear" is a magic keyword */ | |
| 431 if(strcasecompare(alpnbuf, "clear")) { | |
| 432 return CURLE_OK; | |
| 433 } | |
| 434 | |
| 435 /* The 'ma' and 'persist' flags are annoyingly meant for all alternatives | |
| 436 but are set after the list on the line. Scan for the semicolons and get | |
| 437 those fields first! */ | |
| 438 semip = p; | |
| 439 do { | |
| 440 semip = strchr(semip, ';'); | |
| 441 if(semip) { | |
| 442 char option[32]; | |
| 443 unsigned long num; | |
| 444 char *end_ptr; | |
| 445 semip++; /* pass the semicolon */ | |
| 446 result = getalnum(&semip, option, sizeof(option)); | |
| 447 if(result) | |
| 448 break; | |
| 449 while(*semip && ISBLANK(*semip)) | |
| 450 semip++; | |
| 451 if(*semip != '=') | |
| 452 continue; | |
| 453 semip++; | |
| 454 num = strtoul(semip, &end_ptr, 10); | |
| 455 if(num < ULONG_MAX) { | |
| 456 if(strcasecompare("ma", option)) | |
| 457 maxage = num; | |
| 458 else if(strcasecompare("persist", option) && (num == 1)) | |
| 459 persist = TRUE; | |
| 460 } | |
| 461 semip = end_ptr; | |
| 462 } | |
| 463 } while(semip); | |
| 464 | |
| 465 do { | |
| 466 if(*p == '=') { | |
| 467 /* [protocol]="[host][:port]" */ | |
| 468 dstalpnid = alpn2alpnid(alpnbuf); | |
| 469 if(!dstalpnid) { | |
| 470 infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf); | |
| 471 return CURLE_OK; | |
| 472 } | |
| 473 p++; | |
| 474 if(*p == '\"') { | |
| 475 const char *dsthost; | |
| 476 p++; | |
| 477 if(*p != ':') { | |
| 478 /* host name starts here */ | |
| 479 const char *hostp = p; | |
| 480 while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-'))) | |
| 481 p++; | |
| 482 len = p - hostp; | |
| 483 if(!len || (len >= MAX_ALTSVC_HOSTLEN)) | |
| 484 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 485 memcpy(namebuf, hostp, len); | |
| 486 namebuf[len] = 0; | |
| 487 dsthost = namebuf; | |
| 488 } | |
| 489 else { | |
| 490 /* no destination name, use source host */ | |
| 491 dsthost = srchost; | |
| 492 } | |
| 493 if(*p == ':') { | |
| 494 /* a port number */ | |
| 495 char *end_ptr; | |
| 496 unsigned long port = strtoul(++p, &end_ptr, 10); | |
| 497 if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { | |
| 498 infof(data, "Unknown alt-svc port number, ignoring...\n"); | |
| 499 return CURLE_OK; | |
| 500 } | |
| 501 p = end_ptr; | |
| 502 dstport = curlx_ultous(port); | |
| 503 } | |
| 504 if(*p++ != '\"') | |
| 505 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 506 as = altsvc_createid(srchost, dsthost, | |
| 507 srcalpnid, dstalpnid, | |
| 508 srcport, dstport); | |
| 509 if(as) { | |
| 510 /* The expires time also needs to take the Age: value (if any) into | |
| 511 account. [See RFC 7838 section 3.1] */ | |
| 512 as->expires = maxage + time(NULL); | |
| 513 as->persist = persist; | |
| 514 Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); | |
| 515 asi->num++; /* one more entry */ | |
| 516 infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, | |
| 517 Curl_alpnid2str(dstalpnid)); | |
| 518 } | |
| 519 } | |
| 520 /* after the double quote there can be a comma if there's another | |
| 521 string or a semicolon if no more */ | |
| 522 if(*p == ',') { | |
| 523 /* comma means another alternative is presented */ | |
| 524 p++; | |
| 525 result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); | |
| 526 if(result) | |
| 527 /* failed to parse, but since we already did at least one host we | |
| 528 return OK */ | |
| 529 return CURLE_OK; | |
| 530 } | |
| 531 } | |
| 532 } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r')); | |
| 533 | |
| 534 return CURLE_OK; | |
| 535 } | |
| 536 | |
| 537 /* | |
| 538 * Return TRUE on a match | |
| 539 */ | |
| 540 bool Curl_altsvc_lookup(struct altsvcinfo *asi, | |
| 541 enum alpnid srcalpnid, const char *srchost, | |
| 542 int srcport, | |
| 543 struct altsvc **dstentry, | |
| 544 const int versions) /* one or more bits */ | |
| 545 { | |
| 546 struct curl_llist_element *e; | |
| 547 struct curl_llist_element *n; | |
| 548 time_t now = time(NULL); | |
| 549 DEBUGASSERT(asi); | |
| 550 DEBUGASSERT(srchost); | |
| 551 DEBUGASSERT(dstentry); | |
| 552 | |
| 553 for(e = asi->list.head; e; e = n) { | |
| 554 struct altsvc *as = e->ptr; | |
| 555 n = e->next; | |
| 556 if(as->expires < now) { | |
| 557 /* an expired entry, remove */ | |
| 558 Curl_llist_remove(&asi->list, e, NULL); | |
| 559 altsvc_free(as); | |
| 560 continue; | |
| 561 } | |
| 562 if((as->src.alpnid == srcalpnid) && | |
| 563 strcasecompare(as->src.host, srchost) && | |
| 564 (as->src.port == srcport) && | |
| 565 (versions & as->dst.alpnid)) { | |
| 566 /* match */ | |
| 567 *dstentry = as; | |
| 568 return TRUE; | |
| 569 } | |
| 570 } | |
| 571 return FALSE; | |
| 572 } | |
| 573 | |
| 574 #endif /* CURL_DISABLE_HTTP || USE_ALTSVC */ |
