+/** @brief Parse a RFC2109 Cookie: header
+ * @param s Header field value
+ * @param cd Where to store result
+ * @return 0 on success, non-0 on error
+ */
+int parse_cookie(const char *s,
+ struct cookiedata *cd) {
+ char *n = 0, *v = 0;
+
+ memset(cd, 0, sizeof *cd);
+ s = skipwhite(s, 0);
+ while(*s) {
+ /* Skip separators */
+ if(*s == ';' || *s == ',') {
+ ++s;
+ s = skipwhite(s, 0);
+ continue;
+ }
+ if(!(s = parsetoken(s, &n, http_separator))) return -1;
+ s = skipwhite(s, 0);
+ if(*s++ != '=') return -1;
+ s = skipwhite(s, 0);
+ if(!(s = parseword(s, &v, http_separator))) return -1;
+ if(n[0] == '$') {
+ /* Some bit of meta-information */
+ if(!strcmp(n, "$Version"))
+ cd->version = v;
+ else if(!strcmp(n, "$Path")) {
+ if(cd->ncookies > 0 && cd->cookies[cd->ncookies-1].path == 0)
+ cd->cookies[cd->ncookies-1].path = v;
+ else {
+ error(0, "redundant $Path in Cookie: header");
+ return -1;
+ }
+ } else if(!strcmp(n, "$Domain")) {
+ if(cd->ncookies > 0 && cd->cookies[cd->ncookies-1].domain == 0)
+ cd->cookies[cd->ncookies-1].domain = v;
+ else {
+ error(0, "redundant $Domain in Cookie: header");
+ return -1;
+ }
+ }
+ } else {
+ /* It's a new cookie */
+ cd->cookies = xrealloc(cd->cookies,
+ (cd->ncookies + 1) * sizeof (struct cookie));
+ cd->cookies[cd->ncookies].name = n;
+ cd->cookies[cd->ncookies].value = v;
+ cd->cookies[cd->ncookies].path = 0;
+ cd->cookies[cd->ncookies].domain = 0;
+ ++cd->ncookies;
+ }
+ s = skipwhite(s, 0);
+ if(*s && (*s != ',' && *s != ';')) {
+ error(0, "missing separator in Cookie: header");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** @brief Find a named cookie
+ * @param cd Parse cookie data
+ * @param name Name of cookie
+ * @return Cookie structure or NULL if not found
+ */
+const struct cookie *find_cookie(const struct cookiedata *cd,
+ const char *name) {
+ int n;
+
+ for(n = 0; n < cd->ncookies; ++n)
+ if(!strcmp(cd->cookies[n].name, name))
+ return &cd->cookies[n];
+ return 0;
+}
+