static void rfc_cookie(dAT) { apreq_cookie_t *c = apreq_cookie_make(p,"rfc",3,"out",3); const char *expected; long expires; AT_str_eq(c->v.data, "out"); apreq_cookie_version_set(c, 1); AT_int_eq(apreq_cookie_version(c), 1); AT_str_eq(apreq_cookie_as_string(c,p),"rfc=out; Version=1"); c->domain = apr_pstrdup(p, "example.com"); #ifndef WIN32 AT_str_eq(apreq_cookie_as_string(c,p), "rfc=out; Version=1; domain=\"example.com\""); c->path = apr_pstrdup(p, "/quux"); AT_str_eq(apreq_cookie_as_string(c,p), "rfc=out; Version=1; path=\"/quux\"; domain=\"example.com\""); apreq_cookie_expires(c, "+3m"); expires = apreq_atoi64t("+3m"); expected = apr_psprintf(p, "rfc=out; Version=1; path=\"/quux\"; " "domain=\"example.com\"; max-age=%ld", expires); AT_str_eq(apreq_cookie_as_string(c,p), expected); #else expected = "rfc=out; Version=1; domain=\"example.com\""; AT_str_eq(apreq_cookie_as_string(c,p), expected); c->path = apr_pstrdup(p, "/quux"); expected = "rfc=out; Version=1; path=\"/quux\"; domain=\"example.com\""; AT_str_eq(apreq_cookie_as_string(c,p), expected); apreq_cookie_expires(c, "+3m"); expires = apreq_atoi64t("+3m"); expected = apr_psprintf(p, "rfc=out; Version=1; path=\"/quux\"; " "domain=\"example.com\"; max-age=%ld", expires); AT_str_eq(apreq_cookie_as_string(c,p), expected); #endif }
static apr_status_t apreq_cookie_attr(apr_pool_t *p, apreq_cookie_t *c, const char *attr, apr_size_t alen, const char *val, apr_size_t vlen) { if (alen < 2) return APR_EBADARG; if ( attr[0] == '-' || attr[0] == '$' ) { ++attr; --alen; } switch (apr_tolower(*attr)) { case 'n': /* name is not an attr */ return APR_ENOTIMPL; case 'v': /* version; value is not an attr */ if (alen == 5 && strncasecmp(attr,"value", 5) == 0) return APR_ENOTIMPL; while (!apr_isdigit(*val)) { if (vlen == 0) return APREQ_ERROR_BADSEQ; ++val; --vlen; } apreq_cookie_version_set(c, *val - '0'); return APR_SUCCESS; case 'e': case 'm': /* expires, max-age */ apreq_cookie_expires(c, val); return APR_SUCCESS; case 'd': c->domain = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; case 'p': if (alen != 4) break; if (!strncasecmp("port", attr, 4)) { c->port = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } else if (!strncasecmp("path", attr, 4)) { c->path = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } break; case 'c': if (!strncasecmp("commentURL", attr, 10)) { c->commentURL = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } else if (!strncasecmp("comment", attr, 7)) { c->comment = apr_pstrmemdup(p,val,vlen); return APR_SUCCESS; } break; case 's': if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen)) apreq_cookie_secure_on(c); else apreq_cookie_secure_off(c); return APR_SUCCESS; case 'h': /* httponly */ if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen)) apreq_cookie_httponly_on(c); else apreq_cookie_httponly_off(c); return APR_SUCCESS; }; return APR_ENOTIMPL; }
APREQ_DECLARE(apr_status_t)apreq_parse_cookie_header(apr_pool_t *p, apr_table_t *j, const char *hdr) { apreq_cookie_t *c; unsigned version; apr_status_t rv = APR_SUCCESS; parse_cookie_header: c = NULL; version = NETSCAPE; while (apr_isspace(*hdr)) ++hdr; if (*hdr == '$' && strncasecmp(hdr, "$Version", 8) == 0) { /* XXX cheat: assume "$Version" => RFC Cookie header */ version = RFC; skip_version_string: switch (*hdr++) { case 0: return rv; case ',': goto parse_cookie_header; case ';': break; default: goto skip_version_string; } } for (;;) { apr_status_t status; const char *name, *value; apr_size_t nlen = 0, vlen; while (*hdr == ';' || apr_isspace(*hdr)) ++hdr; switch (*hdr) { case 0: /* this is the normal exit point */ if (c != NULL) { ADD_COOKIE(j, c); } return rv; case ',': ++hdr; if (c != NULL) { ADD_COOKIE(j, c); } goto parse_cookie_header; case '$': ++hdr; if (c == NULL) { rv = APREQ_ERROR_BADCHAR; goto parse_cookie_error; } else if (version == NETSCAPE) { rv = APREQ_ERROR_MISMATCH; } status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 1); if (status != APR_SUCCESS) { rv = status; goto parse_cookie_error; } status = apreq_cookie_attr(p, c, name, nlen, value, vlen); switch (status) { case APR_ENOTIMPL: rv = APREQ_ERROR_BADATTR; /* fall thru */ case APR_SUCCESS: break; default: rv = status; goto parse_cookie_error; } break; default: if (c != NULL) { ADD_COOKIE(j, c); } status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 0); if (status != APR_SUCCESS) { c = NULL; rv = status; goto parse_cookie_error; } c = apreq_cookie_make(p, name, nlen, value, vlen); apreq_cookie_tainted_on(c); if (version != NETSCAPE) apreq_cookie_version_set(c, version); } } parse_cookie_error: switch (*hdr) { case 0: return rv; case ',': case ';': if (c != NULL) ADD_COOKIE(j, c); ++hdr; goto parse_cookie_header; default: ++hdr; goto parse_cookie_error; } /* not reached */ return rv; }