diff --git a/src/parse.c b/src/parse.c index b2789fe..bb16b7c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1424,8 +1424,8 @@ static int parse_date(Scanner *s, HTTP_Date *out) out->year = (s->src[s->cur+0] - '0') * 1000 + (s->src[s->cur+1] - '0') * 100 - + (s->src[s->cur+1] - '0') * 10 - + (s->src[s->cur+1] - '0') * 1; + + (s->src[s->cur+2] - '0') * 10 + + (s->src[s->cur+3] - '0') * 1; s->cur += 4; if (s->cur == s->len || s->src[s->cur] != ' ') @@ -1469,46 +1469,57 @@ static bool is_cookie_octet(char c) } typedef struct { + HTTP_String name; HTTP_String value; + bool secure; + bool http_only; + + bool have_date; + HTTP_Date date; + + bool have_max_age; + uint32_t max_age; + + bool have_domain; + HTTP_String domain; + } HTTP_SetCookie; void http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out) { - char *src = str.ptr; - int len = str.len; - int cur = 0; + Scanner s = { str.ptr, str.len, 0 }; // cookie-name = token - if (cur == len || !is_tchar(src[cur])) + if (s.cur == s.len || !is_tchar(s.src[s.cur])) return -1; - int off = cur; + int off = s.cur; do - cur++; - while (cur < len && is_tchar(src[cur])); - out->name = (HTTP_String) { src + off, cur - off }; + s.cur++; + while (s.cur < s.len && is_tchar(s.src[s.cur])); + out->name = (HTTP_String) { s.src + off, s.cur - off }; // cookie-pair = cookie-name "=" cookie-value - if (cur == len || src[cur] != '=') + if (s.cur == s.len || s.src[s.cur] != '=') return -1; - cur++; + s.cur++; // cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) - if (cur < len && src[cur] == '"') { - cur++; // Consume opening double quote - int off = cur; - while (cur < len && is_cookie_octet(src[cur])) - cur++; - if (cur == len || src[cur] != '"') + if (s.cur < s.len && s.src[s.cur] == '"') { + s.cur++; // Consume opening double quote + int off = s.cur; + while (s.cur < s.len && is_cookie_octet(s.src[s.cur])) + s.cur++; + if (s.cur == s.len || s.src[s.cur] != '"') return -1; // Missing closing double quote - out->value = (HTTP_String) { src + off, cur - off }; - cur++; // Consume closing double quote + out->value = (HTTP_String) { s.src + off, s.cur - off }; + s.cur++; // Consume closing double quote } else { - int off = cur; - while (cur < len && is_cookie_octet(src[cur])) - cur++; - out->value = (HTTP_String) { src + off, cur - off }; + int off = s.cur; + while (s.cur < s.len && is_cookie_octet(s.src[s.cur])) + s.cur++; + out->value = (HTTP_String) { s.src + off, s.cur - off }; } // *( ";" SP cookie-av ) @@ -1516,93 +1527,104 @@ void http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out) // cookie-av = expires-av / max-age-av / domain-av / // path-av / secure-av / httponly-av / // extension-av - while (cur < len && src[cur] == ';') { - cur++; // Consume semicolon + out->secure = false; + out->http_only = false; + out->have_date = false; + out->have_max_age = false; + out->have_domain = false; + while (consume_str(&s, HTTP_STR("; "))) { + if (consume_str(&s, HTTP_STR("Expires="))) { - if (cur == len || src[cur] != ' ') - return -1; // Missing space after semicolon - cur++; + // expires-av = "Expires=" sane-cookie-date + if (parse_date(&s, &out->date) < 0) + return -1; + out->have_date = true; - // expires-av = "Expires=" sane-cookie-date - if (7 < len - cur - && src[cur+0] == 'E' - && src[cur+1] == 'x' - && src[cur+2] == 'p' - && src[cur+3] == 'i' - && src[cur+4] == 'r' - && src[cur+5] == 'e' - && src[cur+6] == 's' - && src[cur+7] == '=') { - cur += 8; - - // TODO + } else if (consume_str(&s, HTTP_STR("Max-Age="))) { // max-age-av = "Max-Age=" non-zero-digit *DIGIT - } else if (7 < len - cur - && src[cur+0] == 'M' - && src[cur+1] == 'a' - && src[cur+2] == 'x' - && src[cur+3] == '-' - && src[cur+4] == 'A' - && src[cur+5] == 'g' - && src[cur+6] == 'e' - && src[cur+7] == '=') { - cur += 8; + + uint32_t value = 0; + if (s.cur == s.len || !is_digit(s.src[s.cur])) + return -1; + do { + int d = s.src[s.cur++] - '0'; + if (value > (UINT32_MAX - d) / 10) + return -1; + value = value * 10 + d; + } while (s.cur < s.len && is_digit(s.src[s.cur])); + + out->have_max_age = true; + out->max_age = value; + + } else if (consume_str(&s, HTTP_STR("Domain="))) { // domain-av = "Domain=" domain-value - } else if (6 < len - cur - && src[cur+0] == 'D' - && src[cur+1] == 'o' - && src[cur+2] == 'm' - && src[cur+3] == 'a' - && src[cur+4] == 'i' - && src[cur+5] == 'n' - && src[cur+6] == '=') { - cur += 7; - // domain-value = // ; defined in RFC 1034, Section 3.5 - // TODO + // + // From RFC 1034: + // ::=