You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2008/04/04 18:02:31 UTC

svn commit: r644748 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_session_cookie.xml include/util_cookies.h modules/session/config.m4 modules/session/mod_session_cookie.c server/Makefile.in server/util_cookies.c

Author: minfrin
Date: Fri Apr  4 09:02:22 2008
New Revision: 644748

URL: http://svn.apache.org/viewvc?rev=644748&view=rev
Log:
mod_session_cookie: Add a session implementation capable of storing
session information within cookies on the browser. Useful for high
volume sites where server bound sessions are too resource intensive.

Added:
    httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml
    httpd/httpd/trunk/include/util_cookies.h
    httpd/httpd/trunk/modules/session/mod_session_cookie.c
    httpd/httpd/trunk/server/util_cookies.c
Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/modules/session/config.m4
    httpd/httpd/trunk/server/Makefile.in

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=644748&r1=644747&r2=644748&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Fri Apr  4 09:02:22 2008
@@ -2,6 +2,11 @@
 Changes with Apache 2.3.0
 [ When backported to 2.2.x, remove entry from this file ]
 
+  *) mod_session_cookie: Add a session implementation capable of storing
+     session information within cookies on the browser. Useful for high
+     volume sites where server bound sessions are too resource intensive.
+     [Graham Leggett]
+
   *) mod_session: Add a generic session interface to unify the different
      attempts at saving persistent sessions across requests.
      [Graham Leggett]

