]> granicus.if.org Git - apache/commitdiff
No var declarations in the middle of the code.
authorGuenter Knauf <fuankg@apache.org>
Tue, 8 Apr 2008 12:32:50 +0000 (12:32 +0000)
committerGuenter Knauf <fuankg@apache.org>
Tue, 8 Apr 2008 12:32:50 +0000 (12:32 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@645877 13f79535-47bb-0310-9956-ffa450edef68

modules/session/mod_session.c

index 46439925924530f0698d514efadb8aadc63d7a90..4e377778b4816df70e85ae7647654938607d6eb6 100644 (file)
-/* 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.
- */
-
-#include "mod_session.h"
-#include "apr_lib.h"
-#include "apr_strings.h"
-#include "util_filter.h"
-#include "http_log.h"
-#include "http_request.h"
-#include "http_protocol.h"
-
-#define SESSION_PREFIX "mod_session: "
-#define SESSION_EXPIRY "expiry"
-#define HTTP_SESSION "HTTP_SESSION"
-
-APR_HOOK_STRUCT(
-                APR_HOOK_LINK(session_load)
-                APR_HOOK_LINK(session_save)
-                APR_HOOK_LINK(session_encode)
-                APR_HOOK_LINK(session_decode)
-)
-AP_IMPLEMENT_HOOK_RUN_FIRST(int, session_load,
-                      (request_rec * r, session_rec ** z), (r, z), DECLINED)
-AP_IMPLEMENT_HOOK_RUN_FIRST(int, session_save,
-                       (request_rec * r, session_rec * z), (r, z), DECLINED)
-AP_IMPLEMENT_HOOK_RUN_ALL(int, session_encode,
-                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
-AP_IMPLEMENT_HOOK_RUN_ALL(int, session_decode,
-                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
-/**
- * Should the session be included within this URL.
- *
- * This function tests whether a session is valid for this URL. It uses the
- * include and exclude arrays to determine whether they should be included.
- */
-    static int session_included(request_rec * r, session_dir_conf * conf)
-{
-
-    const char **includes = (const char **) conf->includes->elts;
-    const char **excludes = (const char **) conf->excludes->elts;
-    int included = 1;                /* defaults to included */
-    int i;
-
-    if (conf->includes->nelts) {
-        included = 0;
-        for (i = 0; !included && i < conf->includes->nelts; i++) {
-            const char *include = includes[i];
-            if (strncmp(r->parsed_uri.path, include, strlen(include))) {
-                included = 1;
-            }
-        }
-    }
-
-    if (conf->excludes->nelts) {
-        for (i = 0; included && i < conf->includes->nelts; i++) {
-            const char *exclude = excludes[i];
-            if (strncmp(r->parsed_uri.path, exclude, strlen(exclude))) {
-                included = 0;
-            }
-        }
-    }
-
-    return included;
-}
-
-/**
- * Get a particular value from the session.
- * @param r The current request.
- * @param z The current session. If this value is NULL, the session will be
- * looked up in the request, created if necessary, and saved to the request
- * notes.
- * @param key The key to get.
- * @param value The buffer to write the value to.
- */
-AP_DECLARE(void) ap_session_get(request_rec * r, session_rec * z, const char *key, const char **value)
-{
-    if (!z) {
-        ap_session_load(r, &z);
-    }
-    if (z) {
-        *value = apr_table_get(z->entries, key);
-    }
-}
-
-/**
- * Set a particular value to the session.
- *
- * Using this method ensures that the dirty flag is set correctly, so that
- * the session can be saved efficiently.
- * @param r The current request.
- * @param z The current session. If this value is NULL, the session will be
- * looked up in the request, created if necessary, and saved to the request
- * notes.
- * @param key The key to set. The existing key value will be replaced.
- * @param value The value to set.
- */
-AP_DECLARE(void) ap_session_set(request_rec * r, session_rec * z,
-                                const char *key, const char *value)
-{
-    if (!z) {
-        ap_session_load(r, &z);
-    }
-    if (z) {
-        if (value) {
-            apr_table_set(z->entries, key, value);
-        }
-        else {
-            apr_table_unset(z->entries, key);
-        }
-        z->dirty = 1;
-    }
-}
-
-/**
- * Load the session.
- *
- * If the session doesn't exist, a blank one will be created.
- *
- * @param r The request
- * @param z A pointer to where the session will be written.
- */
-AP_DECLARE(int) ap_session_load(request_rec * r, session_rec ** z)
-{
-
-    session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
-                                                   &session_module);
-    apr_time_t now;
-    session_rec *zz = NULL;
-
-    /* is the session enabled? */
-    if (!dconf->enabled) {
-        return APR_SUCCESS;
-    }
-
-    /* should the session be loaded at all? */
-    if (!session_included(r, dconf)) {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, SESSION_PREFIX
-                      "excluded by configuration for: %s", r->uri);
-        return APR_SUCCESS;
-    }
-
-    /* load the session from the session hook */
-    int rv = ap_run_session_load(r, &zz);
-    if (DECLINED == rv) {
-        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
-                      "session is enabled but no session modules have been configured, "
-                      "session not loaded: %s", r->uri);
-        return APR_EGENERAL;
-    }
-    else if (OK != rv) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
-                      "error while loading the session, "
-                      "session not loaded: %s", r->uri);
-        return rv;
-    }
-
-    /* found a session that hasn't expired? */
-    now = apr_time_now();
-    if (!zz || (zz->expiry && zz->expiry < now)) {
-
-        /* no luck, create a blank session */
-        zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
-        zz->pool = r->pool;
-        zz->entries = apr_table_make(zz->pool, 10);
-        zz->uuid = (apr_uuid_t *) apr_pcalloc(zz->pool, sizeof(apr_uuid_t));
-        apr_uuid_get(zz->uuid);
-
-    }
-    else {
-        rv = ap_run_session_decode(r, zz);
-        if (OK != rv) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
-                          "error while decoding the session, "
-                          "session not loaded: %s", r->uri);
-            return rv;
-        }
-    }
-
-    /* make sure the expiry is set, if present */
-    if (!zz->expiry && dconf->maxage) {
-        zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
-        zz->maxage = dconf->maxage;
-    }
-
-    *z = zz;
-
-    return APR_SUCCESS;
-
-}
-
-/**
- * Save the session.
- *
- * In most implementations the session is only saved if the dirty flag is
- * true. This prevents the session being saved unnecessarily.
- *
- * @param r The request
- * @param z A pointer to where the session will be written.
- */
-AP_DECLARE(int) ap_session_save(request_rec * r, session_rec * z)
-{
-    if (z) {
-        apr_time_t now = apr_time_now();
-        int rv = 0;
-
-        /* sanity checks, should we try save at all? */
-        if (z->written) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, SESSION_PREFIX
-                          "attempt made to save the session twice, "
-                          "session not saved: %s", r->uri);
-            return APR_EGENERAL;
-        }
-        if (z->expiry && z->expiry < now) {
-            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
-                          "attempt made to save a session when the session had already expired, "
-                          "session not saved: %s", r->uri);
-            return APR_EGENERAL;
-        }
-
-        /* encode the session */
-        rv = ap_run_session_encode(r, z);
-        if (OK != rv) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
-                          "error while encoding the session, "
-                          "session not saved: %s", r->uri);
-            return rv;
-        }
-
-        /* try the save */
-        rv = ap_run_session_save(r, z);
-        if (DECLINED == rv) {
-            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
-                          "session is enabled but no session modules have been configured, "
-                          "session not saved: %s", r->uri);
-            return APR_EGENERAL;
-        }
-        else if (OK != rv) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
-                          "error while saving the session, "
-                          "session not saved: %s", r->uri);
-            return rv;
-        }
-        else {
-            z->written = 1;
-        }
-    }
-
-    return APR_SUCCESS;
-
-}
-
-static int identity_count(int *count, const char *key, const char *val)
-{
-    *count += strlen(key) * 3 + strlen(val) * 3 + 1;
-    return 1;
-}
-
-static int identity_concat(char *buffer, const char *key, const char *val)
-{
-    char *slider = buffer;
-    int length = strlen(slider);
-    slider += length;
-    if (length) {
-        *slider = '&';
-        slider++;
-    }
-    ap_escape_path_segment_buffer(slider, key);
-    slider += strlen(slider);
-    *slider = '=';
-    slider++;
-    ap_escape_path_segment_buffer(slider, val);
-    return 1;
-}
-
-/**
- * Default identity encoding for the session.
- *
- * By default, the name value pairs in the session are URLEncoded, separated
- * by equals, and then in turn separated by ampersand, in the format of an
- * html form.
- *
- * This was chosen to make it easy for external code to unpack a session,
- * should there be a need to do so.
- *
- * @param r The request pointer.
- * @param z A pointer to where the session will be written.
- */
-AP_DECLARE(int) ap_session_identity_encode(request_rec * r, session_rec * z)
-{
-
-    char *buffer = NULL;
-    int length = 0;
-    if (z->expiry) {
-        char *expiry = apr_psprintf(r->pool, "%" APR_INT64_T_FMT, z->expiry);
-        apr_table_set(z->entries, SESSION_EXPIRY, expiry);
-    }
-    apr_table_do((int (*) (void *, const char *, const char *))
-                 identity_count, &length, z->entries, NULL);;
-    buffer = apr_pcalloc(r->pool, length + 1);
-    apr_table_do((int (*) (void *, const char *, const char *))
-                 identity_concat, buffer, z->entries, NULL);
-    z->encoded = buffer;
-    return OK;
-
-}
-
-/**
- * Default identity decoding for the session.
- *
- * By default, the name value pairs in the session are URLEncoded, separated
- * by equals, and then in turn separated by ampersand, in the format of an
- * html form.
- *
- * This was chosen to make it easy for external code to unpack a session,
- * should there be a need to do so.
- *
- * This function reverses that process, and populates the session table.
- *
- * Name / value pairs that are not encoded properly are ignored.
- *
- * @param r The request pointer.
- * @param z A pointer to where the session will be written.
- */
-AP_DECLARE(int) ap_session_identity_decode(request_rec * r, session_rec * z)
-{
-
-    char *last = NULL;
-    char *encoded, *pair;
-    const char *sep = "&";
-
-    /* sanity check - anything to decode? */
-    if (!z->encoded) {
-        return OK;
-    }
-
-    /* decode what we have */
-    encoded = apr_pstrcat(r->pool, z->encoded, NULL);
-    pair = apr_strtok(encoded, sep, &last);
-    while (pair && pair[0]) {
-        char *plast = NULL;
-        const char *psep = "=";
-        char *key = apr_strtok(pair, psep, &plast);
-        char *val = apr_strtok(NULL, psep, &plast);
-        if (key && *key) {
-            if (!val || !*val) {
-                apr_table_unset(z->entries, key);
-            }
-            if (!ap_unescape_all(key) && !ap_unescape_all(val)) {
-                if (!strcmp(SESSION_EXPIRY, key)) {
-                    z->expiry = (apr_time_t) apr_atoi64(val);
-                }
-                else {
-                    apr_table_set(z->entries, key, val);
-                }
-            }
-        }
-        pair = apr_strtok(NULL, sep, &last);
-    }
-    z->encoded = NULL;
-    return OK;
-
-}
-
-/**
- * Ensure any changes to the session are committed.
- *
- * This is done in an output filter so that our options for where to
- * store the session can include storing the session within a cookie:
- * As an HTTP header, the cookie must be set before the output is
- * written, but after the handler is run.
- *
- * NOTE: It is possible for internal redirects to cause more than one
- * request to be present, and each request might have a session
- * defined. We need to go through each session in turn, and save each
- * one.
- * 
- * The same session might appear in more than one request. The first
- * attempt to save the session will be called
- */
-static apr_status_t ap_session_output_filter(ap_filter_t * f,
-                                                    apr_bucket_brigade * in)
-{
-
-    /* save all the sessions in all the requests */
-    request_rec *r = f->r->main;
-    if (!r) {
-        r = f->r;
-    }
-    while (r) {
-        session_rec *z = NULL;
-        session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
-                                                      &session_module);
-
-        /* load the session, or create one if necessary */
-        ap_session_load(r, &z);
-        if (!z || z->written) {
-            r = r->next;
-            continue;
-        }
-
-        /* if a header was specified, insert the new values from the header */
-        if (conf->header_set) {
-            const char *override = apr_table_get(r->err_headers_out, conf->header);
-            if (!override) {
-                override = apr_table_get(r->headers_out, conf->header);
-            }
-            if (override) {
-                z->encoded = override;
-                ap_session_identity_decode(r, z);
-            }
-        }
-
-        /* save away the session, and we're done */
-        ap_session_save(r, z);
-
-        r = r->next;
-    }
-
-    /* remove ourselves from the filter chain */
-    ap_remove_output_filter(f);
-
-    /* send the data up the stack */
-    return ap_pass_brigade(f->next, in);
-
-}
-
-/**
- * Insert the output filter.
- */
-static void ap_session_insert_output_filter(request_rec * r)
-{
-    ap_add_output_filter("MOD_SESSION_OUT", NULL, r, r->connection);
-}
-
-/**
- * Fixups hook.
- *
- * Load the session within a fixup - this ensures that the session is
- * properly loaded prior to the handler being called.
- * 
- * The fixup is also responsible for injecting the session into the CGI
- * environment, should the admin have configured it so.
- * 
- * @param r The request
- */
-AP_DECLARE(int) ap_session_fixups(request_rec * r)
-{
-    session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
-                                                  &session_module);
-
-    session_rec *z = NULL;
-    ap_session_load(r, &z);
-
-    if (conf->env) {
-        ap_session_identity_encode(r, z);
-        if (z->encoded) {
-            apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded);
-            z->encoded = NULL;
-        }
-    }
-
-    return OK;
-
-}
-
-
-static void *create_session_dir_config(apr_pool_t * p, char *dummy)
-{
-    session_dir_conf *new =
-    (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
-
-    new->includes = apr_array_make(p, 10, sizeof(const char **));
-    new->excludes = apr_array_make(p, 10, sizeof(const char **));
-
-    return (void *) new;
-}
-
-static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
-{
-    session_dir_conf *new = (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
-    session_dir_conf *add = (session_dir_conf *) addv;
-    session_dir_conf *base = (session_dir_conf *) basev;
-
-    new->enabled = (add->enabled_set == 0) ? base->enabled : add->enabled;
-    new->enabled_set = add->enabled_set || base->enabled_set;
-    new->maxage = (add->maxage_set == 0) ? base->maxage : add->maxage;
-    new->maxage_set = add->maxage_set || base->maxage_set;
-    new->header = (add->header_set == 0) ? base->header : add->header;
-    new->header_set = add->header_set || base->header_set;
-    new->env = (add->env_set == 0) ? base->env : add->env;
-    new->env_set = add->env_set || base->env_set;
-    new->includes = apr_array_append(p, base->includes, add->includes);
-    new->excludes = apr_array_append(p, base->excludes, add->excludes);
-
-    return new;
-}
-
-
-static const char *
-     set_session_enable(cmd_parms * parms, void *dconf, int flag)
-{
-    session_dir_conf *conf = dconf;
-
-    conf->enabled = flag;
-    conf->enabled_set = 1;
-
-    return NULL;
-}
-
-static const char *
-     set_session_maxage(cmd_parms * parms, void *dconf, const char *arg)
-{
-    session_dir_conf *conf = dconf;
-
-    conf->maxage = atol(arg);
-    conf->maxage_set = 1;
-
-    return NULL;
-}
-
-static const char *
-     set_session_header(cmd_parms * parms, void *dconf, const char *arg)
-{
-    session_dir_conf *conf = dconf;
-
-    conf->header = arg;
-    conf->header_set = 1;
-
-    return NULL;
-}
-
-static const char *
-     set_session_env(cmd_parms * parms, void *dconf, int flag)
-{
-    session_dir_conf *conf = dconf;
-
-    conf->env = flag;
-    conf->env_set = 1;
-
-    return NULL;
-}
-
-static const char *add_session_include(cmd_parms * cmd, void *dconf, const char *f)
-{
-    session_dir_conf *conf = dconf;
-
-    const char **new = apr_array_push(conf->includes);
-    *new = f;
-
-    return NULL;
-}
-
-static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char *f)
-{
-    session_dir_conf *conf = dconf;
-
-    const char **new = apr_array_push(conf->excludes);
-    *new = f;
-
-    return NULL;
-}
-
-
-static const command_rec session_cmds[] =
-{
-    AP_INIT_FLAG("Session", set_session_enable, NULL, OR_AUTHCFG,
-                 "on if a session should be maintained for these URLs"),
-    AP_INIT_TAKE1("SessionMaxAge", set_session_maxage, NULL, OR_AUTHCFG,
-                  "length of time for which a session should be valid. Zero to disable"),
-    AP_INIT_TAKE1("SessionHeader", set_session_header, NULL, OR_AUTHCFG,
-                  "output header, if present, whose contents will be injected into the session."),
-    AP_INIT_FLAG("SessionEnv", set_session_env, NULL, OR_AUTHCFG,
-                 "on if a session should be written to the CGI environment. Defaults to off"),
-    AP_INIT_TAKE1("SessionInclude", add_session_include, NULL, OR_AUTHCFG,
-                  "URL prefixes to include in the session. Defaults to all URLs"),
-    AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, OR_AUTHCFG,
-                  "URL prefixes to exclude from the session. Defaults to no URLs"),
-    {NULL}
-};
-
-static void register_hooks(apr_pool_t * p)
-{
-    ap_register_output_filter("MOD_SESSION_OUT", ap_session_output_filter,
-                              NULL, AP_FTYPE_CONTENT_SET);
-    ap_hook_insert_filter(ap_session_insert_output_filter, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_insert_error_filter(ap_session_insert_output_filter,
-                                NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_fixups(ap_session_fixups, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_session_encode(ap_session_identity_encode, NULL, NULL, APR_HOOK_REALLY_FIRST);
-    ap_hook_session_decode(ap_session_identity_decode, NULL, NULL, APR_HOOK_REALLY_LAST);
-    APR_REGISTER_OPTIONAL_FN(ap_session_get);
-    APR_REGISTER_OPTIONAL_FN(ap_session_set);
-    APR_REGISTER_OPTIONAL_FN(ap_session_load);
-    APR_REGISTER_OPTIONAL_FN(ap_session_save);
-}
-
-module AP_MODULE_DECLARE_DATA session_module =
-{
-    STANDARD20_MODULE_STUFF,
-    create_session_dir_config,   /* dir config creater */
-    merge_session_dir_config,    /* dir merger --- default is to override */
-    NULL,                        /* server config */
-    NULL,                        /* merge server config */
-    session_cmds,                /* command apr_table_t */
-    register_hooks               /* register hooks */
-};
+/* Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "mod_session.h"\r
+#include "apr_lib.h"\r
+#include "apr_strings.h"\r
+#include "util_filter.h"\r
+#include "http_log.h"\r
+#include "http_request.h"\r
+#include "http_protocol.h"\r
+\r
+#define SESSION_PREFIX "mod_session: "\r
+#define SESSION_EXPIRY "expiry"\r
+#define HTTP_SESSION "HTTP_SESSION"\r
+\r
+APR_HOOK_STRUCT(\r
+                APR_HOOK_LINK(session_load)\r
+                APR_HOOK_LINK(session_save)\r
+                APR_HOOK_LINK(session_encode)\r
+                APR_HOOK_LINK(session_decode)\r
+)\r
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, session_load,\r
+                      (request_rec * r, session_rec ** z), (r, z), DECLINED)\r
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, session_save,\r
+                       (request_rec * r, session_rec * z), (r, z), DECLINED)\r
+AP_IMPLEMENT_HOOK_RUN_ALL(int, session_encode,\r
+                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)\r
+AP_IMPLEMENT_HOOK_RUN_ALL(int, session_decode,\r
+                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)\r
+/**\r
+ * Should the session be included within this URL.\r
+ *\r
+ * This function tests whether a session is valid for this URL. It uses the\r
+ * include and exclude arrays to determine whether they should be included.\r
+ */\r
+    static int session_included(request_rec * r, session_dir_conf * conf)\r
+{\r
+\r
+    const char **includes = (const char **) conf->includes->elts;\r
+    const char **excludes = (const char **) conf->excludes->elts;\r
+    int included = 1;                /* defaults to included */\r
+    int i;\r
+\r
+    if (conf->includes->nelts) {\r
+        included = 0;\r
+        for (i = 0; !included && i < conf->includes->nelts; i++) {\r
+            const char *include = includes[i];\r
+            if (strncmp(r->parsed_uri.path, include, strlen(include))) {\r
+                included = 1;\r
+            }\r
+        }\r
+    }\r
+\r
+    if (conf->excludes->nelts) {\r
+        for (i = 0; included && i < conf->includes->nelts; i++) {\r
+            const char *exclude = excludes[i];\r
+            if (strncmp(r->parsed_uri.path, exclude, strlen(exclude))) {\r
+                included = 0;\r
+            }\r
+        }\r
+    }\r
+\r
+    return included;\r
+}\r
+\r
+/**\r
+ * Get a particular value from the session.\r
+ * @param r The current request.\r
+ * @param z The current session. If this value is NULL, the session will be\r
+ * looked up in the request, created if necessary, and saved to the request\r
+ * notes.\r
+ * @param key The key to get.\r
+ * @param value The buffer to write the value to.\r
+ */\r
+AP_DECLARE(void) ap_session_get(request_rec * r, session_rec * z, const char *key, const char **value)\r
+{\r
+    if (!z) {\r
+        ap_session_load(r, &z);\r
+    }\r
+    if (z) {\r
+        *value = apr_table_get(z->entries, key);\r
+    }\r
+}\r
+\r
+/**\r
+ * Set a particular value to the session.\r
+ *\r
+ * Using this method ensures that the dirty flag is set correctly, so that\r
+ * the session can be saved efficiently.\r
+ * @param r The current request.\r
+ * @param z The current session. If this value is NULL, the session will be\r
+ * looked up in the request, created if necessary, and saved to the request\r
+ * notes.\r
+ * @param key The key to set. The existing key value will be replaced.\r
+ * @param value The value to set.\r
+ */\r
+AP_DECLARE(void) ap_session_set(request_rec * r, session_rec * z,\r
+                                const char *key, const char *value)\r
+{\r
+    if (!z) {\r
+        ap_session_load(r, &z);\r
+    }\r
+    if (z) {\r
+        if (value) {\r
+            apr_table_set(z->entries, key, value);\r
+        }\r
+        else {\r
+            apr_table_unset(z->entries, key);\r
+        }\r
+        z->dirty = 1;\r
+    }\r
+}\r
+\r
+/**\r
+ * Load the session.\r
+ *\r
+ * If the session doesn't exist, a blank one will be created.\r
+ *\r
+ * @param r The request\r
+ * @param z A pointer to where the session will be written.\r
+ */\r
+AP_DECLARE(int) ap_session_load(request_rec * r, session_rec ** z)\r
+{\r
+\r
+    session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,\r
+                                                   &session_module);\r
+    apr_time_t now;\r
+    session_rec *zz = NULL;\r
+    int rv = 0;\r
+\r
+    /* is the session enabled? */\r
+    if (!dconf->enabled) {\r
+        return APR_SUCCESS;\r
+    }\r
+\r
+    /* should the session be loaded at all? */\r
+    if (!session_included(r, dconf)) {\r
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, SESSION_PREFIX\r
+                      "excluded by configuration for: %s", r->uri);\r
+        return APR_SUCCESS;\r
+    }\r
+\r
+    /* load the session from the session hook */\r
+    rv = ap_run_session_load(r, &zz);\r
+    if (DECLINED == rv) {\r
+        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX\r
+                      "session is enabled but no session modules have been configured, "\r
+                      "session not loaded: %s", r->uri);\r
+        return APR_EGENERAL;\r
+    }\r
+    else if (OK != rv) {\r
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX\r
+                      "error while loading the session, "\r
+                      "session not loaded: %s", r->uri);\r
+        return rv;\r
+    }\r
+\r
+    /* found a session that hasn't expired? */\r
+    now = apr_time_now();\r
+    if (!zz || (zz->expiry && zz->expiry < now)) {\r
+\r
+        /* no luck, create a blank session */\r
+        zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));\r
+        zz->pool = r->pool;\r
+        zz->entries = apr_table_make(zz->pool, 10);\r
+        zz->uuid = (apr_uuid_t *) apr_pcalloc(zz->pool, sizeof(apr_uuid_t));\r
+        apr_uuid_get(zz->uuid);\r
+\r
+    }\r
+    else {\r
+        rv = ap_run_session_decode(r, zz);\r
+        if (OK != rv) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX\r
+                          "error while decoding the session, "\r
+                          "session not loaded: %s", r->uri);\r
+            return rv;\r
+        }\r
+    }\r
+\r
+    /* make sure the expiry is set, if present */\r
+    if (!zz->expiry && dconf->maxage) {\r
+        zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC;\r
+        zz->maxage = dconf->maxage;\r
+    }\r
+\r
+    *z = zz;\r
+\r
+    return APR_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ * Save the session.\r
+ *\r
+ * In most implementations the session is only saved if the dirty flag is\r
+ * true. This prevents the session being saved unnecessarily.\r
+ *\r
+ * @param r The request\r
+ * @param z A pointer to where the session will be written.\r
+ */\r
+AP_DECLARE(int) ap_session_save(request_rec * r, session_rec * z)\r
+{\r
+    if (z) {\r
+        apr_time_t now = apr_time_now();\r
+        int rv = 0;\r
+\r
+        /* sanity checks, should we try save at all? */\r
+        if (z->written) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, SESSION_PREFIX\r
+                          "attempt made to save the session twice, "\r
+                          "session not saved: %s", r->uri);\r
+            return APR_EGENERAL;\r
+        }\r
+        if (z->expiry && z->expiry < now) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX\r
+                          "attempt made to save a session when the session had already expired, "\r
+                          "session not saved: %s", r->uri);\r
+            return APR_EGENERAL;\r
+        }\r
+\r
+        /* encode the session */\r
+        rv = ap_run_session_encode(r, z);\r
+        if (OK != rv) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX\r
+                          "error while encoding the session, "\r
+                          "session not saved: %s", r->uri);\r
+            return rv;\r
+        }\r
+\r
+        /* try the save */\r
+        rv = ap_run_session_save(r, z);\r
+        if (DECLINED == rv) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX\r
+                          "session is enabled but no session modules have been configured, "\r
+                          "session not saved: %s", r->uri);\r
+            return APR_EGENERAL;\r
+        }\r
+        else if (OK != rv) {\r
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX\r
+                          "error while saving the session, "\r
+                          "session not saved: %s", r->uri);\r
+            return rv;\r
+        }\r
+        else {\r
+            z->written = 1;\r
+        }\r
+    }\r
+\r
+    return APR_SUCCESS;\r
+\r
+}\r
+\r
+static int identity_count(int *count, const char *key, const char *val)\r
+{\r
+    *count += strlen(key) * 3 + strlen(val) * 3 + 1;\r
+    return 1;\r
+}\r
+\r
+static int identity_concat(char *buffer, const char *key, const char *val)\r
+{\r
+    char *slider = buffer;\r
+    int length = strlen(slider);\r
+    slider += length;\r
+    if (length) {\r
+        *slider = '&';\r
+        slider++;\r
+    }\r
+    ap_escape_path_segment_buffer(slider, key);\r
+    slider += strlen(slider);\r
+    *slider = '=';\r
+    slider++;\r
+    ap_escape_path_segment_buffer(slider, val);\r
+    return 1;\r
+}\r
+\r
+/**\r
+ * Default identity encoding for the session.\r
+ *\r
+ * By default, the name value pairs in the session are URLEncoded, separated\r
+ * by equals, and then in turn separated by ampersand, in the format of an\r
+ * html form.\r
+ *\r
+ * This was chosen to make it easy for external code to unpack a session,\r
+ * should there be a need to do so.\r
+ *\r
+ * @param r The request pointer.\r
+ * @param z A pointer to where the session will be written.\r
+ */\r
+AP_DECLARE(int) ap_session_identity_encode(request_rec * r, session_rec * z)\r
+{\r
+\r
+    char *buffer = NULL;\r
+    int length = 0;\r
+    if (z->expiry) {\r
+        char *expiry = apr_psprintf(r->pool, "%" APR_INT64_T_FMT, z->expiry);\r
+        apr_table_set(z->entries, SESSION_EXPIRY, expiry);\r
+    }\r
+    apr_table_do((int (*) (void *, const char *, const char *))\r
+                 identity_count, &length, z->entries, NULL);;\r
+    buffer = apr_pcalloc(r->pool, length + 1);\r
+    apr_table_do((int (*) (void *, const char *, const char *))\r
+                 identity_concat, buffer, z->entries, NULL);\r
+    z->encoded = buffer;\r
+    return OK;\r
+\r
+}\r
+\r
+/**\r
+ * Default identity decoding for the session.\r
+ *\r
+ * By default, the name value pairs in the session are URLEncoded, separated\r
+ * by equals, and then in turn separated by ampersand, in the format of an\r
+ * html form.\r
+ *\r
+ * This was chosen to make it easy for external code to unpack a session,\r
+ * should there be a need to do so.\r
+ *\r
+ * This function reverses that process, and populates the session table.\r
+ *\r
+ * Name / value pairs that are not encoded properly are ignored.\r
+ *\r
+ * @param r The request pointer.\r
+ * @param z A pointer to where the session will be written.\r
+ */\r
+AP_DECLARE(int) ap_session_identity_decode(request_rec * r, session_rec * z)\r
+{\r
+\r
+    char *last = NULL;\r
+    char *encoded, *pair;\r
+    const char *sep = "&";\r
+\r
+    /* sanity check - anything to decode? */\r
+    if (!z->encoded) {\r
+        return OK;\r
+    }\r
+\r
+    /* decode what we have */\r
+    encoded = apr_pstrcat(r->pool, z->encoded, NULL);\r
+    pair = apr_strtok(encoded, sep, &last);\r
+    while (pair && pair[0]) {\r
+        char *plast = NULL;\r
+        const char *psep = "=";\r
+        char *key = apr_strtok(pair, psep, &plast);\r
+        char *val = apr_strtok(NULL, psep, &plast);\r
+        if (key && *key) {\r
+            if (!val || !*val) {\r
+                apr_table_unset(z->entries, key);\r
+            }\r
+            if (!ap_unescape_all(key) && !ap_unescape_all(val)) {\r
+                if (!strcmp(SESSION_EXPIRY, key)) {\r
+                    z->expiry = (apr_time_t) apr_atoi64(val);\r
+                }\r
+                else {\r
+                    apr_table_set(z->entries, key, val);\r
+                }\r
+            }\r
+        }\r
+        pair = apr_strtok(NULL, sep, &last);\r
+    }\r
+    z->encoded = NULL;\r
+    return OK;\r
+\r
+}\r
+\r
+/**\r
+ * Ensure any changes to the session are committed.\r
+ *\r
+ * This is done in an output filter so that our options for where to\r
+ * store the session can include storing the session within a cookie:\r
+ * As an HTTP header, the cookie must be set before the output is\r
+ * written, but after the handler is run.\r
+ *\r
+ * NOTE: It is possible for internal redirects to cause more than one\r
+ * request to be present, and each request might have a session\r
+ * defined. We need to go through each session in turn, and save each\r
+ * one.\r
+ * \r
+ * The same session might appear in more than one request. The first\r
+ * attempt to save the session will be called\r
+ */\r
+static apr_status_t ap_session_output_filter(ap_filter_t * f,\r
+                                                    apr_bucket_brigade * in)\r
+{\r
+\r
+    /* save all the sessions in all the requests */\r
+    request_rec *r = f->r->main;\r
+    if (!r) {\r
+        r = f->r;\r
+    }\r
+    while (r) {\r
+        session_rec *z = NULL;\r
+        session_dir_conf *conf = ap_get_module_config(r->per_dir_config,\r
+                                                      &session_module);\r
+\r
+        /* load the session, or create one if necessary */\r
+        ap_session_load(r, &z);\r
+        if (!z || z->written) {\r
+            r = r->next;\r
+            continue;\r
+        }\r
+\r
+        /* if a header was specified, insert the new values from the header */\r
+        if (conf->header_set) {\r
+            const char *override = apr_table_get(r->err_headers_out, conf->header);\r
+            if (!override) {\r
+                override = apr_table_get(r->headers_out, conf->header);\r
+            }\r
+            if (override) {\r
+                z->encoded = override;\r
+                ap_session_identity_decode(r, z);\r
+            }\r
+        }\r
+\r
+        /* save away the session, and we're done */\r
+        ap_session_save(r, z);\r
+\r
+        r = r->next;\r
+    }\r
+\r
+    /* remove ourselves from the filter chain */\r
+    ap_remove_output_filter(f);\r
+\r
+    /* send the data up the stack */\r
+    return ap_pass_brigade(f->next, in);\r
+\r
+}\r
+\r
+/**\r
+ * Insert the output filter.\r
+ */\r
+static void ap_session_insert_output_filter(request_rec * r)\r
+{\r
+    ap_add_output_filter("MOD_SESSION_OUT", NULL, r, r->connection);\r
+}\r
+\r
+/**\r
+ * Fixups hook.\r
+ *\r
+ * Load the session within a fixup - this ensures that the session is\r
+ * properly loaded prior to the handler being called.\r
+ * \r
+ * The fixup is also responsible for injecting the session into the CGI\r
+ * environment, should the admin have configured it so.\r
+ * \r
+ * @param r The request\r
+ */\r
+AP_DECLARE(int) ap_session_fixups(request_rec * r)\r
+{\r
+    session_dir_conf *conf = ap_get_module_config(r->per_dir_config,\r
+                                                  &session_module);\r
+\r
+    session_rec *z = NULL;\r
+    ap_session_load(r, &z);\r
+\r
+    if (conf->env) {\r
+        ap_session_identity_encode(r, z);\r
+        if (z->encoded) {\r
+            apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded);\r
+            z->encoded = NULL;\r
+        }\r
+    }\r
+\r
+    return OK;\r
+\r
+}\r
+\r
+\r
+static void *create_session_dir_config(apr_pool_t * p, char *dummy)\r
+{\r
+    session_dir_conf *new =\r
+    (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));\r
+\r
+    new->includes = apr_array_make(p, 10, sizeof(const char **));\r
+    new->excludes = apr_array_make(p, 10, sizeof(const char **));\r
+\r
+    return (void *) new;\r
+}\r
+\r
+static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)\r
+{\r
+    session_dir_conf *new = (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));\r
+    session_dir_conf *add = (session_dir_conf *) addv;\r
+    session_dir_conf *base = (session_dir_conf *) basev;\r
+\r
+    new->enabled = (add->enabled_set == 0) ? base->enabled : add->enabled;\r
+    new->enabled_set = add->enabled_set || base->enabled_set;\r
+    new->maxage = (add->maxage_set == 0) ? base->maxage : add->maxage;\r
+    new->maxage_set = add->maxage_set || base->maxage_set;\r
+    new->header = (add->header_set == 0) ? base->header : add->header;\r
+    new->header_set = add->header_set || base->header_set;\r
+    new->env = (add->env_set == 0) ? base->env : add->env;\r
+    new->env_set = add->env_set || base->env_set;\r
+    new->includes = apr_array_append(p, base->includes, add->includes);\r
+    new->excludes = apr_array_append(p, base->excludes, add->excludes);\r
+\r
+    return new;\r
+}\r
+\r
+\r
+static const char *\r
+     set_session_enable(cmd_parms * parms, void *dconf, int flag)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    conf->enabled = flag;\r
+    conf->enabled_set = 1;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char *\r
+     set_session_maxage(cmd_parms * parms, void *dconf, const char *arg)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    conf->maxage = atol(arg);\r
+    conf->maxage_set = 1;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char *\r
+     set_session_header(cmd_parms * parms, void *dconf, const char *arg)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    conf->header = arg;\r
+    conf->header_set = 1;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char *\r
+     set_session_env(cmd_parms * parms, void *dconf, int flag)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    conf->env = flag;\r
+    conf->env_set = 1;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char *add_session_include(cmd_parms * cmd, void *dconf, const char *f)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    const char **new = apr_array_push(conf->includes);\r
+    *new = f;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char *f)\r
+{\r
+    session_dir_conf *conf = dconf;\r
+\r
+    const char **new = apr_array_push(conf->excludes);\r
+    *new = f;\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+static const command_rec session_cmds[] =\r
+{\r
+    AP_INIT_FLAG("Session", set_session_enable, NULL, OR_AUTHCFG,\r
+                 "on if a session should be maintained for these URLs"),\r
+    AP_INIT_TAKE1("SessionMaxAge", set_session_maxage, NULL, OR_AUTHCFG,\r
+                  "length of time for which a session should be valid. Zero to disable"),\r
+    AP_INIT_TAKE1("SessionHeader", set_session_header, NULL, OR_AUTHCFG,\r
+                  "output header, if present, whose contents will be injected into the session."),\r
+    AP_INIT_FLAG("SessionEnv", set_session_env, NULL, OR_AUTHCFG,\r
+                 "on if a session should be written to the CGI environment. Defaults to off"),\r
+    AP_INIT_TAKE1("SessionInclude", add_session_include, NULL, OR_AUTHCFG,\r
+                  "URL prefixes to include in the session. Defaults to all URLs"),\r
+    AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, OR_AUTHCFG,\r
+                  "URL prefixes to exclude from the session. Defaults to no URLs"),\r
+    {NULL}\r
+};\r
+\r
+static void register_hooks(apr_pool_t * p)\r
+{\r
+    ap_register_output_filter("MOD_SESSION_OUT", ap_session_output_filter,\r
+                              NULL, AP_FTYPE_CONTENT_SET);\r
+    ap_hook_insert_filter(ap_session_insert_output_filter, NULL, NULL, APR_HOOK_MIDDLE);\r
+    ap_hook_insert_error_filter(ap_session_insert_output_filter,\r
+                                NULL, NULL, APR_HOOK_MIDDLE);\r
+    ap_hook_fixups(ap_session_fixups, NULL, NULL, APR_HOOK_MIDDLE);\r
+    ap_hook_session_encode(ap_session_identity_encode, NULL, NULL, APR_HOOK_REALLY_FIRST);\r
+    ap_hook_session_decode(ap_session_identity_decode, NULL, NULL, APR_HOOK_REALLY_LAST);\r
+    APR_REGISTER_OPTIONAL_FN(ap_session_get);\r
+    APR_REGISTER_OPTIONAL_FN(ap_session_set);\r
+    APR_REGISTER_OPTIONAL_FN(ap_session_load);\r
+    APR_REGISTER_OPTIONAL_FN(ap_session_save);\r
+}\r
+\r
+module AP_MODULE_DECLARE_DATA session_module =\r
+{\r
+    STANDARD20_MODULE_STUFF,\r
+    create_session_dir_config,   /* dir config creater */\r
+    merge_session_dir_config,    /* dir merger --- default is to override */\r
+    NULL,                        /* server config */\r
+    NULL,                        /* merge server config */\r
+    session_cmds,                /* command apr_table_t */\r
+    register_hooks               /* register hooks */\r
+};\r