From: Ruediger Pluem Date: Tue, 8 Apr 2008 13:49:49 +0000 (+0000) Subject: * Fix eol-style property. X-Git-Tag: 2.3.0~764 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3bd88fb8538f3ba71607589c9da02684b478d564;p=apache * Fix eol-style property. Changes to mod_session.c only fix line endings again. No functional changes. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@645923 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c index 4e377778b4..cd4950e719 100644 --- a/modules/session/mod_session.c +++ b/modules/session/mod_session.c @@ -1,620 +1,620 @@ -/* 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; - int rv = 0; - - /* 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 */ - 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 + * 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; + int rv = 0; + + /* 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 */ + 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 */ +};