Added: httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml?rev=644748&view=auto
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml (added)
+++ httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml Fri Apr  4 09:02:22 2008
@@ -0,0 +1,156 @@
+<?xml version="1.0"?>
+<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
+<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
+<!-- $LastChangedRevision: 634760 $ -->
+
+<!--
+ 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
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ 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.
+-->
+
+<modulesynopsis metafile="mod_session_cookie.xml.meta">
+
+<name>mod_session_cookie</name>
+<description>Cookie based session support</description>
+<status>Extension</status>
+<sourcefile>mod_session_cookie.c</sourcefile>
+<identifier>session_cookie_module</identifier>
+
+<summary>
+    <note type="warning"><title>Warning</title>
+      <p>The session modules make use of HTTP cookies, and as such can fall
+      victim to Cross Site Scripting attacks, or expose potentially private
+      information to clients. Please ensure that the relevant risks have
+      been taken into account before enabling the session functionality on
+      your server.</p>
+    </note>
+
+    <p>This submodule of <module>mod_session</module> provides support for the
+    storage of user sessions on the remote browser within HTTP cookies.</p>
+    
+    <p>Using cookies to store a session removes the need for the server or
+    a group of servers to store the session locally, or collaborate to share
+    a session, and can be useful for high traffic environments where a
+    server based session might be too resource intensive.</p>
+    
+    <p>If session privacy is required, the <module>mod_session_crypto</module>
+    module can be used to encrypt the contents of the session before writing
+    the session to the client.</p>
+    
+    <p>For more details on the session interface, see the documentation for
+    the <module>mod_session</module> module.</p>
+    
+</summary>
+<seealso><module>mod_session</module></seealso>
+<seealso><module>mod_session_crypto</module></seealso>
+<seealso><module>mod_session_dbd</module></seealso>
+
+    <section id="basicexamples"><title>Basic Examples</title>
+    
+      <p>To create a simple session and store it in a cookie called
+      <var>session</var>, configure the session as follows:</p>
+      
+      <example><title>Browser based session</title>
+        Session On<br />
+        SessionCookieName session path=/<br />
+      </example>
+      
+      <p>For more examples on how the session can be configured to be read
+      from and written to by a CGI application, see the
+      <module>mod_session</module> examples section.</p>
+      
+      <p>For documentation on how the session can be used to store username
+      and password details, see the <module>mod_auth_form</module> module.</p>
+
+    </section>
+
+<directivesynopsis>
+<name>SessionCookieName</name>
+<description>Name and attributes for the RFC2109 cookie storing the session</description>
+<syntax>SessionCookieName <var>name</var> <var>attributes</var></syntax>
+<default>none</default>
+<contextlist><context>directory</context>
+</contextlist>
+<compatibility>Available in Apache 2.3.0 and later</compatibility>
+
+<usage>
+    <p>The <directive>SessionCookieName</directive> directive specifies the name and
+    optional attributes of an RFC2109 compliant cookie inside which the session will
+    be stored. RFC2109 cookies are set using the <code>Set-Cookie</code> HTTP header.
+    </p>
+    
+    <p>An optional list of cookie attributes can be specified, as per the example below.
+    These attributes are inserted into the cookie as is, and are not interpreted by
+    Apache. Ensure that your attributes are defined correctly as per the cookie specification.
+    </p>
+    
+    <example><title>Cookie with attributes</title>
+      Session On<br />
+      SessionCookieName session path=/private;domain=example.com;httponly;secure;version=1;<br />
+    </example>
+
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SessionCookieName2</name>
+<description>Name and attributes for the RFC2965 cookie storing the session</description>
+<syntax>SessionCookieName2 <var>name</var> <var>attributes</var></syntax>
+<default>none</default>
+<contextlist><context>directory</context>
+</contextlist>
+<compatibility>Available in Apache 2.3.0 and later</compatibility>
+
+<usage>
+    <p>The <directive>SessionCookieName2</directive> directive specifies the name and
+    optional attributes of an RFC2965 compliant cookie inside which the session will
+    be stored. RFC2965 cookies are set using the <code>Set-Cookie2</code> HTTP header.
+    </p>
+    
+    <p>An optional list of cookie attributes can be specified, as per the example below.
+    These attributes are inserted into the cookie as is, and are not interpreted by
+    Apache. Ensure that your attributes are defined correctly as per the cookie specification.
+    </p>
+    
+    <example><title>Cookie2 with attributes</title>
+      Session On<br />
+      SessionCookieName2 session path=/private;domain=example.com;httponly;secure;version=1;<br />
+    </example>
+
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SessionCookieRemove</name>
+<description>Control for whether session cookies should be removed from incoming HTTP headers</description>
+<syntax>SessionCookieRemove On|Off</syntax>
+<default>SessionCookieRemove Off</default>
+<contextlist><context>directory</context>
+</contextlist>
+<compatibility>Available in Apache 2.3.0 and later</compatibility>
+
+<usage>
+    <p>The <directive>SessionCookieRemove</directive> flag controls whether the cookies
+    containing the session will be removed from the headers during request processing.</p>
+    
+    <p>In a reverse proxy situation where the Apache server acts as a server frontend for
+    a backend origin server, revealing the contents of the session cookie to the backend
+    could be a potential privacy violation. When set to on, the session cookie will be
+    removed from the incoming HTTP headers.</p>
+
+</usage>
+</directivesynopsis>
+
+</modulesynopsis>

