blob: 1f53875194305126abfcacca85679989171caba7 [file] [log] [blame]
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
#include "apache_cookie.h"
char *ApacheCookie_expires(ApacheCookie *c, char *time_str)
{
char *expires;
expires = ApacheUtil_expires(c->r->pool, time_str, EXPIRES_COOKIE);
if (expires) {
c->expires = expires;
}
return c->expires;
}
#define cookie_get_set(thing,val) \
retval = thing; \
if(val) thing = ap_pstrdup(c->r->pool, val)
char *ApacheCookie_attr(ApacheCookie *c, char *key, char *val)
{
char *retval = NULL;
int ix = key[0] == '-' ? 1 : 0;
switch (key[ix]) {
case 'n':
cookie_get_set(c->name, val);
break;
case 'v':
ApacheCookieAdd(c, val);
break;
case 'e':
retval = ApacheCookie_expires(c, val);
break;
case 'd':
cookie_get_set(c->domain, val);
break;
case 'p':
cookie_get_set(c->path, val);
break;
case 's':
if(val) {
c->secure =
!strcaseEQ(val, "off") &&
!strcaseEQ(val, "0");
}
retval = c->secure ? "on" : "";
break;
default:
ap_log_rerror(APC_ERROR,
"[libapreq] unknown cookie pair: `%s' => `%s'", key, val);
};
return retval;
}
ApacheCookie *ApacheCookie_new(request_rec *r, ...)
{
va_list args;
ApacheRequest req;
ApacheCookie *c =
ap_pcalloc(r->pool, sizeof(ApacheCookie));
req.r = r;
c->r = r;
c->values = ap_make_array(r->pool, 1, sizeof(char *));
c->secure = 0;
c->name = c->expires = NULL;
c->domain = NULL;
c->path = ApacheRequest_script_path(&req);
va_start(args, r);
for(;;) {
char *key, *val;
key = va_arg(args, char *);
if (key == NULL) {
break;
}
val = va_arg(args, char *);
(void)ApacheCookie_attr(c, key, val);
}
va_end(args);
return c;
}
ApacheCookieJar *ApacheCookie_parse(request_rec *r, const char *data)
{
const char *pair;
ApacheCookieJar *retval =
ap_make_array(r->pool, 1, sizeof(ApacheCookie *));
if (!data) {
if (!(data = ap_table_get(r->headers_in, "Cookie"))) {
return retval;
}
}
while (*data && (pair = ap_getword(r->pool, &data, ';'))) {
const char *key, *val;
ApacheCookie *c;
while (ap_isspace(*data)) {
++data;
}
key = ap_getword(r->pool, &pair, '=');
ap_unescape_url((char *)key);
c = ApacheCookie_new(r, "-name", key, NULL);
if (c->values) {
c->values->nelts = 0;
}
else {
c->values = ap_make_array(r->pool, 4, sizeof(char *));
}
if (!*pair) {
ApacheCookieAdd(c, "");
}
while (*pair && (val = ap_getword(r->pool, &pair, '&'))) {
ap_unescape_url((char *)val);
ApacheCookieAdd(c, val);
}
ApacheCookieJarAdd(retval, c);
}
return retval;
}
#define cookie_push_arr(arr, val) \
*(char **)ap_push_array(arr) = (char *)val
#define cookie_push_named(arr, name, val) \
if(val) { \
cookie_push_arr(arr, ap_pstrcat(p, name, "=", val, NULL)); \
}
static char * escape_url(pool *p, char *val)
{
char *result = ap_os_escape_path(p, val?val:"", 1);
char *end = result + strlen(result);
char *seek;
for ( seek = end-1; seek >= result; --seek) {
char *ptr, *replacement;
switch (*seek) {
case '&':
replacement = "%26";
break;
case '=':
replacement = "%3d";
break;
/* additional cases here */
default:
continue; /* next for() */
}
for (ptr = end; ptr > seek; --ptr) {
ptr[2] = ptr[0];
}
strncpy(seek, replacement, 3);
end += 2;
}
return(result);
}
char *ApacheCookie_as_string(ApacheCookie *c)
{
array_header *values;
pool *p = c->r->pool;
char *cookie, *retval;
int i;
if (!c->name) {
return "";
}
values = ap_make_array(p, 6, sizeof(char *));
cookie_push_named(values, "domain", c->domain);
cookie_push_named(values, "path", c->path);
cookie_push_named(values, "expires", c->expires);
if (c->secure) {
cookie_push_arr(values, "secure");
}
cookie = ap_pstrcat(p, escape_url(p, c->name), "=", NULL);
for (i=0; i<c->values->nelts; i++) {
cookie = ap_pstrcat(p, cookie,
escape_url(p, ((char**)c->values->elts)[i]),
(i < (c->values->nelts-1) ? "&" : NULL),
NULL);
}
retval = cookie;
for (i=0; i<values->nelts; i++) {
retval = ap_pstrcat(p, retval, "; ",
((char**)values->elts)[i], NULL);
}
return retval;
}
void ApacheCookie_bake(ApacheCookie *c)
{
ap_table_add(c->r->err_headers_out, "Set-Cookie",
ApacheCookie_as_string(c));
}