|  | Home | Documentation | The Sessions Plugin updated by Robert van Engelen |

The Sessions Plugin

# HTTP Server Session Management Plugin

By Chris Moutsos and Robert van Engelen.

# Overview

The HTTP server session management plugin for gSOAP enables servers to store a database of sessions to keep track of client data across multiple requests. Client data is stored per session as name and value pairs that can be set to any valid string. Sessions are tracked with unique session IDs (sometimes called tokens) that are passed between the server and client with HTTP cookies.

The sessions plugin is MT safe.

# Features

- Stores sessions identified by random 128-bit session IDs managed with HTTP cookies
- Session validity can be restricted based on domain and path
- Each session stores a list of session variables (name/value string pairs)
- Can easily create, modify, delete, and retrieve session variables
- Configurable settings
  - Rolling sessions (re-set session ID cookie with every response)
  - Session ID cookie Max-Age and Expire attribute values
  - Maximum stale time before a session expires server-side
  - Time interval between purging expired sessions
  - Max number of sessions allowed in database
- Thread-safe
- Can be used with C or C++ projects

# Setup

To set up the sessions plugin on the server-side:

1. Make sure to compile your program with plugin/sessions.c and plugin/threads.c.
2. Enable cookies by compiling all gSOAP source code with -DWITH_COOKIES. Cookies are required for tracking session IDs.
3. Enable HTTPS (compile with -DWITH_OPENSSL or -DWITH_GNUTLS or link with -lgsoapssl/-lgsoapssl++).

Note
  While it is not a requirement to use HTTPS with this plugin, it is strongly recommended to use HTTPS. This is because the session ID cookies can be intercepted if not encrypted with SSL/TLS. Cookies are automatically sent with the Secure flag enabled when SSL is enabled. The HttpOnly flag is automatically enabled for all cookies in order to prevent XSS attacks.

# Basic Usage

Client-side usage is automatic, provided that the client supports cookies and the server has properly configured the plugin. If the client is a gSOAP application, make sure to compile with -DWITH_COOKIES.

For server-side usage, register the plugin with:

#include "plugin/sessions.h"
struct soap *soap = soap_new();
soap_register_plugin(soap, sessions);
sessions.h
sessions
SOAP_FMAC1 int SOAP_FMAC2 sessions(struct soap *soap, struct soap_plugin *plugin, void *arg)
Plugin registry function, invoked by soap_register_plugin.
Definition sessions.c:518

If you are using a server object in C++ generated with soappcpp2 option -j:

#include "plugin/sessions.h"
soap_register_plugin(server.soap, sessions);

For brevity, the struct soap* version will be used below. Replace soap with your server object's soap member if necessary.

Start a new session with:

struct soap_session *session = soap_start_session(soap, "domain", "path");
soap_start_session
SOAP_FMAC1 struct soap_session *SOAP_FMAC2 soap_start_session(struct soap *soap, const char *domain, const char *path)
Creates a new session with a random 128-bit ID. A cookie will be created with name SESSION_COOKIE_NAM...
Definition sessions.c:844
soap_session
A session node.
Definition sessions.h:86

This creates a new session with a random 128-bit session ID and the default settings (see section: Settings). If the client already has a session ID cookie with name SESSION_COOKIE_NAME and the given domain and path, and that ID refers to a valid session, that existing session will be returned instead.

Note
  For all of the sessions plugin function calls, domain and path arguments are required. These must match the values that were given when the session was created, otherwise the client's session ID cookie won't be found. The domain and path arguments may be set to NULL to use the current values given by the soap context's cookie_domain and cookie_path members:

  Attribute | Value
  --- | ---
  const char *cookie_domain | MUST be set to the domain (host) of the service
  const char *cookie_path | MAY be set to the default path to the service (defaults to '/')

  These rules also apply to the cookies used for tracking session IDs. See the gSOAP User Guide for more information on how gSOAP handles cookies.

For example, to create a session on localhost:8080 that is valid on any path:

soap->cookie_domain = "localhost:8080";
struct soap_session *session = soap_start_session(soap, NULL, NULL);

To create a new session variable or modify an existing session variable inside that session:

