int parse_new_cookie(http_request req, const char* value, meta_error e) { cookie c; assert(NULL != req); assert(NULL != value); if( (c = cookie_new()) == NULL) return set_os_error(e, ENOMEM); /* New cookies require this field! */ if(!parse_new_cookie_version(c, value, e)) { cookie_free(c); return 0; } /* Now for the rest of the attributes */ if(!parse_new_cookie_name(c, value, e) || !parse_new_cookie_path(c, value, e) || !parse_new_cookie_domain(c, value, e) || !parse_new_cookie_secure(c, value, e)) { cookie_free(c); return 0; } if(!request_add_cookie(req, c)) { set_os_error(e, errno); cookie_free(c); return 0; } else return 1; }
/* * The old cookie format is (hopefully) name=value * where value may be quoted. */ int parse_old_cookie(http_request req, const char* input, meta_error e) { cookie c = NULL; cstring name = NULL, value = NULL; if( (name = cstring_new()) == NULL || (value = cstring_new()) == NULL) goto memerr; while(*input != '\0' && *input != '=') { if(!cstring_charcat(name, *input++)) goto memerr; } if(*input != '=') { cstring_free(name); cstring_free(value); return set_http_error(e, HTTP_400_BAD_REQUEST); } input++; /* Skip '=' */ if(!cstring_copy(value, input)) goto memerr; if( (c = cookie_new()) == NULL) goto memerr; if(!cookie_set_name(c, c_str(name)) || !cookie_set_value(c, c_str(value))) goto memerr; cstring_free(name); cstring_free(value); cookie_set_version(c, 0); if(!request_add_cookie(req, c)) { set_os_error(e, errno); cookie_free(c); return 0; } return 1; memerr: cstring_free(name); cstring_free(value); cookie_free(c); return set_os_error(e, ENOMEM); }
int main(void) { cookie c; size_t i, niter = 10000; const char* name = "name"; const char* value = "value"; const char* domain = "DOMAIN"; const char* path = "PATH"; const char* comment = "THIS IS A COMMENT"; int max_age = 0; int secure = 1; int version = 1; for(i = 0; i < niter; i++) { if( (c = cookie_new()) == NULL) return 77; if(!cookie_set_name(c, name)) return 77; if(!cookie_set_value(c, value)) return 77; if(!cookie_set_domain(c, domain)) return 77; if(!cookie_set_path(c, path)) return 77; if(!cookie_set_comment(c, comment)) return 77; if(!cookie_set_max_age(c, max_age)) return 77; cookie_set_secure(c, secure); cookie_set_version(c, version); if(strcmp(cookie_get_name(c), name) != 0) return 77; if(strcmp(cookie_get_value(c), value) != 0) return 77; if(strcmp(cookie_get_domain(c), domain) != 0) return 77; if(strcmp(cookie_get_path(c), path) != 0) return 77; if(strcmp(cookie_get_comment(c), comment) != 0) return 77; if(cookie_get_max_age(c) != max_age) return 77; if(cookie_get_secure(c) != secure) return 77; if(cookie_get_version(c) != version) return 77; cookie_free(c); } return 0; }
static struct cookie * parse_set_cookies (const char *sc) { struct cookie *cookie = cookie_new (); enum { S_NAME_PRE, S_NAME, S_NAME_POST, S_VALUE_PRE, S_VALUE, S_VALUE_TRAILSPACE_MAYBE, S_QUOTED_VALUE, S_QUOTED_VALUE_POST, S_ATTR_ACTION, S_DONE, S_ERROR } state = S_NAME_PRE; const char *p = sc; char c; const char *name_b = NULL, *name_e = NULL; const char *value_b = NULL, *value_e = NULL; FETCH (c, p); while (state != S_DONE && state != S_ERROR) { switch (state) { case S_NAME_PRE: if (ISSPACE (c)) FETCH (c, p); else if (ATTR_NAME_CHAR (c)) { name_b = p - 1; FETCH1 (c, p); state = S_NAME; } else /* empty attr name not allowed */ state = S_ERROR; break; case S_NAME: if (ATTR_NAME_CHAR (c)) FETCH1 (c, p); else if (!c || c == ';' || c == '=' || ISSPACE (c)) { name_e = p - 1; state = S_NAME_POST; } else state = S_ERROR; break; case S_NAME_POST: if (ISSPACE (c)) FETCH1 (c, p); else if (!c || c == ';') { value_b = value_e = NULL; state = S_ATTR_ACTION; } else if (c == '=') { FETCH1 (c, p); state = S_VALUE_PRE; } else state = S_ERROR; break; case S_VALUE_PRE: if (ISSPACE (c)) FETCH1 (c, p); else if (c == '"') { value_b = p; FETCH (c, p); state = S_QUOTED_VALUE; } else if (c == ';' || c == '\0') { value_b = value_e = p - 1; state = S_ATTR_ACTION; } else { value_b = p - 1; value_e = NULL; state = S_VALUE; } break; case S_VALUE: if (c == ';' || c == '\0') { if (!value_e) value_e = p - 1; state = S_ATTR_ACTION; } else if (ISSPACE (c)) { value_e = p - 1; FETCH1 (c, p); state = S_VALUE_TRAILSPACE_MAYBE; } else { value_e = NULL; /* no trailing space */ FETCH1 (c, p); } break; case S_VALUE_TRAILSPACE_MAYBE: if (ISSPACE (c)) FETCH1 (c, p); else state = S_VALUE; break; case S_QUOTED_VALUE: if (c == '"') { value_e = p - 1; FETCH1 (c, p); state = S_QUOTED_VALUE_POST; } else FETCH (c, p); break; case S_QUOTED_VALUE_POST: if (c == ';' || !c) state = S_ATTR_ACTION; else if (ISSPACE (c)) FETCH1 (c, p); else state = S_ERROR; break; case S_ATTR_ACTION: { int legal = update_cookie_field (cookie, name_b, name_e, value_b, value_e); if (!legal) { char *name; BOUNDED_TO_ALLOCA (name_b, name_e, name); logprintf (LOG_NOTQUIET, _("Error in Set-Cookie, field `%s'"), name); state = S_ERROR; break; } if (c) FETCH1 (c, p); if (!c) state = S_DONE; else state = S_NAME_PRE; } break; case S_DONE: case S_ERROR: /* handled by loop condition */ break; } } if (state == S_DONE) return cookie; delete_cookie (cookie); if (state == S_ERROR) logprintf (LOG_NOTQUIET, _("Syntax error in Set-Cookie at character `%c'.\n"), c); else abort (); return NULL; eof: delete_cookie (cookie); logprintf (LOG_NOTQUIET, _("Syntax error in Set-Cookie: premature end of string.\n")); return NULL; }
void load_cookies (const char *file) { char *line; FILE *fp = fopen (file, "r"); if (!fp) { logprintf (LOG_NOTQUIET, "Cannot open cookies file `%s': %s\n", file, strerror (errno)); return; } cookies_now = time (NULL); for (; ((line = read_whole_line (fp)) != NULL); xfree (line)) { struct cookie *cookie; char *p = line; int port; char *domain_b = NULL, *domain_e = NULL; char *ignore_b = NULL, *ignore_e = NULL; char *path_b = NULL, *path_e = NULL; char *secure_b = NULL, *secure_e = NULL; char *expires_b = NULL, *expires_e = NULL; char *name_b = NULL, *name_e = NULL; char *value_b = NULL, *value_e = NULL; SKIP_WS (p); if (!*p || *p == '#') /* empty line */ continue; SET_WORD_BOUNDARIES (p, domain_b, domain_e); SET_WORD_BOUNDARIES (p, ignore_b, ignore_e); SET_WORD_BOUNDARIES (p, path_b, path_e); SET_WORD_BOUNDARIES (p, secure_b, secure_e); SET_WORD_BOUNDARIES (p, expires_b, expires_e); SET_WORD_BOUNDARIES (p, name_b, name_e); /* Don't use SET_WORD_BOUNDARIES for value because it may contain whitespace. Instead, set value_e to the end of line, modulo trailing space (this will skip the line separator.) */ SKIP_WS (p); value_b = p; value_e = p + strlen (p); while (value_e > value_b && ISSPACE (*(value_e - 1))) --value_e; if (value_b == value_e) /* Hmm, should we check for empty value? I guess that's legal, so I leave it. */ ; cookie = cookie_new (); cookie->attr = strdupdelim (name_b, name_e); cookie->value = strdupdelim (value_b, value_e); cookie->path = strdupdelim (path_b, path_e); if (BOUNDED_EQUAL (secure_b, secure_e, "TRUE")) cookie->secure = 1; /* DOMAIN needs special treatment because we might need to extract the port. */ port = domain_port (domain_b, domain_e, (const char **)&domain_e); if (port) cookie->port = port; else cookie->port = cookie->secure ? DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT; cookie->domain = strdupdelim (domain_b, domain_e); /* safe default in case EXPIRES field is garbled. */ cookie->expiry_time = cookies_now - 1; /* I don't like changing the line, but it's completely safe. (line is malloced.) */ *expires_e = '\0'; sscanf (expires_b, "%lu", &cookie->expiry_time); if (cookie->expiry_time < cookies_now) /* ignore stale cookie. */ goto abort; cookie->permanent = 1; store_cookie (cookie); next: continue; abort: delete_cookie (cookie); } fclose (fp); }