Added: httpd/httpd/trunk/include/util_cookies.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/util_cookies.h?rev=644748&view=auto
==============================================================================
--- httpd/httpd/trunk/include/util_cookies.h (added)
+++ httpd/httpd/trunk/include/util_cookies.h Fri Apr  4 09:02:22 2008
@@ -0,0 +1,120 @@
+/* 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+/**
+ * @file util_cookies.h
+ * @brief Apache cookie library
+ */
+
+#ifndef UTIL_COOKIES_H
+#define UTIL_COOKIES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup APACHE_CORE_COOKIE Cookies
+ * @ingroup  APACHE_CORE
+ *
+ * RFC2109 and RFC2965 compliant HTTP cookies can be read from and written
+ * to using this set of functions.
+ *
+ */
+
+#include "apr_errno.h"
+#include "httpd.h"
+
+#define SET_COOKIE "Set-Cookie"
+#define SET_COOKIE2 "Set-Cookie2"
+#define DEFAULT_ATTRS "HttpOnly;Secure;Version=1"
+#define CLEAR_ATTRS "Max-Age=0;Version=1"
+
+typedef struct {
+    request_rec *r;
+    const char *name;
+    const char *encoded;
+    apr_table_t *new_cookies;
+    int duplicated;
+} ap_cookie_do;
+
+/**
+ * Write an RFC2109 compliant cookie.
+ *
+ * @param r The request
+ * @param name The name of the cookie.
+ * @param val The value to place in the cookie.
+ * @param attrs The string containing additional cookie attributes. If NULL, the
+ *              DEFAULT_ATTRS will be used.
+ * @param maxage If non zero, a Max-Age header will be added to the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_write(request_rec * r, const char *name, const char *val,
+                                         const char *attrs, long maxage);
+
+/**
+ * Write an RFC2965 compliant cookie.
+ *
+ * @param r The request
+ * @param name2 The name of the cookie.
+ * @param val The value to place in the cookie.
+ * @param attrs2 The string containing additional cookie attributes. If NULL, the
+ *               DEFAULT_ATTRS will be used.
+ * @param maxage If non zero, a Max-Age header will be added to the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_write2(request_rec * r, const char *name2, const char *val,
+                                          const char *attrs2, long maxage);
+
+/**
+ * Remove an RFC2109 compliant cookie.
+ *
+ * @param r The request
+ * @param name The name of the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_remove(request_rec * r, const char *name);
+
+/**
+ * Remove an RFC2965 compliant cookie.
+ *
+ * @param r The request
+ * @param name2 The name of the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_remove2(request_rec * r, const char *name2);
+
+/**
+ * Read a cookie called name, placing its value in val.
+ *
+ * Both the Cookie and Cookie2 headers are scanned for the cookie.
+ *
+ * If the cookie is duplicated, this function returns APR_EGENERAL. If found,
+ * and if remove is non zero, the cookie will be removed from the headers, and
+ * thus kept private from the backend.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_read(request_rec * r, const char *name, const char **val,
+                                        int remove);
+
+/**
+ * Sanity check a given string that it exists, is not empty,
+ * and does not contain the special characters '=', ';' and '&'.
+ *
+ * It is used to sanity check the cookie names.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_check_string(const char *string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !UTIL_COOKIES_H */

Modified: httpd/httpd/trunk/modules/session/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/session/config.m4?rev=644748&r1=644747&r2=644748&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/session/config.m4 (original)
+++ httpd/httpd/trunk/modules/session/config.m4 Fri Apr  4 09:02:22 2008
@@ -10,7 +10,7 @@
 dnl various places, such as databases, LDAP, or cookies.
 dnl
 APACHE_MODULE(session, session module, , , most)
-dnl APACHE_MODULE(session_cookie, session cookie module, , , most)
+APACHE_MODULE(session_cookie, session cookie module, , , most)
 dnl APACHE_MODULE(session_crypto, session crypto module, , , most)
 dnl APACHE_MODULE(session_dbd, session dbd module, , , most)
 dnl APACHE_MODULE(session_ldap, session ldap module, , , most)

