1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker /*
25*6236dae4SAndroid Build Coastguard Worker * The Alt-Svc: header is defined in RFC 7838:
26*6236dae4SAndroid Build Coastguard Worker * https://datatracker.ietf.org/doc/html/rfc7838
27*6236dae4SAndroid Build Coastguard Worker */
28*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
29*6236dae4SAndroid Build Coastguard Worker
30*6236dae4SAndroid Build Coastguard Worker #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
31*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
32*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
33*6236dae4SAndroid Build Coastguard Worker #include "altsvc.h"
34*6236dae4SAndroid Build Coastguard Worker #include "curl_get_line.h"
35*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
36*6236dae4SAndroid Build Coastguard Worker #include "parsedate.h"
37*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
38*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
39*6236dae4SAndroid Build Coastguard Worker #include "fopen.h"
40*6236dae4SAndroid Build Coastguard Worker #include "rename.h"
41*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
42*6236dae4SAndroid Build Coastguard Worker #include "inet_pton.h"
43*6236dae4SAndroid Build Coastguard Worker
44*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
45*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
46*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
47*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
48*6236dae4SAndroid Build Coastguard Worker
49*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_LINE 4095
50*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_DATELENSTR "64"
51*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_DATELEN 64
52*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_HOSTLENSTR "512"
53*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_HOSTLEN 512
54*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_ALPNLENSTR "10"
55*6236dae4SAndroid Build Coastguard Worker #define MAX_ALTSVC_ALPNLEN 10
56*6236dae4SAndroid Build Coastguard Worker
57*6236dae4SAndroid Build Coastguard Worker #define H3VERSION "h3"
58*6236dae4SAndroid Build Coastguard Worker
alpn2alpnid(char * name)59*6236dae4SAndroid Build Coastguard Worker static enum alpnid alpn2alpnid(char *name)
60*6236dae4SAndroid Build Coastguard Worker {
61*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(name, "h1"))
62*6236dae4SAndroid Build Coastguard Worker return ALPN_h1;
63*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(name, "h2"))
64*6236dae4SAndroid Build Coastguard Worker return ALPN_h2;
65*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(name, H3VERSION))
66*6236dae4SAndroid Build Coastguard Worker return ALPN_h3;
67*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(name, "http/1.1"))
68*6236dae4SAndroid Build Coastguard Worker return ALPN_h1;
69*6236dae4SAndroid Build Coastguard Worker return ALPN_none; /* unknown, probably rubbish input */
70*6236dae4SAndroid Build Coastguard Worker }
71*6236dae4SAndroid Build Coastguard Worker
72*6236dae4SAndroid Build Coastguard Worker /* Given the ALPN ID, return the name */
Curl_alpnid2str(enum alpnid id)73*6236dae4SAndroid Build Coastguard Worker const char *Curl_alpnid2str(enum alpnid id)
74*6236dae4SAndroid Build Coastguard Worker {
75*6236dae4SAndroid Build Coastguard Worker switch(id) {
76*6236dae4SAndroid Build Coastguard Worker case ALPN_h1:
77*6236dae4SAndroid Build Coastguard Worker return "h1";
78*6236dae4SAndroid Build Coastguard Worker case ALPN_h2:
79*6236dae4SAndroid Build Coastguard Worker return "h2";
80*6236dae4SAndroid Build Coastguard Worker case ALPN_h3:
81*6236dae4SAndroid Build Coastguard Worker return H3VERSION;
82*6236dae4SAndroid Build Coastguard Worker default:
83*6236dae4SAndroid Build Coastguard Worker return ""; /* bad */
84*6236dae4SAndroid Build Coastguard Worker }
85*6236dae4SAndroid Build Coastguard Worker }
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard Worker
altsvc_free(struct altsvc * as)88*6236dae4SAndroid Build Coastguard Worker static void altsvc_free(struct altsvc *as)
89*6236dae4SAndroid Build Coastguard Worker {
90*6236dae4SAndroid Build Coastguard Worker free(as->src.host);
91*6236dae4SAndroid Build Coastguard Worker free(as->dst.host);
92*6236dae4SAndroid Build Coastguard Worker free(as);
93*6236dae4SAndroid Build Coastguard Worker }
94*6236dae4SAndroid Build Coastguard Worker
altsvc_createid(const char * srchost,const char * dsthost,size_t dlen,enum alpnid srcalpnid,enum alpnid dstalpnid,unsigned int srcport,unsigned int dstport)95*6236dae4SAndroid Build Coastguard Worker static struct altsvc *altsvc_createid(const char *srchost,
96*6236dae4SAndroid Build Coastguard Worker const char *dsthost,
97*6236dae4SAndroid Build Coastguard Worker size_t dlen, /* dsthost length */
98*6236dae4SAndroid Build Coastguard Worker enum alpnid srcalpnid,
99*6236dae4SAndroid Build Coastguard Worker enum alpnid dstalpnid,
100*6236dae4SAndroid Build Coastguard Worker unsigned int srcport,
101*6236dae4SAndroid Build Coastguard Worker unsigned int dstport)
102*6236dae4SAndroid Build Coastguard Worker {
103*6236dae4SAndroid Build Coastguard Worker struct altsvc *as = calloc(1, sizeof(struct altsvc));
104*6236dae4SAndroid Build Coastguard Worker size_t hlen;
105*6236dae4SAndroid Build Coastguard Worker if(!as)
106*6236dae4SAndroid Build Coastguard Worker return NULL;
107*6236dae4SAndroid Build Coastguard Worker hlen = strlen(srchost);
108*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(hlen);
109*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(dlen);
110*6236dae4SAndroid Build Coastguard Worker if(!hlen || !dlen) {
111*6236dae4SAndroid Build Coastguard Worker /* bad input */
112*6236dae4SAndroid Build Coastguard Worker free(as);
113*6236dae4SAndroid Build Coastguard Worker return NULL;
114*6236dae4SAndroid Build Coastguard Worker }
115*6236dae4SAndroid Build Coastguard Worker if((hlen > 2) && srchost[0] == '[') {
116*6236dae4SAndroid Build Coastguard Worker /* IPv6 address, strip off brackets */
117*6236dae4SAndroid Build Coastguard Worker srchost++;
118*6236dae4SAndroid Build Coastguard Worker hlen -= 2;
119*6236dae4SAndroid Build Coastguard Worker }
120*6236dae4SAndroid Build Coastguard Worker else if(srchost[hlen - 1] == '.')
121*6236dae4SAndroid Build Coastguard Worker /* strip off trailing dot */
122*6236dae4SAndroid Build Coastguard Worker hlen--;
123*6236dae4SAndroid Build Coastguard Worker if((dlen > 2) && dsthost[0] == '[') {
124*6236dae4SAndroid Build Coastguard Worker /* IPv6 address, strip off brackets */
125*6236dae4SAndroid Build Coastguard Worker dsthost++;
126*6236dae4SAndroid Build Coastguard Worker dlen -= 2;
127*6236dae4SAndroid Build Coastguard Worker }
128*6236dae4SAndroid Build Coastguard Worker
129*6236dae4SAndroid Build Coastguard Worker as->src.host = Curl_memdup0(srchost, hlen);
130*6236dae4SAndroid Build Coastguard Worker if(!as->src.host)
131*6236dae4SAndroid Build Coastguard Worker goto error;
132*6236dae4SAndroid Build Coastguard Worker
133*6236dae4SAndroid Build Coastguard Worker as->dst.host = Curl_memdup0(dsthost, dlen);
134*6236dae4SAndroid Build Coastguard Worker if(!as->dst.host)
135*6236dae4SAndroid Build Coastguard Worker goto error;
136*6236dae4SAndroid Build Coastguard Worker
137*6236dae4SAndroid Build Coastguard Worker as->src.alpnid = srcalpnid;
138*6236dae4SAndroid Build Coastguard Worker as->dst.alpnid = dstalpnid;
139*6236dae4SAndroid Build Coastguard Worker as->src.port = curlx_ultous(srcport);
140*6236dae4SAndroid Build Coastguard Worker as->dst.port = curlx_ultous(dstport);
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker return as;
143*6236dae4SAndroid Build Coastguard Worker error:
144*6236dae4SAndroid Build Coastguard Worker altsvc_free(as);
145*6236dae4SAndroid Build Coastguard Worker return NULL;
146*6236dae4SAndroid Build Coastguard Worker }
147*6236dae4SAndroid Build Coastguard Worker
altsvc_create(char * srchost,char * dsthost,char * srcalpn,char * dstalpn,unsigned int srcport,unsigned int dstport)148*6236dae4SAndroid Build Coastguard Worker static struct altsvc *altsvc_create(char *srchost,
149*6236dae4SAndroid Build Coastguard Worker char *dsthost,
150*6236dae4SAndroid Build Coastguard Worker char *srcalpn,
151*6236dae4SAndroid Build Coastguard Worker char *dstalpn,
152*6236dae4SAndroid Build Coastguard Worker unsigned int srcport,
153*6236dae4SAndroid Build Coastguard Worker unsigned int dstport)
154*6236dae4SAndroid Build Coastguard Worker {
155*6236dae4SAndroid Build Coastguard Worker enum alpnid dstalpnid = alpn2alpnid(dstalpn);
156*6236dae4SAndroid Build Coastguard Worker enum alpnid srcalpnid = alpn2alpnid(srcalpn);
157*6236dae4SAndroid Build Coastguard Worker if(!srcalpnid || !dstalpnid)
158*6236dae4SAndroid Build Coastguard Worker return NULL;
159*6236dae4SAndroid Build Coastguard Worker return altsvc_createid(srchost, dsthost, strlen(dsthost),
160*6236dae4SAndroid Build Coastguard Worker srcalpnid, dstalpnid,
161*6236dae4SAndroid Build Coastguard Worker srcport, dstport);
162*6236dae4SAndroid Build Coastguard Worker }
163*6236dae4SAndroid Build Coastguard Worker
164*6236dae4SAndroid Build Coastguard Worker /* only returns SERIOUS errors */
altsvc_add(struct altsvcinfo * asi,char * line)165*6236dae4SAndroid Build Coastguard Worker static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
166*6236dae4SAndroid Build Coastguard Worker {
167*6236dae4SAndroid Build Coastguard Worker /* Example line:
168*6236dae4SAndroid Build Coastguard Worker h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
169*6236dae4SAndroid Build Coastguard Worker */
170*6236dae4SAndroid Build Coastguard Worker char srchost[MAX_ALTSVC_HOSTLEN + 1];
171*6236dae4SAndroid Build Coastguard Worker char dsthost[MAX_ALTSVC_HOSTLEN + 1];
172*6236dae4SAndroid Build Coastguard Worker char srcalpn[MAX_ALTSVC_ALPNLEN + 1];
173*6236dae4SAndroid Build Coastguard Worker char dstalpn[MAX_ALTSVC_ALPNLEN + 1];
174*6236dae4SAndroid Build Coastguard Worker char date[MAX_ALTSVC_DATELEN + 1];
175*6236dae4SAndroid Build Coastguard Worker unsigned int srcport;
176*6236dae4SAndroid Build Coastguard Worker unsigned int dstport;
177*6236dae4SAndroid Build Coastguard Worker unsigned int prio;
178*6236dae4SAndroid Build Coastguard Worker unsigned int persist;
179*6236dae4SAndroid Build Coastguard Worker int rc;
180*6236dae4SAndroid Build Coastguard Worker
181*6236dae4SAndroid Build Coastguard Worker rc = sscanf(line,
182*6236dae4SAndroid Build Coastguard Worker "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
183*6236dae4SAndroid Build Coastguard Worker "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
184*6236dae4SAndroid Build Coastguard Worker "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u",
185*6236dae4SAndroid Build Coastguard Worker srcalpn, srchost, &srcport,
186*6236dae4SAndroid Build Coastguard Worker dstalpn, dsthost, &dstport,
187*6236dae4SAndroid Build Coastguard Worker date, &persist, &prio);
188*6236dae4SAndroid Build Coastguard Worker if(9 == rc) {
189*6236dae4SAndroid Build Coastguard Worker struct altsvc *as;
190*6236dae4SAndroid Build Coastguard Worker time_t expires = Curl_getdate_capped(date);
191*6236dae4SAndroid Build Coastguard Worker as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport);
192*6236dae4SAndroid Build Coastguard Worker if(as) {
193*6236dae4SAndroid Build Coastguard Worker as->expires = expires;
194*6236dae4SAndroid Build Coastguard Worker as->prio = prio;
195*6236dae4SAndroid Build Coastguard Worker as->persist = persist ? 1 : 0;
196*6236dae4SAndroid Build Coastguard Worker Curl_llist_append(&asi->list, as, &as->node);
197*6236dae4SAndroid Build Coastguard Worker }
198*6236dae4SAndroid Build Coastguard Worker }
199*6236dae4SAndroid Build Coastguard Worker
200*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
201*6236dae4SAndroid Build Coastguard Worker }
202*6236dae4SAndroid Build Coastguard Worker
203*6236dae4SAndroid Build Coastguard Worker /*
204*6236dae4SAndroid Build Coastguard Worker * Load alt-svc entries from the given file. The text based line-oriented file
205*6236dae4SAndroid Build Coastguard Worker * format is documented here: https://curl.se/docs/alt-svc.html
206*6236dae4SAndroid Build Coastguard Worker *
207*6236dae4SAndroid Build Coastguard Worker * This function only returns error on major problems that prevent alt-svc
208*6236dae4SAndroid Build Coastguard Worker * handling to work completely. It will ignore individual syntactical errors
209*6236dae4SAndroid Build Coastguard Worker * etc.
210*6236dae4SAndroid Build Coastguard Worker */
altsvc_load(struct altsvcinfo * asi,const char * file)211*6236dae4SAndroid Build Coastguard Worker static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
212*6236dae4SAndroid Build Coastguard Worker {
213*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
214*6236dae4SAndroid Build Coastguard Worker FILE *fp;
215*6236dae4SAndroid Build Coastguard Worker
216*6236dae4SAndroid Build Coastguard Worker /* we need a private copy of the filename so that the altsvc cache file
217*6236dae4SAndroid Build Coastguard Worker name survives an easy handle reset */
218*6236dae4SAndroid Build Coastguard Worker free(asi->filename);
219*6236dae4SAndroid Build Coastguard Worker asi->filename = strdup(file);
220*6236dae4SAndroid Build Coastguard Worker if(!asi->filename)
221*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
222*6236dae4SAndroid Build Coastguard Worker
223*6236dae4SAndroid Build Coastguard Worker fp = fopen(file, FOPEN_READTEXT);
224*6236dae4SAndroid Build Coastguard Worker if(fp) {
225*6236dae4SAndroid Build Coastguard Worker struct dynbuf buf;
226*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
227*6236dae4SAndroid Build Coastguard Worker while(Curl_get_line(&buf, fp)) {
228*6236dae4SAndroid Build Coastguard Worker char *lineptr = Curl_dyn_ptr(&buf);
229*6236dae4SAndroid Build Coastguard Worker while(*lineptr && ISBLANK(*lineptr))
230*6236dae4SAndroid Build Coastguard Worker lineptr++;
231*6236dae4SAndroid Build Coastguard Worker if(*lineptr == '#')
232*6236dae4SAndroid Build Coastguard Worker /* skip commented lines */
233*6236dae4SAndroid Build Coastguard Worker continue;
234*6236dae4SAndroid Build Coastguard Worker
235*6236dae4SAndroid Build Coastguard Worker altsvc_add(asi, lineptr);
236*6236dae4SAndroid Build Coastguard Worker }
237*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&buf); /* free the line buffer */
238*6236dae4SAndroid Build Coastguard Worker fclose(fp);
239*6236dae4SAndroid Build Coastguard Worker }
240*6236dae4SAndroid Build Coastguard Worker return result;
241*6236dae4SAndroid Build Coastguard Worker }
242*6236dae4SAndroid Build Coastguard Worker
243*6236dae4SAndroid Build Coastguard Worker /*
244*6236dae4SAndroid Build Coastguard Worker * Write this single altsvc entry to a single output line
245*6236dae4SAndroid Build Coastguard Worker */
246*6236dae4SAndroid Build Coastguard Worker
altsvc_out(struct altsvc * as,FILE * fp)247*6236dae4SAndroid Build Coastguard Worker static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
248*6236dae4SAndroid Build Coastguard Worker {
249*6236dae4SAndroid Build Coastguard Worker struct tm stamp;
250*6236dae4SAndroid Build Coastguard Worker const char *dst6_pre = "";
251*6236dae4SAndroid Build Coastguard Worker const char *dst6_post = "";
252*6236dae4SAndroid Build Coastguard Worker const char *src6_pre = "";
253*6236dae4SAndroid Build Coastguard Worker const char *src6_post = "";
254*6236dae4SAndroid Build Coastguard Worker CURLcode result = Curl_gmtime(as->expires, &stamp);
255*6236dae4SAndroid Build Coastguard Worker if(result)
256*6236dae4SAndroid Build Coastguard Worker return result;
257*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
258*6236dae4SAndroid Build Coastguard Worker else {
259*6236dae4SAndroid Build Coastguard Worker char ipv6_unused[16];
260*6236dae4SAndroid Build Coastguard Worker if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
261*6236dae4SAndroid Build Coastguard Worker dst6_pre = "[";
262*6236dae4SAndroid Build Coastguard Worker dst6_post = "]";
263*6236dae4SAndroid Build Coastguard Worker }
264*6236dae4SAndroid Build Coastguard Worker if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
265*6236dae4SAndroid Build Coastguard Worker src6_pre = "[";
266*6236dae4SAndroid Build Coastguard Worker src6_post = "]";
267*6236dae4SAndroid Build Coastguard Worker }
268*6236dae4SAndroid Build Coastguard Worker }
269*6236dae4SAndroid Build Coastguard Worker #endif
270*6236dae4SAndroid Build Coastguard Worker fprintf(fp,
271*6236dae4SAndroid Build Coastguard Worker "%s %s%s%s %u "
272*6236dae4SAndroid Build Coastguard Worker "%s %s%s%s %u "
273*6236dae4SAndroid Build Coastguard Worker "\"%d%02d%02d "
274*6236dae4SAndroid Build Coastguard Worker "%02d:%02d:%02d\" "
275*6236dae4SAndroid Build Coastguard Worker "%u %u\n",
276*6236dae4SAndroid Build Coastguard Worker Curl_alpnid2str(as->src.alpnid),
277*6236dae4SAndroid Build Coastguard Worker src6_pre, as->src.host, src6_post,
278*6236dae4SAndroid Build Coastguard Worker as->src.port,
279*6236dae4SAndroid Build Coastguard Worker
280*6236dae4SAndroid Build Coastguard Worker Curl_alpnid2str(as->dst.alpnid),
281*6236dae4SAndroid Build Coastguard Worker dst6_pre, as->dst.host, dst6_post,
282*6236dae4SAndroid Build Coastguard Worker as->dst.port,
283*6236dae4SAndroid Build Coastguard Worker
284*6236dae4SAndroid Build Coastguard Worker stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
285*6236dae4SAndroid Build Coastguard Worker stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
286*6236dae4SAndroid Build Coastguard Worker as->persist, as->prio);
287*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
288*6236dae4SAndroid Build Coastguard Worker }
289*6236dae4SAndroid Build Coastguard Worker
290*6236dae4SAndroid Build Coastguard Worker /* ---- library-wide functions below ---- */
291*6236dae4SAndroid Build Coastguard Worker
292*6236dae4SAndroid Build Coastguard Worker /*
293*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_init() creates a new altsvc cache.
294*6236dae4SAndroid Build Coastguard Worker * It returns the new instance or NULL if something goes wrong.
295*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_init(void)296*6236dae4SAndroid Build Coastguard Worker struct altsvcinfo *Curl_altsvc_init(void)
297*6236dae4SAndroid Build Coastguard Worker {
298*6236dae4SAndroid Build Coastguard Worker struct altsvcinfo *asi = calloc(1, sizeof(struct altsvcinfo));
299*6236dae4SAndroid Build Coastguard Worker if(!asi)
300*6236dae4SAndroid Build Coastguard Worker return NULL;
301*6236dae4SAndroid Build Coastguard Worker Curl_llist_init(&asi->list, NULL);
302*6236dae4SAndroid Build Coastguard Worker
303*6236dae4SAndroid Build Coastguard Worker /* set default behavior */
304*6236dae4SAndroid Build Coastguard Worker asi->flags = CURLALTSVC_H1
305*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTP2
306*6236dae4SAndroid Build Coastguard Worker | CURLALTSVC_H2
307*6236dae4SAndroid Build Coastguard Worker #endif
308*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTP3
309*6236dae4SAndroid Build Coastguard Worker | CURLALTSVC_H3
310*6236dae4SAndroid Build Coastguard Worker #endif
311*6236dae4SAndroid Build Coastguard Worker ;
312*6236dae4SAndroid Build Coastguard Worker return asi;
313*6236dae4SAndroid Build Coastguard Worker }
314*6236dae4SAndroid Build Coastguard Worker
315*6236dae4SAndroid Build Coastguard Worker /*
316*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_load() loads alt-svc from file.
317*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_load(struct altsvcinfo * asi,const char * file)318*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
319*6236dae4SAndroid Build Coastguard Worker {
320*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(asi);
321*6236dae4SAndroid Build Coastguard Worker return altsvc_load(asi, file);
322*6236dae4SAndroid Build Coastguard Worker }
323*6236dae4SAndroid Build Coastguard Worker
324*6236dae4SAndroid Build Coastguard Worker /*
325*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_ctrl() passes on the external bitmask.
326*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_ctrl(struct altsvcinfo * asi,const long ctrl)327*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
328*6236dae4SAndroid Build Coastguard Worker {
329*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(asi);
330*6236dae4SAndroid Build Coastguard Worker asi->flags = ctrl;
331*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
332*6236dae4SAndroid Build Coastguard Worker }
333*6236dae4SAndroid Build Coastguard Worker
334*6236dae4SAndroid Build Coastguard Worker /*
335*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
336*6236dae4SAndroid Build Coastguard Worker * resources.
337*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_cleanup(struct altsvcinfo ** altsvcp)338*6236dae4SAndroid Build Coastguard Worker void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
339*6236dae4SAndroid Build Coastguard Worker {
340*6236dae4SAndroid Build Coastguard Worker if(*altsvcp) {
341*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
342*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *n;
343*6236dae4SAndroid Build Coastguard Worker struct altsvcinfo *altsvc = *altsvcp;
344*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&altsvc->list); e; e = n) {
345*6236dae4SAndroid Build Coastguard Worker struct altsvc *as = Curl_node_elem(e);
346*6236dae4SAndroid Build Coastguard Worker n = Curl_node_next(e);
347*6236dae4SAndroid Build Coastguard Worker altsvc_free(as);
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker free(altsvc->filename);
350*6236dae4SAndroid Build Coastguard Worker free(altsvc);
351*6236dae4SAndroid Build Coastguard Worker *altsvcp = NULL; /* clear the pointer */
352*6236dae4SAndroid Build Coastguard Worker }
353*6236dae4SAndroid Build Coastguard Worker }
354*6236dae4SAndroid Build Coastguard Worker
355*6236dae4SAndroid Build Coastguard Worker /*
356*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_save() writes the altsvc cache to a file.
357*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_save(struct Curl_easy * data,struct altsvcinfo * altsvc,const char * file)358*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_altsvc_save(struct Curl_easy *data,
359*6236dae4SAndroid Build Coastguard Worker struct altsvcinfo *altsvc, const char *file)
360*6236dae4SAndroid Build Coastguard Worker {
361*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
362*6236dae4SAndroid Build Coastguard Worker FILE *out;
363*6236dae4SAndroid Build Coastguard Worker char *tempstore = NULL;
364*6236dae4SAndroid Build Coastguard Worker
365*6236dae4SAndroid Build Coastguard Worker if(!altsvc)
366*6236dae4SAndroid Build Coastguard Worker /* no cache activated */
367*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
368*6236dae4SAndroid Build Coastguard Worker
369*6236dae4SAndroid Build Coastguard Worker /* if not new name is given, use the one we stored from the load */
370*6236dae4SAndroid Build Coastguard Worker if(!file && altsvc->filename)
371*6236dae4SAndroid Build Coastguard Worker file = altsvc->filename;
372*6236dae4SAndroid Build Coastguard Worker
373*6236dae4SAndroid Build Coastguard Worker if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
374*6236dae4SAndroid Build Coastguard Worker /* marked as read-only, no file or zero length filename */
375*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
376*6236dae4SAndroid Build Coastguard Worker
377*6236dae4SAndroid Build Coastguard Worker result = Curl_fopen(data, file, &out, &tempstore);
378*6236dae4SAndroid Build Coastguard Worker if(!result) {
379*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
380*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *n;
381*6236dae4SAndroid Build Coastguard Worker fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
382*6236dae4SAndroid Build Coastguard Worker "# This file was generated by libcurl! Edit at your own risk.\n",
383*6236dae4SAndroid Build Coastguard Worker out);
384*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&altsvc->list); e; e = n) {
385*6236dae4SAndroid Build Coastguard Worker struct altsvc *as = Curl_node_elem(e);
386*6236dae4SAndroid Build Coastguard Worker n = Curl_node_next(e);
387*6236dae4SAndroid Build Coastguard Worker result = altsvc_out(as, out);
388*6236dae4SAndroid Build Coastguard Worker if(result)
389*6236dae4SAndroid Build Coastguard Worker break;
390*6236dae4SAndroid Build Coastguard Worker }
391*6236dae4SAndroid Build Coastguard Worker fclose(out);
392*6236dae4SAndroid Build Coastguard Worker if(!result && tempstore && Curl_rename(tempstore, file))
393*6236dae4SAndroid Build Coastguard Worker result = CURLE_WRITE_ERROR;
394*6236dae4SAndroid Build Coastguard Worker
395*6236dae4SAndroid Build Coastguard Worker if(result && tempstore)
396*6236dae4SAndroid Build Coastguard Worker unlink(tempstore);
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker free(tempstore);
399*6236dae4SAndroid Build Coastguard Worker return result;
400*6236dae4SAndroid Build Coastguard Worker }
401*6236dae4SAndroid Build Coastguard Worker
getalnum(const char ** ptr,char * alpnbuf,size_t buflen)402*6236dae4SAndroid Build Coastguard Worker static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
403*6236dae4SAndroid Build Coastguard Worker {
404*6236dae4SAndroid Build Coastguard Worker size_t len;
405*6236dae4SAndroid Build Coastguard Worker const char *protop;
406*6236dae4SAndroid Build Coastguard Worker const char *p = *ptr;
407*6236dae4SAndroid Build Coastguard Worker while(*p && ISBLANK(*p))
408*6236dae4SAndroid Build Coastguard Worker p++;
409*6236dae4SAndroid Build Coastguard Worker protop = p;
410*6236dae4SAndroid Build Coastguard Worker while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
411*6236dae4SAndroid Build Coastguard Worker p++;
412*6236dae4SAndroid Build Coastguard Worker len = p - protop;
413*6236dae4SAndroid Build Coastguard Worker *ptr = p;
414*6236dae4SAndroid Build Coastguard Worker
415*6236dae4SAndroid Build Coastguard Worker if(!len || (len >= buflen))
416*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_FUNCTION_ARGUMENT;
417*6236dae4SAndroid Build Coastguard Worker memcpy(alpnbuf, protop, len);
418*6236dae4SAndroid Build Coastguard Worker alpnbuf[len] = 0;
419*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
420*6236dae4SAndroid Build Coastguard Worker }
421*6236dae4SAndroid Build Coastguard Worker
422*6236dae4SAndroid Build Coastguard Worker /* hostcompare() returns true if 'host' matches 'check'. The first host
423*6236dae4SAndroid Build Coastguard Worker * argument may have a trailing dot present that will be ignored.
424*6236dae4SAndroid Build Coastguard Worker */
hostcompare(const char * host,const char * check)425*6236dae4SAndroid Build Coastguard Worker static bool hostcompare(const char *host, const char *check)
426*6236dae4SAndroid Build Coastguard Worker {
427*6236dae4SAndroid Build Coastguard Worker size_t hlen = strlen(host);
428*6236dae4SAndroid Build Coastguard Worker size_t clen = strlen(check);
429*6236dae4SAndroid Build Coastguard Worker
430*6236dae4SAndroid Build Coastguard Worker if(hlen && (host[hlen - 1] == '.'))
431*6236dae4SAndroid Build Coastguard Worker hlen--;
432*6236dae4SAndroid Build Coastguard Worker if(hlen != clen)
433*6236dae4SAndroid Build Coastguard Worker /* they cannot match if they have different lengths */
434*6236dae4SAndroid Build Coastguard Worker return FALSE;
435*6236dae4SAndroid Build Coastguard Worker return strncasecompare(host, check, hlen);
436*6236dae4SAndroid Build Coastguard Worker }
437*6236dae4SAndroid Build Coastguard Worker
438*6236dae4SAndroid Build Coastguard Worker /* altsvc_flush() removes all alternatives for this source origin from the
439*6236dae4SAndroid Build Coastguard Worker list */
altsvc_flush(struct altsvcinfo * asi,enum alpnid srcalpnid,const char * srchost,unsigned short srcport)440*6236dae4SAndroid Build Coastguard Worker static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
441*6236dae4SAndroid Build Coastguard Worker const char *srchost, unsigned short srcport)
442*6236dae4SAndroid Build Coastguard Worker {
443*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
444*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *n;
445*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&asi->list); e; e = n) {
446*6236dae4SAndroid Build Coastguard Worker struct altsvc *as = Curl_node_elem(e);
447*6236dae4SAndroid Build Coastguard Worker n = Curl_node_next(e);
448*6236dae4SAndroid Build Coastguard Worker if((srcalpnid == as->src.alpnid) &&
449*6236dae4SAndroid Build Coastguard Worker (srcport == as->src.port) &&
450*6236dae4SAndroid Build Coastguard Worker hostcompare(srchost, as->src.host)) {
451*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
452*6236dae4SAndroid Build Coastguard Worker altsvc_free(as);
453*6236dae4SAndroid Build Coastguard Worker }
454*6236dae4SAndroid Build Coastguard Worker }
455*6236dae4SAndroid Build Coastguard Worker }
456*6236dae4SAndroid Build Coastguard Worker
457*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
458*6236dae4SAndroid Build Coastguard Worker /* to play well with debug builds, we can *set* a fixed time this will
459*6236dae4SAndroid Build Coastguard Worker return */
altsvc_debugtime(void * unused)460*6236dae4SAndroid Build Coastguard Worker static time_t altsvc_debugtime(void *unused)
461*6236dae4SAndroid Build Coastguard Worker {
462*6236dae4SAndroid Build Coastguard Worker char *timestr = getenv("CURL_TIME");
463*6236dae4SAndroid Build Coastguard Worker (void)unused;
464*6236dae4SAndroid Build Coastguard Worker if(timestr) {
465*6236dae4SAndroid Build Coastguard Worker long val = strtol(timestr, NULL, 10);
466*6236dae4SAndroid Build Coastguard Worker return (time_t)val;
467*6236dae4SAndroid Build Coastguard Worker }
468*6236dae4SAndroid Build Coastguard Worker return time(NULL);
469*6236dae4SAndroid Build Coastguard Worker }
470*6236dae4SAndroid Build Coastguard Worker #undef time
471*6236dae4SAndroid Build Coastguard Worker #define time(x) altsvc_debugtime(x)
472*6236dae4SAndroid Build Coastguard Worker #endif
473*6236dae4SAndroid Build Coastguard Worker
474*6236dae4SAndroid Build Coastguard Worker #define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
475*6236dae4SAndroid Build Coastguard Worker
476*6236dae4SAndroid Build Coastguard Worker /*
477*6236dae4SAndroid Build Coastguard Worker * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
478*6236dae4SAndroid Build Coastguard Worker * the data correctly in the cache.
479*6236dae4SAndroid Build Coastguard Worker *
480*6236dae4SAndroid Build Coastguard Worker * 'value' points to the header *value*. That is contents to the right of the
481*6236dae4SAndroid Build Coastguard Worker * header name.
482*6236dae4SAndroid Build Coastguard Worker *
483*6236dae4SAndroid Build Coastguard Worker * Currently this function rejects invalid data without returning an error.
484*6236dae4SAndroid Build Coastguard Worker * Invalid hostname, port number will result in the specific alternative
485*6236dae4SAndroid Build Coastguard Worker * being rejected. Unknown protocols are skipped.
486*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_parse(struct Curl_easy * data,struct altsvcinfo * asi,const char * value,enum alpnid srcalpnid,const char * srchost,unsigned short srcport)487*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_altsvc_parse(struct Curl_easy *data,
488*6236dae4SAndroid Build Coastguard Worker struct altsvcinfo *asi, const char *value,
489*6236dae4SAndroid Build Coastguard Worker enum alpnid srcalpnid, const char *srchost,
490*6236dae4SAndroid Build Coastguard Worker unsigned short srcport)
491*6236dae4SAndroid Build Coastguard Worker {
492*6236dae4SAndroid Build Coastguard Worker const char *p = value;
493*6236dae4SAndroid Build Coastguard Worker char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
494*6236dae4SAndroid Build Coastguard Worker struct altsvc *as;
495*6236dae4SAndroid Build Coastguard Worker unsigned short dstport = srcport; /* the same by default */
496*6236dae4SAndroid Build Coastguard Worker CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
497*6236dae4SAndroid Build Coastguard Worker size_t entries = 0;
498*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_DISABLE_VERBOSE_STRINGS
499*6236dae4SAndroid Build Coastguard Worker (void)data;
500*6236dae4SAndroid Build Coastguard Worker #endif
501*6236dae4SAndroid Build Coastguard Worker if(result) {
502*6236dae4SAndroid Build Coastguard Worker infof(data, "Excessive alt-svc header, ignoring.");
503*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
504*6236dae4SAndroid Build Coastguard Worker }
505*6236dae4SAndroid Build Coastguard Worker
506*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(asi);
507*6236dae4SAndroid Build Coastguard Worker
508*6236dae4SAndroid Build Coastguard Worker /* "clear" is a magic keyword */
509*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(alpnbuf, "clear")) {
510*6236dae4SAndroid Build Coastguard Worker /* Flush cached alternatives for this source origin */
511*6236dae4SAndroid Build Coastguard Worker altsvc_flush(asi, srcalpnid, srchost, srcport);
512*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
513*6236dae4SAndroid Build Coastguard Worker }
514*6236dae4SAndroid Build Coastguard Worker
515*6236dae4SAndroid Build Coastguard Worker do {
516*6236dae4SAndroid Build Coastguard Worker if(*p == '=') {
517*6236dae4SAndroid Build Coastguard Worker /* [protocol]="[host][:port]" */
518*6236dae4SAndroid Build Coastguard Worker enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */
519*6236dae4SAndroid Build Coastguard Worker p++;
520*6236dae4SAndroid Build Coastguard Worker if(*p == '\"') {
521*6236dae4SAndroid Build Coastguard Worker const char *dsthost = "";
522*6236dae4SAndroid Build Coastguard Worker size_t dstlen = 0; /* destination hostname length */
523*6236dae4SAndroid Build Coastguard Worker const char *value_ptr;
524*6236dae4SAndroid Build Coastguard Worker char option[32];
525*6236dae4SAndroid Build Coastguard Worker unsigned long num;
526*6236dae4SAndroid Build Coastguard Worker char *end_ptr;
527*6236dae4SAndroid Build Coastguard Worker bool quoted = FALSE;
528*6236dae4SAndroid Build Coastguard Worker time_t maxage = 24 * 3600; /* default is 24 hours */
529*6236dae4SAndroid Build Coastguard Worker bool persist = FALSE;
530*6236dae4SAndroid Build Coastguard Worker bool valid = TRUE;
531*6236dae4SAndroid Build Coastguard Worker p++;
532*6236dae4SAndroid Build Coastguard Worker if(*p != ':') {
533*6236dae4SAndroid Build Coastguard Worker /* hostname starts here */
534*6236dae4SAndroid Build Coastguard Worker const char *hostp = p;
535*6236dae4SAndroid Build Coastguard Worker if(*p == '[') {
536*6236dae4SAndroid Build Coastguard Worker /* pass all valid IPv6 letters - does not handle zone id */
537*6236dae4SAndroid Build Coastguard Worker dstlen = strspn(++p, "0123456789abcdefABCDEF:.");
538*6236dae4SAndroid Build Coastguard Worker if(p[dstlen] != ']')
539*6236dae4SAndroid Build Coastguard Worker /* invalid host syntax, bail out */
540*6236dae4SAndroid Build Coastguard Worker break;
541*6236dae4SAndroid Build Coastguard Worker /* we store the IPv6 numerical address *with* brackets */
542*6236dae4SAndroid Build Coastguard Worker dstlen += 2;
543*6236dae4SAndroid Build Coastguard Worker p = &p[dstlen-1];
544*6236dae4SAndroid Build Coastguard Worker }
545*6236dae4SAndroid Build Coastguard Worker else {
546*6236dae4SAndroid Build Coastguard Worker while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
547*6236dae4SAndroid Build Coastguard Worker p++;
548*6236dae4SAndroid Build Coastguard Worker dstlen = p - hostp;
549*6236dae4SAndroid Build Coastguard Worker }
550*6236dae4SAndroid Build Coastguard Worker if(!dstlen || (dstlen >= MAX_ALTSVC_HOSTLEN)) {
551*6236dae4SAndroid Build Coastguard Worker infof(data, "Excessive alt-svc hostname, ignoring.");
552*6236dae4SAndroid Build Coastguard Worker valid = FALSE;
553*6236dae4SAndroid Build Coastguard Worker }
554*6236dae4SAndroid Build Coastguard Worker else {
555*6236dae4SAndroid Build Coastguard Worker dsthost = hostp;
556*6236dae4SAndroid Build Coastguard Worker }
557*6236dae4SAndroid Build Coastguard Worker }
558*6236dae4SAndroid Build Coastguard Worker else {
559*6236dae4SAndroid Build Coastguard Worker /* no destination name, use source host */
560*6236dae4SAndroid Build Coastguard Worker dsthost = srchost;
561*6236dae4SAndroid Build Coastguard Worker dstlen = strlen(srchost);
562*6236dae4SAndroid Build Coastguard Worker }
563*6236dae4SAndroid Build Coastguard Worker if(*p == ':') {
564*6236dae4SAndroid Build Coastguard Worker unsigned long port = 0;
565*6236dae4SAndroid Build Coastguard Worker p++;
566*6236dae4SAndroid Build Coastguard Worker if(ISDIGIT(*p))
567*6236dae4SAndroid Build Coastguard Worker /* a port number */
568*6236dae4SAndroid Build Coastguard Worker port = strtoul(p, &end_ptr, 10);
569*6236dae4SAndroid Build Coastguard Worker else
570*6236dae4SAndroid Build Coastguard Worker end_ptr = (char *)p; /* not left uninitialized */
571*6236dae4SAndroid Build Coastguard Worker if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
572*6236dae4SAndroid Build Coastguard Worker infof(data, "Unknown alt-svc port number, ignoring.");
573*6236dae4SAndroid Build Coastguard Worker valid = FALSE;
574*6236dae4SAndroid Build Coastguard Worker }
575*6236dae4SAndroid Build Coastguard Worker else {
576*6236dae4SAndroid Build Coastguard Worker dstport = curlx_ultous(port);
577*6236dae4SAndroid Build Coastguard Worker p = end_ptr;
578*6236dae4SAndroid Build Coastguard Worker }
579*6236dae4SAndroid Build Coastguard Worker }
580*6236dae4SAndroid Build Coastguard Worker if(*p++ != '\"')
581*6236dae4SAndroid Build Coastguard Worker break;
582*6236dae4SAndroid Build Coastguard Worker /* Handle the optional 'ma' and 'persist' flags. Unknown flags
583*6236dae4SAndroid Build Coastguard Worker are skipped. */
584*6236dae4SAndroid Build Coastguard Worker for(;;) {
585*6236dae4SAndroid Build Coastguard Worker while(ISBLANK(*p))
586*6236dae4SAndroid Build Coastguard Worker p++;
587*6236dae4SAndroid Build Coastguard Worker if(*p != ';')
588*6236dae4SAndroid Build Coastguard Worker break;
589*6236dae4SAndroid Build Coastguard Worker p++; /* pass the semicolon */
590*6236dae4SAndroid Build Coastguard Worker if(!*p || ISNEWLINE(*p))
591*6236dae4SAndroid Build Coastguard Worker break;
592*6236dae4SAndroid Build Coastguard Worker result = getalnum(&p, option, sizeof(option));
593*6236dae4SAndroid Build Coastguard Worker if(result) {
594*6236dae4SAndroid Build Coastguard Worker /* skip option if name is too long */
595*6236dae4SAndroid Build Coastguard Worker option[0] = '\0';
596*6236dae4SAndroid Build Coastguard Worker }
597*6236dae4SAndroid Build Coastguard Worker while(*p && ISBLANK(*p))
598*6236dae4SAndroid Build Coastguard Worker p++;
599*6236dae4SAndroid Build Coastguard Worker if(*p != '=')
600*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
601*6236dae4SAndroid Build Coastguard Worker p++;
602*6236dae4SAndroid Build Coastguard Worker while(*p && ISBLANK(*p))
603*6236dae4SAndroid Build Coastguard Worker p++;
604*6236dae4SAndroid Build Coastguard Worker if(!*p)
605*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
606*6236dae4SAndroid Build Coastguard Worker if(*p == '\"') {
607*6236dae4SAndroid Build Coastguard Worker /* quoted value */
608*6236dae4SAndroid Build Coastguard Worker p++;
609*6236dae4SAndroid Build Coastguard Worker quoted = TRUE;
610*6236dae4SAndroid Build Coastguard Worker }
611*6236dae4SAndroid Build Coastguard Worker value_ptr = p;
612*6236dae4SAndroid Build Coastguard Worker if(quoted) {
613*6236dae4SAndroid Build Coastguard Worker while(*p && *p != '\"')
614*6236dae4SAndroid Build Coastguard Worker p++;
615*6236dae4SAndroid Build Coastguard Worker if(!*p++)
616*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
617*6236dae4SAndroid Build Coastguard Worker }
618*6236dae4SAndroid Build Coastguard Worker else {
619*6236dae4SAndroid Build Coastguard Worker while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
620*6236dae4SAndroid Build Coastguard Worker p++;
621*6236dae4SAndroid Build Coastguard Worker }
622*6236dae4SAndroid Build Coastguard Worker num = strtoul(value_ptr, &end_ptr, 10);
623*6236dae4SAndroid Build Coastguard Worker if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
624*6236dae4SAndroid Build Coastguard Worker if(strcasecompare("ma", option))
625*6236dae4SAndroid Build Coastguard Worker maxage = (time_t)num;
626*6236dae4SAndroid Build Coastguard Worker else if(strcasecompare("persist", option) && (num == 1))
627*6236dae4SAndroid Build Coastguard Worker persist = TRUE;
628*6236dae4SAndroid Build Coastguard Worker }
629*6236dae4SAndroid Build Coastguard Worker }
630*6236dae4SAndroid Build Coastguard Worker if(dstalpnid && valid) {
631*6236dae4SAndroid Build Coastguard Worker if(!entries++)
632*6236dae4SAndroid Build Coastguard Worker /* Flush cached alternatives for this source origin, if any - when
633*6236dae4SAndroid Build Coastguard Worker this is the first entry of the line. */
634*6236dae4SAndroid Build Coastguard Worker altsvc_flush(asi, srcalpnid, srchost, srcport);
635*6236dae4SAndroid Build Coastguard Worker
636*6236dae4SAndroid Build Coastguard Worker as = altsvc_createid(srchost, dsthost, dstlen,
637*6236dae4SAndroid Build Coastguard Worker srcalpnid, dstalpnid,
638*6236dae4SAndroid Build Coastguard Worker srcport, dstport);
639*6236dae4SAndroid Build Coastguard Worker if(as) {
640*6236dae4SAndroid Build Coastguard Worker /* The expires time also needs to take the Age: value (if any) into
641*6236dae4SAndroid Build Coastguard Worker account. [See RFC 7838 section 3.1] */
642*6236dae4SAndroid Build Coastguard Worker as->expires = maxage + time(NULL);
643*6236dae4SAndroid Build Coastguard Worker as->persist = persist;
644*6236dae4SAndroid Build Coastguard Worker Curl_llist_append(&asi->list, as, &as->node);
645*6236dae4SAndroid Build Coastguard Worker infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
646*6236dae4SAndroid Build Coastguard Worker Curl_alpnid2str(dstalpnid));
647*6236dae4SAndroid Build Coastguard Worker }
648*6236dae4SAndroid Build Coastguard Worker }
649*6236dae4SAndroid Build Coastguard Worker }
650*6236dae4SAndroid Build Coastguard Worker else
651*6236dae4SAndroid Build Coastguard Worker break;
652*6236dae4SAndroid Build Coastguard Worker /* after the double quote there can be a comma if there is another
653*6236dae4SAndroid Build Coastguard Worker string or a semicolon if no more */
654*6236dae4SAndroid Build Coastguard Worker if(*p == ',') {
655*6236dae4SAndroid Build Coastguard Worker /* comma means another alternative is presented */
656*6236dae4SAndroid Build Coastguard Worker p++;
657*6236dae4SAndroid Build Coastguard Worker result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
658*6236dae4SAndroid Build Coastguard Worker if(result)
659*6236dae4SAndroid Build Coastguard Worker break;
660*6236dae4SAndroid Build Coastguard Worker }
661*6236dae4SAndroid Build Coastguard Worker }
662*6236dae4SAndroid Build Coastguard Worker else
663*6236dae4SAndroid Build Coastguard Worker break;
664*6236dae4SAndroid Build Coastguard Worker } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
665*6236dae4SAndroid Build Coastguard Worker
666*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
667*6236dae4SAndroid Build Coastguard Worker }
668*6236dae4SAndroid Build Coastguard Worker
669*6236dae4SAndroid Build Coastguard Worker /*
670*6236dae4SAndroid Build Coastguard Worker * Return TRUE on a match
671*6236dae4SAndroid Build Coastguard Worker */
Curl_altsvc_lookup(struct altsvcinfo * asi,enum alpnid srcalpnid,const char * srchost,int srcport,struct altsvc ** dstentry,const int versions)672*6236dae4SAndroid Build Coastguard Worker bool Curl_altsvc_lookup(struct altsvcinfo *asi,
673*6236dae4SAndroid Build Coastguard Worker enum alpnid srcalpnid, const char *srchost,
674*6236dae4SAndroid Build Coastguard Worker int srcport,
675*6236dae4SAndroid Build Coastguard Worker struct altsvc **dstentry,
676*6236dae4SAndroid Build Coastguard Worker const int versions) /* one or more bits */
677*6236dae4SAndroid Build Coastguard Worker {
678*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
679*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *n;
680*6236dae4SAndroid Build Coastguard Worker time_t now = time(NULL);
681*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(asi);
682*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(srchost);
683*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(dstentry);
684*6236dae4SAndroid Build Coastguard Worker
685*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&asi->list); e; e = n) {
686*6236dae4SAndroid Build Coastguard Worker struct altsvc *as = Curl_node_elem(e);
687*6236dae4SAndroid Build Coastguard Worker n = Curl_node_next(e);
688*6236dae4SAndroid Build Coastguard Worker if(as->expires < now) {
689*6236dae4SAndroid Build Coastguard Worker /* an expired entry, remove */
690*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
691*6236dae4SAndroid Build Coastguard Worker altsvc_free(as);
692*6236dae4SAndroid Build Coastguard Worker continue;
693*6236dae4SAndroid Build Coastguard Worker }
694*6236dae4SAndroid Build Coastguard Worker if((as->src.alpnid == srcalpnid) &&
695*6236dae4SAndroid Build Coastguard Worker hostcompare(srchost, as->src.host) &&
696*6236dae4SAndroid Build Coastguard Worker (as->src.port == srcport) &&
697*6236dae4SAndroid Build Coastguard Worker (versions & (int)as->dst.alpnid)) {
698*6236dae4SAndroid Build Coastguard Worker /* match */
699*6236dae4SAndroid Build Coastguard Worker *dstentry = as;
700*6236dae4SAndroid Build Coastguard Worker return TRUE;
701*6236dae4SAndroid Build Coastguard Worker }
702*6236dae4SAndroid Build Coastguard Worker }
703*6236dae4SAndroid Build Coastguard Worker return FALSE;
704*6236dae4SAndroid Build Coastguard Worker }
705*6236dae4SAndroid Build Coastguard Worker
706*6236dae4SAndroid Build Coastguard Worker #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
707