summaryrefslogtreecommitdiff
path: root/lib/altsvc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/altsvc.c')
-rw-r--r--lib/altsvc.c171
1 files changed, 98 insertions, 73 deletions
diff --git a/lib/altsvc.c b/lib/altsvc.c
index 93204e012..0e9a97826 100644
--- a/lib/altsvc.c
+++ b/lib/altsvc.c
@@ -351,12 +351,12 @@ static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
p++;
len = p - protop;
+ *ptr = p;
if(!len || (len >= buflen))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(alpnbuf, protop, len);
alpnbuf[len] = 0;
- *ptr = p;
return CURLE_OK;
}
@@ -402,6 +402,10 @@ static time_t debugtime(void *unused)
*
* 'value' points to the header *value*. That's contents to the right of the
* header name.
+ *
+ * Currently this function rejects invalid data without returning an error.
+ * Invalid host name, port number will result in the specific alternative
+ * being rejected. Unknown protocols are skipped.
*/
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
struct altsvcinfo *asi, const char *value,
@@ -415,12 +419,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
struct altsvc *as;
unsigned short dstport = srcport; /* the same by default */
- const char *semip;
- time_t maxage = 24 * 3600; /* default is 24 hours */
- bool persist = FALSE;
CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
- if(result)
- return result;
+ if(result) {
+ infof(data, "Excessive alt-svc header, ignoring...\n");
+ return CURLE_OK;
+ }
DEBUGASSERT(asi);
@@ -432,57 +435,20 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
return CURLE_OK;
}
- /* The 'ma' and 'persist' flags are annoyingly meant for all alternatives
- but are set after the list on the line. Scan for the semicolons and get
- those fields first! */
- semip = p;
- do {
- semip = strchr(semip, ';');
- if(semip) {
- char option[32];
- unsigned long num;
- char *end_ptr;
- bool quoted = FALSE;
- semip++; /* pass the semicolon */
- result = getalnum(&semip, option, sizeof(option));
- if(result)
- break;
- while(*semip && ISBLANK(*semip))
- semip++;
- if(*semip != '=')
- continue;
- semip++;
- while(*semip && ISBLANK(*semip))
- semip++;
- if(*semip == '\"') {
- /* quoted value */
- semip++;
- quoted = TRUE;
- }
- num = strtoul(semip, &end_ptr, 10);
- if((end_ptr != semip) && num && (num < ULONG_MAX)) {
- if(strcasecompare("ma", option))
- maxage = num;
- else if(strcasecompare("persist", option) && (num == 1))
- persist = TRUE;
- if(quoted && (*end_ptr == '\"'))
- end_ptr++;
- }
- semip = end_ptr;
- }
- } while(semip);
-
do {
if(*p == '=') {
/* [protocol]="[host][:port]" */
dstalpnid = alpn2alpnid(alpnbuf);
- if(!dstalpnid) {
- infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf);
- return CURLE_OK;
- }
p++;
if(*p == '\"') {
const char *dsthost;
+ const char *value_ptr;
+ char option[32];
+ unsigned long num;
+ char *end_ptr;
+ bool quoted = FALSE;
+ time_t maxage = 24 * 3600; /* default is 24 hours */
+ bool persist = FALSE;
p++;
if(*p != ':') {
/* host name starts here */
@@ -490,11 +456,15 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
p++;
len = p - hostp;
- if(!len || (len >= MAX_ALTSVC_HOSTLEN))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- memcpy(namebuf, hostp, len);
- namebuf[len] = 0;
- dsthost = namebuf;
+ if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
+ infof(data, "Excessive alt-svc host name, ignoring...\n");
+ dstalpnid = ALPN_none;
+ }
+ else {
+ memcpy(namebuf, hostp, len);
+ namebuf[len] = 0;
+ dsthost = namebuf;
+ }
}
else {
/* no destination name, use source host */
@@ -502,31 +472,86 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
}
if(*p == ':') {
/* a port number */
- char *end_ptr;
unsigned long port = strtoul(++p, &end_ptr, 10);
if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
infof(data, "Unknown alt-svc port number, ignoring...\n");
- return CURLE_OK;
+ dstalpnid = ALPN_none;
}
p = end_ptr;
dstport = curlx_ultous(port);
}
if(*p++ != '\"')
- return CURLE_BAD_FUNCTION_ARGUMENT;
- as = altsvc_createid(srchost, dsthost,
- srcalpnid, dstalpnid,
- srcport, dstport);
- if(as) {
- /* The expires time also needs to take the Age: value (if any) into
- account. [See RFC 7838 section 3.1] */
- as->expires = maxage + time(NULL);
- as->persist = persist;
- Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
- asi->num++; /* one more entry */
- infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
- Curl_alpnid2str(dstalpnid));
+ break;
+ /* Handle the optional 'ma' and 'persist' flags. Unknown flags
+ are skipped. */
+ for(;;) {
+ while(*p && ISBLANK(*p) && *p != ';' && *p != ',')
+ p++;
+ if(!*p || *p == ',')
+ break;
+ p++; /* pass the semicolon */
+ if(!*p)
+ break;
+ result = getalnum(&p, option, sizeof(option));
+ if(result) {
+ /* skip option if name is too long */
+ option[0] = '\0';
+ }
+ while(*p && ISBLANK(*p))
+ p++;
+ if(*p != '=')
+ return CURLE_OK;
+ p++;
+ while(*p && ISBLANK(*p))
+ p++;
+ if(!*p)
+ return CURLE_OK;
+ if(*p == '\"') {
+ /* quoted value */
+ p++;
+ quoted = TRUE;
+ }
+ value_ptr = p;
+ if(quoted) {
+ while(*p && *p != '\"')
+ p++;
+ if(!*p++)
+ return CURLE_OK;
+ }
+ else {
+ while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
+ p++;
+ }
+ num = strtoul(value_ptr, &end_ptr, 10);
+ if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
+ if(strcasecompare("ma", option))
+ maxage = num;
+ else if(strcasecompare("persist", option) && (num == 1))
+ persist = TRUE;
+ }
+ }
+ if(dstalpnid) {
+ as = altsvc_createid(srchost, dsthost,
+ srcalpnid, dstalpnid,
+ srcport, dstport);
+ if(as) {
+ /* The expires time also needs to take the Age: value (if any) into
+ account. [See RFC 7838 section 3.1] */
+ as->expires = maxage + time(NULL);
+ as->persist = persist;
+ Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+ asi->num++; /* one more entry */
+ infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
+ Curl_alpnid2str(dstalpnid));
+ }
+ }
+ else {
+ infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n",
+ alpnbuf);
}
}
+ else
+ break;
/* after the double quote there can be a comma if there's another
string or a semicolon if no more */
if(*p == ',') {
@@ -534,11 +559,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
p++;
result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
if(result)
- /* failed to parse, but since we already did at least one host we
- return OK */
- return CURLE_OK;
+ break;
}
}
+ else
+ break;
} while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
return CURLE_OK;