Added: httpd/httpd/trunk/modules/session/mod_session_cookie.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/session/mod_session_cookie.c?rev=644748&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/session/mod_session_cookie.c (added)
+++ httpd/httpd/trunk/modules/session/mod_session_cookie.c Fri Apr  4 09:02:22 2008
@@ -0,0 +1,269 @@
+/* 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_session.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "http_log.h"
+#include "util_cookies.h"
+
+#define LOG_PREFIX "mod_session_cookie: "
+#define MOD_SESSION_COOKIE "mod_session_cookie"
+
+module AP_MODULE_DECLARE_DATA session_cookie_module;
+
+/**
+ * Structure to carry the per-dir session config.
+ */
+typedef struct {
+    const char *name;
+    int name_set;
+    const char *name_attrs;
+    const char *name2;
+    int name2_set;
+    const char *name2_attrs;
+    int remove;
+    int remove_set;
+} session_cookie_dir_conf;
+
+/**
+ * Set the cookie and embed the session within it.
+ *
+ * This function adds an RFC2109 compliant Set-Cookie header for
+ * the cookie specified in SessionCookieName, and an RFC2965 compliant
+ * Set-Cookie2 header for the cookie specified in SessionCookieName2.
+ *
+ * If specified, the optional cookie attributes will be added to
+ * each cookie. If defaults are not specified, DEFAULT_ATTRS
+ * will be used.
+ *
+ * On success, this method will return APR_SUCCESS.
+ *
+ * @param r The request pointer.
+ * @param z A pointer to where the session will be written.
+ */
+AP_DECLARE(int) ap_session_cookie_save(request_rec * r, session_rec * z)
+{
+
+    session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
+                                                    &session_cookie_module);
+
+    /* don't cache auth protected pages */
+    apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
+
+    /* create RFC2109 compliant cookie */
+    if (conf->name_set) {
+        if (z->encoded && z->encoded[0]) {
+            ap_cookie_write(r, conf->name, z->encoded, conf->name_attrs, z->maxage);
+        }
+        else {
+            ap_cookie_remove(r, conf->name);
+        }
+    }
+
+    /* create RFC2965 compliant cookie */
+    if (conf->name2_set) {
+        if (z->encoded && z->encoded[0]) {
+            ap_cookie_write2(r, conf->name2, z->encoded, conf->name2_attrs, z->maxage);
+        }
+        else {
+            ap_cookie_remove2(r, conf->name2);
+        }
+    }
+
+    if (conf->name_set || conf->name2_set) {
+        return OK;
+    }
+    return DECLINED;
+
+}
+
+/**
+ * Isolate the cookie with the name "name", and if present, extract
+ * the payload from the cookie.
+ *
+ * If the cookie is found, the cookie and any other cookies with the
+ * same name are removed from the cookies passed in the request, so
+ * that credentials are not leaked to a backend server or process.
+ *
+ * A missing or malformed cookie will cause this function to return
+ * APR_EGENERAL.
+ *
+ * On success, this returns APR_SUCCESS.
+ */
+AP_DECLARE(int) ap_session_cookie_load(request_rec * r, session_rec ** z)
+{
+
+    session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
+                                                    &session_cookie_module);
+
+    session_rec *zz = NULL;
+    const char *val = NULL;
+    const char *note = NULL;
+    const char *name = NULL;
+    request_rec *m = r->main ? r->main : r;
+
+    /* is our session in a cookie? */
+    if (conf->name2_set) {
+        name = conf->name2;
+    }
+    else if (conf->name_set) {
+        name = conf->name;
+    }
+    else {
+        return DECLINED;
+    }
+
+    /* first look in the notes */
+    note = apr_pstrcat(r->pool, MOD_SESSION_COOKIE, name, NULL);
+    zz = (session_rec *)apr_table_get(m->notes, note);
+    if (zz) {
+        *z = zz;
+        return OK;
+    }
+
+    /* otherwise, try parse the cookie */
+    ap_cookie_read(r, name, &val, conf->remove);
+
+    /* create a new session and return it */
+    zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
+    zz->pool = r->pool;
+    zz->entries = apr_table_make(r->pool, 10);
+    zz->encoded = val;
+    zz->uuid = (apr_uuid_t *) apr_pcalloc(r->pool, sizeof(apr_uuid_t));
+    *z = zz;
+
+    /* put the session in the notes so we don't have to parse it again */
+    apr_table_setn(m->notes, note, (char *)zz);
+
+    return OK;
+
+}
+
+
+
+static void *create_session_cookie_dir_config(apr_pool_t * p, char *dummy)
+{
+    session_cookie_dir_conf *new =
+    (session_cookie_dir_conf *) apr_pcalloc(p, sizeof(session_cookie_dir_conf));
+
+    return (void *) new;
+}
+
+static void *merge_session_cookie_dir_config(apr_pool_t * p, void *basev, void *addv)
+{
+    session_cookie_dir_conf *new = (session_cookie_dir_conf *) apr_pcalloc(p, sizeof(session_cookie_dir_conf));
+    session_cookie_dir_conf *add = (session_cookie_dir_conf *) addv;
+    session_cookie_dir_conf *base = (session_cookie_dir_conf *) basev;
+
+    new->name = (add->name_set == 0) ? base->name : add->name;
+    new->name_attrs = (add->name_set == 0) ? base->name_attrs : add->name_attrs;
+    new->name_set = add->name_set || base->name_set;
+    new->name2 = (add->name2_set == 0) ? base->name2 : add->name2;
+    new->name2_attrs = (add->name2_set == 0) ? base->name2_attrs : add->name2_attrs;
+    new->name2_set = add->name2_set || base->name2_set;
+    new->remove = (add->remove_set == 0) ? base->remove : add->remove;
+    new->remove_set = add->remove_set || base->remove_set;
+
+    return new;
+}
+
+/**
+ * Sanity check a given string that it exists, is not empty,
+ * and does not contain special characters.
+ */
+static const char *check_string(cmd_parms * cmd, const char *string)
+{
+    if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) {
+        return apr_pstrcat(cmd->pool, cmd->directive->directive,
+                           " cannot be empty, or contain '=' or '&'.",
+                           NULL);
+    }
+    return NULL;
+}
+
+static const char *set_cookie_name(cmd_parms * cmd, void *config, const char *args)
+{
+    char *last;
+    char *line = apr_pstrdup(cmd->pool, args);
+    session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
+    char *cookie = apr_strtok(line, " \t", &last);
+    conf->name = cookie;
+    conf->name_set = 1;
+    while (apr_isspace(*last)) {
+        last++;
+    }
+    conf->name_attrs = last;
+    return check_string(cmd, cookie);
+}
+
+static const char *set_cookie_name2(cmd_parms * cmd, void *config, const char *args)
+{
+    char *last;
+    char *line = apr_pstrdup(cmd->pool, args);
+    session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
+    char *cookie = apr_strtok(line, " \t", &last);
+    conf->name2 = cookie;
+    conf->name2_set = 1;
+    while (apr_isspace(*last)) {
+        last++;
+    }
+    conf->name2_attrs = last;
+    return check_string(cmd, cookie);
+}
+
+static const char *
+     set_remove(cmd_parms * parms, void *dconf, int flag)
+{
+    session_cookie_dir_conf *conf = dconf;
+
+    conf->remove = flag;
+    conf->remove_set = 1;
+
+    return NULL;
+}
+
+static const command_rec session_cookie_cmds[] =
+{
+    AP_INIT_RAW_ARGS("SessionCookieName", set_cookie_name, NULL, OR_AUTHCFG,
+                     "The name of the RFC2109 cookie carrying the session"),
+    AP_INIT_RAW_ARGS("SessionCookieName2", set_cookie_name2, NULL, OR_AUTHCFG,
+                     "The name of the RFC2965 cookie carrying the session"),
+    AP_INIT_FLAG("SessionCookieRemove", set_remove, NULL, OR_AUTHCFG,
+                 "Set to 'On' to remove the session cookie from the headers "
+                 "and hide the cookie from a backend server or process"),
+    {NULL}
+};
+
+static void register_hooks(apr_pool_t * p)
+{
+    ap_hook_session_load(ap_session_cookie_load, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_session_save(ap_session_cookie_save, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA session_cookie_module =
+{
+    STANDARD20_MODULE_STUFF,
+    create_session_cookie_dir_config, /* dir config creater */
+    merge_session_cookie_dir_config,  /* dir merger --- default is to
+                                       * override */
+    NULL,                             /* server config */
+    NULL,                             /* merge server config */
+    session_cookie_cmds,              /* command apr_table_t */
+    register_hooks                    /* register hooks */
+};

Modified: httpd/httpd/trunk/server/Makefile.in
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/Makefile.in?rev=644748&r1=644747&r2=644748&view=diff
==============================================================================
--- httpd/httpd/trunk/server/Makefile.in (original)
+++ httpd/httpd/trunk/server/Makefile.in Fri Apr  4 09:02:22 2008
@@ -11,7 +11,7 @@
 	config.c log.c main.c vhost.c util.c \
 	util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \
 	connection.c listen.c util_mutex.c \
-	mpm_common.c util_charset.c util_debug.c util_xml.c \
+	mpm_common.c util_charset.c util_cookies.c util_debug.c util_xml.c \
 	util_expr.c util_filter.c util_pcre.c exports.c \
 	scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \
 	eoc_bucket.c eor_bucket.c core_filters.c

Added: httpd/httpd/trunk/server/util_cookies.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_cookies.c?rev=644748&view=auto
==============================================================================
--- httpd/httpd/trunk/server/util_cookies.c (added)
+++ httpd/httpd/trunk/server/util_cookies.c Fri Apr  4 09:02:22 2008
@@ -0,0 +1,256 @@
+/* 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#define CORE_PRIVATE
+
+#include "util_cookies.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "http_log.h"
+
+#define LOG_PREFIX "ap_cookie: "
+
+/**
+ * Write an RFC2109 compliant cookie.
+ *
+ * @param r The request
+ * @param name The name of the cookie.
+ * @param val The value to place in the cookie.
+ * @param attrs The string containing additional cookie attributes. If NULL, the
+ *              DEFAULT_ATTRS will be used.
+ * @param maxage If non zero, a Max-Age header will be added to the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_write(request_rec * r, const char *name, const char *val,
+                                         const char *attrs, long maxage)
+{
+
+    char *buffer;
+
+    /* handle expiry */
+    buffer = "";
+    if (maxage) {
+        buffer = apr_pstrcat(r->pool, "Max-Age=", apr_ltoa(r->pool, maxage), ";", NULL);
+    }
+
+    /* create RFC2109 compliant cookie */
+    char *rfc2109 = apr_pstrcat(r->pool, name, "=", val, ";",
+                                buffer,
+                                attrs && strlen(attrs) > 0 ?
+                                attrs : DEFAULT_ATTRS, NULL);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, LOG_PREFIX
+                  "user '%s' set cookie: '%s'", r->user, rfc2109);
+    apr_table_addn(r->headers_out, SET_COOKIE, rfc2109);
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * Write an RFC2965 compliant cookie.
+ *
+ * @param r The request
+ * @param name2 The name of the cookie.
+ * @param val The value to place in the cookie.
+ * @param attrs2 The string containing additional cookie attributes. If NULL, the
+ *               DEFAULT_ATTRS will be used.
+ * @param maxage If non zero, a Max-Age header will be added to the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_write2(request_rec * r, const char *name2, const char *val,
+                                          const char *attrs2, long maxage)
+{
+
+    char *buffer;
+
+    /* handle expiry */
+    buffer = "";
+    if (maxage) {
+        buffer = apr_pstrcat(r->pool, "Max-Age=", apr_ltoa(r->pool, maxage), ";");
+    }
+
+    /* create RFC2965 compliant cookie */
+    char *rfc2965 = apr_pstrcat(r->pool, name2, "=", val, ";",
+                                buffer,
+                                attrs2 && strlen(attrs2) > 0 ?
+                                attrs2 : DEFAULT_ATTRS, NULL);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, LOG_PREFIX
+                  "user '%s' set cookie2: '%s'", r->user, rfc2965);
+    apr_table_addn(r->headers_out, SET_COOKIE2, rfc2965);
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * Remove an RFC2109 compliant cookie.
+ *
+ * @param r The request
+ * @param name The name of the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_remove(request_rec * r, const char *name)
+{
+
+    /* create RFC2109 compliant cookie */
+    char *rfc2109 = apr_pstrcat(r->pool, name, "=;",
+                                CLEAR_ATTRS, NULL);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, LOG_PREFIX
+                  "user '%s' removed cookie: '%s'", r->user, rfc2109);
+    apr_table_addn(r->headers_out, SET_COOKIE, rfc2109);
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * Remove an RFC2965 compliant cookie.
+ *
+ * @param r The request
+ * @param name2 The name of the cookie.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_remove2(request_rec * r, const char *name2)
+{
+
+    /* create RFC2965 compliant cookie */
+    char *rfc2965 = apr_pstrcat(r->pool, name2, "=;",
+                                CLEAR_ATTRS, NULL);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, LOG_PREFIX
+                  "user '%s' removed cookie2: '%s'", r->user, rfc2965);
+    apr_table_addn(r->headers_out, SET_COOKIE2, rfc2965);
+
+    return APR_SUCCESS;
+
+}
+
+/* Iterate through the cookies, isolate our cookie and then remove it.
+ *
+ * If our cookie appears two or more times, but with different values,
+ * remove it twice and set the duplicated flag to true. Remove any
+ * $path or other attributes following our cookie if present. If we end
+ * up with an empty cookie, remove the whole header.
+ */
+static int extract_cookie_line(ap_cookie_do * v, const char *key, const char *val)
+{
+    char *last1, *last2;
+    char *cookie = apr_pstrdup(v->r->pool, val);
+    const char *name = apr_pstrcat(v->r->pool, v->name ? v->name : "", "=", NULL);
+    size_t len = strlen(name);
+    char *new_cookie = "";
+    const char *comma = ",";
+    char *next1;
+    const char *semi = ";";
+    char *next2;
+    const char *sep = "";
+    int cookies = 0;
+
+    /* find the cookie called name */
+    int eat = 0;
+    next1 = apr_strtok(cookie, comma, &last1);
+    while (next1) {
+        next2 = apr_strtok(next1, semi, &last2);
+        while (next2) {
+            char *trim = next2;
+            while (apr_isspace(*trim)) {
+                trim++;
+            }
+            if (!strncmp(trim, name, len)) {
+                if (v->encoded) {
+                    if (strcmp(v->encoded, trim + len)) {
+                        v->duplicated = 1;
+                    }
+                }
+                v->encoded = apr_pstrdup(v->r->pool, trim + len);
+                eat = 1;
+            }
+            else {
+                if (*trim != '$') {
+                    cookies++;
+                    eat = 0;
+                }
+                if (!eat) {
+                    new_cookie = apr_pstrcat(v->r->pool, new_cookie, sep, next2, NULL);
+                }
+            }
+            next2 = apr_strtok(NULL, semi, &last2);
+            sep = semi;
+        }
+
+        next1 = apr_strtok(NULL, comma, &last1);
+        sep = comma;
+    }
+
+    /* any cookies left over? */
+    if (cookies) {
+        apr_table_addn(v->new_cookies, key, new_cookie);
+    }
+
+    return 1;
+}
+
+/**
+ * Read a cookie called name, placing its value in val.
+ *
+ * Both the Cookie and Cookie2 headers are scanned for the cookie.
+ *
+ * If the cookie is duplicated, this function returns APR_EGENERAL. If found,
+ * and if remove is non zero, the cookie will be removed from the headers, and
+ * thus kept private from the backend.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_read(request_rec * r, const char *name, const char **val,
+                                        int remove)
+{
+
+    ap_cookie_do v;
+    v.r = r;
+    v.encoded = NULL;
+    v.new_cookies = apr_table_make(r->pool, 10);
+    v.duplicated = 0;
+    v.name = name;
+
+    apr_table_do((int (*) (void *, const char *, const char *))
+                 extract_cookie_line, (void *) &v, r->headers_in,
+                 "Cookie", "Cookie2", NULL);
+    if (v.duplicated) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, LOG_PREFIX
+         "client submitted cookie '%s' more than once: %s", v.name, r->uri);
+        return APR_EGENERAL;
+    }
+
+    /* remove our cookie(s), and replace them */
+    if (remove) {
+        apr_table_unset(r->headers_in, "Cookie");
+        apr_table_unset(r->headers_in, "Cookie2");
+        r->headers_in = apr_table_overlay(r->pool, r->headers_in, v.new_cookies);
+    }
+
+    *val = v.encoded;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * Sanity check a given string that it exists, is not empty,
+ * and does not contain the special characters '=', ';' and '&'.
+ *
+ * It is used to sanity check the cookie names.
+ */
+AP_DECLARE(apr_status_t) ap_cookie_check_string(const char *string)
+{
+    if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&') ||
+        ap_strchr_c(string, ';')) {
+        return APR_EGENERAL;
+    }
+    return APR_SUCCESS;
+}



