apreq_cookie.c revision 6ac28b74a504006c016d4df3fb84d2cd2e373942
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_cookie.h"
#include "apreq_error.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_date.h"
#define RFC 1
#define NETSCAPE 0
#define ADD_COOKIE(j,c) apreq_value_table_add(&c->v, j)
const char *time_str)
{
c->max_age = -1;
return;
}
c->max_age = 0;
else {
if (c->max_age == APR_DATE_BAD)
else
c->max_age -= apr_time_now();
}
}
apreq_cookie_t *c,
const char *attr,
const char *val,
{
if (alen < 2)
return APR_EBADARG;
++attr;
--alen;
}
switch (apr_tolower(*attr)) {
case 'n': /* name is not an attr */
return APR_ENOTIMPL;
case 'v': /* version; value is not an attr */
return APR_ENOTIMPL;
while (!apr_isdigit(*val)) {
if (vlen == 0)
return APREQ_ERROR_BADSEQ;
++val;
--vlen;
}
return APR_SUCCESS;
case 'e': case 'm': /* expires, max-age */
apreq_cookie_expires(c, val);
return APR_SUCCESS;
case 'd':
return APR_SUCCESS;
case 'p':
if (alen != 4)
break;
return APR_SUCCESS;
}
return APR_SUCCESS;
}
break;
case 'c':
return APR_SUCCESS;
}
return APR_SUCCESS;
}
break;
case 's':
else
return APR_SUCCESS;
case 'h': /* httponly */
else
return APR_SUCCESS;
};
return APR_ENOTIMPL;
}
const char *name,
const apr_size_t nlen,
const char *value,
const apr_size_t vlen)
{
apreq_cookie_t *c;
apreq_value_t *v;
if (c == NULL)
return NULL;
*(const apreq_value_t **)&v = &c->v;
c->commentURL = NULL;
c->flags = 0;
return c;
}
static APR_INLINE
const char **n, apr_size_t *nlen,
{
int nlen_set = 0;
++hdr;
*n = hdr;
switch (*hdr) {
case 0:
case ';':
case ',':
if (!nlen_set)
*v = hdr;
*vlen = 0;
case '=':
if (!nlen_set) {
nlen_set = 1;
}
break;
case ' ':
case '\t':
case '\r':
case '\n':
if (!nlen_set) {
nlen_set = 1;
}
/* fall thru */
default:
++hdr;
goto scan_name;
}
while (apr_isspace(*val))
++val;
if (*val == '"') {
unsigned saw_backslash = 0;
switch (*val) {
case '"':
if (!unquote) {
}
else if (!saw_backslash) {
}
else {
const char *s = *v;
while (s < val) {
if (*s == '\\')
++s;
*d++ = *s++;
}
*v = dest;
}
return APR_SUCCESS;
case '\\':
saw_backslash = 1;
if (val[1] != 0)
++val;
default:
break;
}
}
/* bad sequence: no terminating quote found */
return APREQ_ERROR_BADSEQ;
}
else {
/* value is not wrapped in quotes */
switch (*val) {
case ';':
case ',':
case ' ':
case '\t':
case '\r':
case '\n':
return APR_SUCCESS;
default:
break;
}
}
}
return APR_SUCCESS;
}
apr_table_t *j,
const char *hdr)
{
apreq_cookie_t *c;
unsigned version;
c = NULL;
while (apr_isspace(*hdr))
++hdr;
/* XXX cheat: assume "$Version" => RFC Cookie header */
switch (*hdr++) {
case 0:
return rv;
case ',':
goto parse_cookie_header;
case ';':
break;
default:
goto skip_version_string;
}
}
for (;;) {
++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) {
goto parse_cookie_error;
}
}
if (status != APR_SUCCESS) {
goto parse_cookie_error;
}
switch (status) {
case APR_ENOTIMPL:
/* fall thru */
case APR_SUCCESS:
break;
default:
goto parse_cookie_error;
}
break;
default:
if (c != NULL) {
ADD_COOKIE(j, c);
}
if (status != APR_SUCCESS) {
c = NULL;
goto 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;
}
{
/* The format string must be large enough to accomodate all
* of the cookie attributes. The current attributes sum to
* ~90 characters (w/ 6-8 padding chars per attr), so anything
* over 100 should be fine.
*/
unsigned version = apreq_cookie_version(c);
/* XXX protocol enforcement (for debugging, anyway) ??? */
return -1;
char expires[APR_RFC822_DATE_LEN] = {0};
#define ADD_NS_ATTR(name) do { \
else \
strcpy(f, "%0.s"); \
f += strlen(f); \
} while (0)
if (c->max_age != -1) {
strcpy(f, "; expires=%s");
}
else
strcpy(f, "");
f += strlen(f);
if (apreq_cookie_is_secure(c))
strcpy(f, "; secure");
f += strlen(f);
if (apreq_cookie_is_httponly(c))
strcpy(f, "; HttpOnly");
}
/* c->version == RFC */
strcpy(f,"; Version=%u");
f += strlen(f);
/* ensure RFC attributes are always quoted */
#define ADD_RFC_ATTR(name) do { \
if (*c->name == '"') \
else \
else \
strcpy(f, "%0.s"); \
f += strlen (f); \
} while (0)
f += strlen(f);
if (apreq_cookie_is_secure(c))
strcpy(f, "; secure");
f += strlen(f);
if (apreq_cookie_is_httponly(c))
strcpy(f, "; HttpOnly");
}
apr_pool_t *p)
{
int n = apreq_cookie_serialize(c, NULL, 0);
char *s = apr_palloc(p, n + 1);
apreq_cookie_serialize(c, s, n + 1);
return s;
}