soap_set_session_var(soap, "session_var_name", "session_var_value", NULL, NULL);
soap_set_session_var
SOAP_FMAC1 struct soap_session_var *SOAP_FMAC2 soap_set_session_var(struct soap *soap, const char *name, const char *value, const char *domain, const char *path)
Add new session_var with the given name and value to the current session (identified by the cookie wi...
Definition sessions.c:1448

To access the value of that session variable:

const char *value = soap_get_session_var(soap, "session_var_name", NULL, NULL);
soap_get_session_var
SOAP_FMAC1 const char *SOAP_FMAC2 soap_get_session_var(struct soap *soap, const char *name, const char *domain, const char *path)
Returns session_var value by name in the current session (identified by the cookie with name SESSION_...
Definition sessions.c:1400

To delete that session variable:

soap_clr_session_var(soap, "session_var_name", NULL, NULL);
soap_clr_session_var
SOAP_FMAC1 void SOAP_FMAC2 soap_clr_session_var(struct soap *soap, const char *name, const char *domain, const char *path)
Frees session var with the given name in the current session (identified by the cookie with name SESS...
Definition sessions.c:1584

Consider changing the session's rolling, cookie_maxage, max_inactive_secs settings from their defaults. Read more about these in the Settings section.

# Simple Calculator Server (C) Example

We will show how to extend the simple calculator server example (in C) to keep track of the client's last calculated value with a session variable.

Make sure to register the plugin and set the default domain and path. After calling soap_destroy and soap_end, we should also free the internal cookie database (or call soap_done):

#include "plugin/session.h"
...
struct soap soap;
soap_init(&soap);
soap_register_plugin(&soap, sessions);
soap.cookie_domain = "localhost:8080";
soap.cookie_path = "/";
... // set up the service and serve requests
soap_destroy(&soap);
soap_end(&soap);
soap_free_cookies(&soap);

Now in each of our calculator service operations (ns__add, ns__sub, etc.), we can update the lastCalculation session variable in our current session:

int ns__add(struct soap *soap, double a, double b, double *result)
{
(void)soap; *result = a + b;
// make sure we have a session
if (!soap_get_session(soap, NULL, NULL))
{
// no current session, create a new one
if (!soap_start_session(soap, NULL, NULL))
return SOAP_ERR; // session creation failed
// configure session settings
soap_set_session_rolling(soap, 1, NULL, NULL);
soap_set_session_cookie_maxage(soap, 30, NULL, NULL);
soap_set_session_max_inactive_secs(soap, 30, NULL, NULL);
}
// update `lastCalculation` session variable
char calculation[80];
sprintf(calculation, "add %f %f, result = %f", a, b, *result);
soap_set_session_var(soap, "lastCalculation", calculation, NULL, NULL);
return SOAP_OK;
}
soap_get_session
SOAP_FMAC1 struct soap_session *SOAP_FMAC2 soap_get_session(struct soap *soap, const char *domain, const char *path)
Finds the session identified by the cookie with name SESSION_COOKIE_NAME and the given domain and pat...
Definition sessions.c:805
soap_set_session_cookie_maxage
SOAP_FMAC1 int SOAP_FMAC2 soap_set_session_cookie_maxage(struct soap *soap, long maxage, const char *domain, const char *path)
Sets the cookie_maxage for the current session (identified by the cookie with name SESSION_COOKIE_NAM...
Definition sessions.c:1164
soap_set_session_max_inactive_secs
SOAP_FMAC1 int SOAP_FMAC2 soap_set_session_max_inactive_secs(struct soap *soap, long max, const char *domain, const char *path)
Sets the max_inactive_secs for the current session (identified by the cookie with name SESSION_COOKIE...
Definition sessions.c:1242
soap_set_session_rolling
SOAP_FMAC1 int SOAP_FMAC2 soap_set_session_rolling(struct soap *soap, int rolling, const char *domain, const char *path)
Sets the rolling flag for the current session (identified by the cookie with name SESSION_COOKIE_NAME...
Definition sessions.c:1319

If we want to allow the client to access their last calculation, add another service operation to retrieve the lastCalculation session variable:

int ns__getLastCalculation(struct soap *soap, char **r)
{
const char *lastCalculation = soap_get_session_var(soap, "lastCalculation", NULL, NULL);
if (!lastCalculation)
lastCalculation = "None";
if ((*r = (char*)soap_malloc(soap, strlen(lastCalculation)+1)))
strcpy(*r, lastCalculation);
return SOAP_OK;
}

# Sessions Plugin API

This section describes the Sessions Plugin API.

Note
  The term session ID cookie refers to a cookie with the name SESSION_COOKIE_NAME (see section: Settings), the given domain and path (see section: Basic Usage), and a random 128-bit session ID as the value. The term current session refers to the session in the database identified by the client's session ID cookie.
  The arguments domain and path may be set to NULL to use the current values given by soap->cookie_domain and soap->cookie_path (see section: Basic Usage).

The sessions plugin provides the following API for server-side session management:

Session Plugin Function Description
struct soap_session* soap_start_session(struct soap * soap, const char *domain, const char *path); Create a session in the database and a session ID cookie. Behaves the same as soap_get_session if the client already has a valid session ID cookie. Returns pointer to the session node, or NULL if the session could not be created.
struct soap_session* soap_get_session(struct soap *soap, const char *domain, const char *path); Get the current session. Can be used as a 'touch'. Returns pointer to the session node, or NULL if the session is not found or is expired.

int soap_get_num_sessions(struct soap *soap, const char *domain, const char *path);
Get the number of sessions in the database. Returns -1 if the session is not found or is expired.

struct soap_session* soap_regenerate_session_id(struct soap * soap, const char *domain, const char *path);
Create a new session ID for the current session and update the session ID cookie. Returns pointer to the session node, or NULL if the session is not found or is expired.

int soap_get_num_session_vars(struct soap *soap, const char *domain, const char *path);
Get the number of session variables in the current session. Returns -1 if the session is not found or is expired.

void soap_end_session(struct soap *soap, const char * domain, const char *path);
Delete the current session from the database and clear the client's session ID cookie.

void soap_end_sessions(struct soap *soap, const char * domain, const char *path);
Delete all sessions in the database and clear the current session ID
cookie.

struct soap_session_var* soap_set_session_var(struct soap * soap, const char *name, const char *value, const char domain, const char *path);
Set a session variable with the given name and value in the current session, overwring any old value. Returns pointer to the session variable node, or NULL if the session is not found or is expired.

const char* soap_get_session_var(struct soap *soap, const char *name, const char *domain, const char *path);
Get the value of the session variable with the given name in the current session. Returns NULL if the session is not found or is expired.

void soap_clr_session_var(struct soap *soap, const char *name, const char *domain, const char *path);
Delete the session variable with the given name in the current session.

void soap_clr_session_vars(struct soap *soap, const char *domain, const char *path);
Delete all session variables in the current session.

For managing session settings (see section: Settings), the following API is provided:

Session Plugin Function Description (Settings / Misc.)
int soap_set_session_rolling(struct soap * soap, int rolling, const char *domain, const char * path); Set the rolling setting for the current session. Zero (non-rolling) means the session ID cookie is only set when the session is first created. Non-zero (rolling) means the session ID cookie will be re-set on every response. If successful, returns SOAP_OK, or SOAP_ERR otherwise.

int soap_get_session_rolling(struct soap * soap, const char *domain, const char *path);
Get the rolling setting for the current session. Returns -1 if the session is not found or is expired.

int soap_set_session_cookie_maxage(struct soap * soap, long maxage, const char *domain, const char * path);
Set the cookie_maxage member for the current session. This will be used to set the session ID cookie's Max-Age and Expires attributes. -1 means the cookie will have no Max-Age or Expires attributes. If successful, returns SOAP_OK, or SOAP_ERR otherwise.

long soap_get_session_cookie_maxage(struct soap * soap, const char *domain, const char *path);
Get the cookie_maxage member for the current session. Returns 0 if the session is not found or is expired.

int soap_set_session_max_inactive_secs(struct soap * soap, long max, const char *domain, const char * path);
Set the max_inactive_secs member for the current session. This is the maximum amount of stale time in seconds before a session is marked as expired (to be purged) on the server-side. -1 means the session will never expire. If successful, returns SOAP_OK, or SOAP_ERR otherwise.

long soap_get_session_max_inactive_secs(struct soap * soap, const char *domain, const char *path);
Get the max_inactive_secs member for the current session. Returns 0 if the session is not found or is expired.

struct soap_session* soap_get_sessions_head();
Get soap_sessions, the first node in the sessions linked list. Not necessary unless low-level list management is needed (see section: The Internals).

# Settings

In plugins/session.h, the following constants are defined:

Name | Default | Description
--- | --- | ---
SESSION_COOKIE_NAME | "GSOAP_SESSIONID" | The name to use for session ID cookies.
SESSION_MAX | 8192 | The max number of sessions allowed in the database. Any attempt to create more sessions than this will fail.
SESSIONS_DEFAULT_MAX_INACTIVE_SECS | 300 | The default time in seconds for sessions' max_inactive_secs member. -1 means the session will never expire server-side.
SESSION_PURGE_INTERVAL | 300 | On every session database access, the time since the last database purge is checked. If it's been longer than this interval (in seconds), any expired sessions will be purged with soap_purge_sessions(). 0 means a purge will occcur on every database access. -1 means a purge will never occur.

Set these values to whatever makes sense for your application.

In each session node, the following settings are declared:

Name | Default | Description
--- | --- | ---
rolling | 0 | Non-rolling (0) means the session ID cookie is only set when the session is first created. Rolling (non-0) means the session ID cookie will be re-set on every response after any part of the session has been touched.
cookie_maxage | -1 | This will be used to set the session ID cookie's Max-Age and Expires attributes. -1 means the cookie will have no Max-Age or Expires attributes.
max_inactive_secs | SESSIONS_DEFAULT_MAX_INACTIVE_SECS | This is the maximum amount of stale time in seconds before a session is marked as expired (to be purged) on the server-side. -1 means the session will never expire server-side. This should probably be set equal to cookie_maxage unless that value is -1.

Note
  These settings should not be changed directly. See the Sessions Plugin API section for functions to manage these settings.

# The Internals

The session database is stored as a linked list pointed to by soap_sessions (accessible by calling soap_get_sessions_head()). Session nodes are of type struct soap_session and are declared as:

struct soap_session
{
struct soap_session *next;
const char *id;
struct soap_session_var *session_vars;
struct soap_session_var *session_vars_tail;
int num_session_vars; // the total number of session_vars we have in this session
long cookie_maxage; // client time in seconds before the cookie expires (-1 for session cookie)
int rolling; // whether or not we should set the cookie's maxage on every response
time_t last_touched; // time that we last touched this session or its vars
long max_inactive_secs; // server time in seconds before inactive session expires (-1 to never expire)
// this should usually be at least as high as cookie_maxage
};
soap_session_var
A session variable node. Session variables are name-value pairs.
Definition sessions.h:104
soap_session::next
struct soap_session * next
Definition sessions.h:87
soap_session::session_vars
struct soap_session_var * session_vars
Definition sessions.h:89
soap_session::session_vars_tail
struct soap_session_var * session_vars_tail
Definition sessions.h:90
soap_session::num_session_vars
int num_session_vars
Definition sessions.h:91
soap_session::rolling
int rolling
Definition sessions.h:93
soap_session::last_touched
time_t last_touched
Definition sessions.h:94
soap_session::max_inactive_secs
long max_inactive_secs
Definition sessions.h:95
soap_session::cookie_maxage
long cookie_maxage
Definition sessions.h:92
soap_session::id
const char * id
Definition sessions.h:88

The session_vars member is a pointer to the session's linked list of session variables. Session variable nodes are of type struct soap_session_var and are declared as:

struct soap_session_var
{
struct soap_session_var *next;
const char *name;
const char *value;
};
soap_session_var::value
const char * value
Definition sessions.h:107
soap_session_var::next
struct soap_session_var * next
Definition sessions.h:105
soap_session_var::name
const char * name
Definition sessions.h:106