Re: svn commit: r644748 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_session_cookie.xml include/util_cookies.h modules/session/config.m4 modules/session/mod_session_cookie.c server/Makefile.in server/util_cookies.c

Posted by Ruediger Pluem <rp...@apache.org>.

On 04/04/2008 06:02 PM, minfrin@apache.org wrote:
> Author: minfrin
> Date: Fri Apr  4 09:02:22 2008
> New Revision: 644748
> 
> URL: http://svn.apache.org/viewvc?rev=644748&view=rev
> Log:
> mod_session_cookie: Add a session implementation capable of storing
> session information within cookies on the browser. Useful for high
> volume sites where server bound sessions are too resource intensive.
> 
> Added:
>     httpd/httpd/trunk/docs/manual/mod/mod_session_cookie.xml
>     httpd/httpd/trunk/include/util_cookies.h
>     httpd/httpd/trunk/modules/session/mod_session_cookie.c
>     httpd/httpd/trunk/server/util_cookies.c
> Modified:
>     httpd/httpd/trunk/CHANGES
>     httpd/httpd/trunk/modules/session/config.m4
>     httpd/httpd/trunk/server/Makefile.in
> 

> Added: httpd/httpd/trunk/modules/session/mod_session_cookie.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/session/mod_session_cookie.c?rev=644748&view=auto
> ==============================================================================
> --- httpd/httpd/trunk/modules/session/mod_session_cookie.c (added)
> +++ httpd/httpd/trunk/modules/session/mod_session_cookie.c Fri Apr  4 09:02:22 2008


