|
|
a4f3a1 |
diff --git a/docs/manual/mod/mod_session.html.en b/docs/manual/mod/mod_session.html.en
|
|
|
a4f3a1 |
index 96a61e6..4ecc97d 100644
|
|
|
a4f3a1 |
--- a/docs/manual/mod/mod_session.html.en
|
|
|
a4f3a1 |
+++ b/docs/manual/mod/mod_session.html.en
|
|
|
a4f3a1 |
@@ -69,6 +69,7 @@
|
|
|
a4f3a1 |
SessionHeader
|
|
|
a4f3a1 |
SessionInclude
|
|
|
a4f3a1 |
SessionMaxAge
|
|
|
a4f3a1 |
+ SessionExpiryUpdateInterval
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
Topics
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
@@ -494,6 +495,37 @@ AuthName realm
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
Setting the maxage to zero disables session expiry.
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+Description:Define the number of seconds a session's expiry may change without the session being updated
|
|
|
a4f3a1 |
+Syntax:SessionExpiryUpdateInterval interval
|
|
|
a4f3a1 |
+Default:SessionExpiryUpdateInterval 0 (always update)
|
|
|
a4f3a1 |
+Context:server config, virtual host, directory, .htaccess
|
|
|
a4f3a1 |
+Module:mod_session
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ The SessionExpiryUpdateInterval directive allows
|
|
|
a4f3a1 |
+ sessions to avoid the cost associated with writing the session each request
|
|
|
a4f3a1 |
+ when only the expiry time has changed. This can be used to make a website
|
|
|
a4f3a1 |
+ more efficient or reduce load on a database when using
|
|
|
a4f3a1 |
+ <module>mod_session_dbd</module>. The session is always written if the data
|
|
|
a4f3a1 |
+ stored in the session has changed or the expiry has changed by more than the
|
|
|
a4f3a1 |
+ configured interval.
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ Setting the interval to zero disables this directive, and the session
|
|
|
a4f3a1 |
+ expiry is refreshed for each request.
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ This directive only has an effect when combined with SessionMaxAge to enable session
|
|
|
a4f3a1 |
+ expiry. Sessions without an expiry are only written when the data stored in
|
|
|
a4f3a1 |
+ the session has changed.
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ Warning
|
|
|
a4f3a1 |
+ Because the session expiry may not be refreshed with each request, it's
|
|
|
a4f3a1 |
+ possible for sessions to expire up to interval seconds early.
|
|
|
a4f3a1 |
+ Using a small interval usually provides sufficient savings while having a
|
|
|
a4f3a1 |
+ minimal effect on expiry resolution.
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
|
|
a4f3a1 |
index 3e73c7a..83bf3fc 100644
|
|
|
a4f3a1 |
--- a/modules/session/mod_session.c
|
|
|
a4f3a1 |
+++ b/modules/session/mod_session.c
|
|
|
a4f3a1 |
@@ -177,6 +177,7 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z)
|
|
|
a4f3a1 |
{
|
|
|
a4f3a1 |
if (z) {
|
|
|
a4f3a1 |
apr_time_t now = apr_time_now();
|
|
|
a4f3a1 |
+ apr_time_t initialExpiry = z->expiry;
|
|
|
a4f3a1 |
int rv = 0;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
|
|
a4f3a1 |
@@ -202,6 +203,17 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z)
|
|
|
a4f3a1 |
z->maxage = dconf->maxage;
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+ /* don't save if the only change is the expiry by a small amount */
|
|
|
a4f3a1 |
+ if (!z->dirty && dconf->expiry_update_time
|
|
|
a4f3a1 |
+ && (z->expiry - initialExpiry < dconf->expiry_update_time)) {
|
|
|
a4f3a1 |
+ return APR_SUCCESS;
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ /* also don't save sessions that didn't change at all */
|
|
|
a4f3a1 |
+ if (!z->dirty && !z->maxage) {
|
|
|
a4f3a1 |
+ return APR_SUCCESS;
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
/* encode the session */
|
|
|
a4f3a1 |
rv = ap_run_session_encode(r, z);
|
|
|
a4f3a1 |
if (OK != rv) {
|
|
|
a4f3a1 |
@@ -544,6 +556,10 @@ static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
|
|
|
a4f3a1 |
new->env_set = add->env_set || base->env_set;
|
|
|
a4f3a1 |
new->includes = apr_array_append(p, base->includes, add->includes);
|
|
|
a4f3a1 |
new->excludes = apr_array_append(p, base->excludes, add->excludes);
|
|
|
a4f3a1 |
+ new->expiry_update_time = (add->expiry_update_set == 0)
|
|
|
a4f3a1 |
+ ? base->expiry_update_time
|
|
|
a4f3a1 |
+ : add->expiry_update_time;
|
|
|
a4f3a1 |
+ new->expiry_update_set = add->expiry_update_set || base->expiry_update_set;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
return new;
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
@@ -613,6 +629,21 @@ static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char
|
|
|
a4f3a1 |
return NULL;
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+static const char *
|
|
|
a4f3a1 |
+ set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg)
|
|
|
a4f3a1 |
+{
|
|
|
a4f3a1 |
+ session_dir_conf *conf = dconf;
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ conf->expiry_update_time = atoi(arg);
|
|
|
a4f3a1 |
+ if (conf->expiry_update_time < 0) {
|
|
|
a4f3a1 |
+ return "SessionExpiryUpdateInterval must be positive or nul";
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+ conf->expiry_update_time = apr_time_from_sec(conf->expiry_update_time);
|
|
|
a4f3a1 |
+ conf->expiry_update_set = 1;
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ return NULL;
|
|
|
a4f3a1 |
+}
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
static const command_rec session_cmds[] =
|
|
|
a4f3a1 |
{
|
|
|
a4f3a1 |
@@ -628,6 +659,9 @@ static const command_rec session_cmds[] =
|
|
|
a4f3a1 |
"URL prefixes to include in the session. Defaults to all URLs"),
|
|
|
a4f3a1 |
AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
|
a4f3a1 |
"URL prefixes to exclude from the session. Defaults to no URLs"),
|
|
|
a4f3a1 |
+ AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
|
a4f3a1 |
+ "time interval for which a session's expiry time may change "
|
|
|
a4f3a1 |
+ "without having to be rewritten. Zero to disable"),
|
|
|
a4f3a1 |
{NULL}
|
|
|
a4f3a1 |
};
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
diff --git a/modules/session/mod_session.h b/modules/session/mod_session.h
|
|
|
a4f3a1 |
index a6dd5e9..bdeb532 100644
|
|
|
a4f3a1 |
--- a/modules/session/mod_session.h
|
|
|
a4f3a1 |
+++ b/modules/session/mod_session.h
|
|
|
a4f3a1 |
@@ -115,6 +115,9 @@ typedef struct {
|
|
|
a4f3a1 |
* URLs included if empty */
|
|
|
a4f3a1 |
apr_array_header_t *excludes; /* URL prefixes to be excluded. No
|
|
|
a4f3a1 |
* URLs excluded if empty */
|
|
|
a4f3a1 |
+ apr_time_t expiry_update_time; /* seconds the session expiry may change and
|
|
|
a4f3a1 |
+ * not have to be rewritten */
|
|
|
a4f3a1 |
+ int expiry_update_set;
|
|
|
a4f3a1 |
} session_dir_conf;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
/**
|
|
|
a4f3a1 |
diff --git a/modules/session/mod_session_cookie.c b/modules/session/mod_session_cookie.c
|
|
|
a4f3a1 |
index 6a02322..4aa75e4 100644
|
|
|
a4f3a1 |
--- a/modules/session/mod_session_cookie.c
|
|
|
a4f3a1 |
+++ b/modules/session/mod_session_cookie.c
|
|
|
a4f3a1 |
@@ -60,9 +60,6 @@ static apr_status_t session_cookie_save(request_rec * r, session_rec * z)
|
|
|
a4f3a1 |
session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
|
a4f3a1 |
&session_cookie_module);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
- /* don't cache auth protected pages */
|
|
|
a4f3a1 |
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
|
|
a4f3a1 |
-
|
|
|
a4f3a1 |
/* create RFC2109 compliant cookie */
|
|
|
a4f3a1 |
if (conf->name_set) {
|
|
|
a4f3a1 |
if (z->encoded && z->encoded[0]) {
|
|
|
a4f3a1 |
@@ -162,6 +159,9 @@ static apr_status_t session_cookie_load(request_rec * r, session_rec ** z)
|
|
|
a4f3a1 |
/* put the session in the notes so we don't have to parse it again */
|
|
|
a4f3a1 |
apr_table_setn(m->notes, note, (char *)zz);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+ /* don't cache auth protected pages */
|
|
|
a4f3a1 |
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
return OK;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
diff --git a/modules/session/mod_session_dbd.c b/modules/session/mod_session_dbd.c
|
|
|
a4f3a1 |
index cf65e5a..20ef72e 100644
|
|
|
a4f3a1 |
--- a/modules/session/mod_session_dbd.c
|
|
|
a4f3a1 |
+++ b/modules/session/mod_session_dbd.c
|
|
|
a4f3a1 |
@@ -243,6 +243,9 @@ static apr_status_t session_dbd_load(request_rec * r, session_rec ** z)
|
|
|
a4f3a1 |
/* put the session in the notes so we don't have to parse it again */
|
|
|
a4f3a1 |
apr_table_setn(m->notes, note, (char *)zz);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+ /* don't cache pages with a session */
|
|
|
a4f3a1 |
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
return OK;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
@@ -407,9 +410,6 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z)
|
|
|
a4f3a1 |
if (conf->name_set || conf->name2_set) {
|
|
|
a4f3a1 |
char *oldkey = NULL, *newkey = NULL;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
- /* don't cache pages with a session */
|
|
|
a4f3a1 |
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
|
|
a4f3a1 |
-
|
|
|
a4f3a1 |
/* if the session is new or changed, make a new session ID */
|
|
|
a4f3a1 |
if (z->uuid) {
|
|
|
a4f3a1 |
oldkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
|
|
|
a4f3a1 |
@@ -456,7 +456,7 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z)
|
|
|
a4f3a1 |
else if (conf->peruser) {
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
/* don't cache pages with a session */
|
|
|
a4f3a1 |
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
|
|
a4f3a1 |
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
if (r->user) {
|
|
|
a4f3a1 |
ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry);
|