> +/**
> + * Sanity check a given string that it exists, is not empty,
> + * and does not contain special characters.
> + */
> +static const char *check_string(cmd_parms * cmd, const char *string)
> +{
> +    if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) {
> +        return apr_pstrcat(cmd->pool, cmd->directive->directive,
> +                           " cannot be empty, or contain '=' or '&'.",
> +                           NULL);
> +    }
> +    return NULL;
> +}

Why don't we use ap_cookie_check_string?

> +
> +static const char *set_cookie_name(cmd_parms * cmd, void *config, const char *args)
> +{
> +    char *last;
> +    char *line = apr_pstrdup(cmd->pool, args);
> +    session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
> +    char *cookie = apr_strtok(line, " \t", &last);
> +    conf->name = cookie;

Don't we need to trim trailing spaces from the cookie name?


> +    conf->name_set = 1;
> +    while (apr_isspace(*last)) {
> +        last++;
> +    }
> +    conf->name_attrs = last;
> +    return check_string(cmd, cookie);
> +}
> +
> +static const char *set_cookie_name2(cmd_parms * cmd, void *config, const char *args)
> +{
> +    char *last;
> +    char *line = apr_pstrdup(cmd->pool, args);
> +    session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
> +    char *cookie = apr_strtok(line, " \t", &last);
> +    conf->name2 = cookie;

Don't we need to trim trailing spaces from the cookie name?

> +    conf->name2_set = 1;
> +    while (apr_isspace(*last)) {
> +        last++;
> +    }
> +    conf->name2_attrs = last;
> +    return check_string(cmd, cookie);
> +}
> +

Regards

RĂ¼diger