00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00030 #ifndef DISABLE_CGI
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <stdbool.h>
00035 #include <string.h>
00036 #include <stdarg.h>
00037 #include <unistd.h>
00038 #ifndef _WIN32
00039 #include <dirent.h>
00040 #endif
00041 #include "qDecoder.h"
00042 #include "qInternal.h"
00043
00044 #ifdef _WIN32
00045 #define SESSION_DEFAULT_REPOSITORY "C:\\Windows\\Temp"
00046 #else
00047 #define SESSION_DEFAULT_REPOSITORY "/tmp"
00048 #endif
00049
00050 #define SESSION_ID "QSESSIONID"
00051 #define SESSION_PREFIX "qsession-"
00052 #define SESSION_STORAGE_EXTENSION ".properties"
00053 #define SESSION_TIMEOUT_EXTENSION ".expire"
00054 #define SESSION_TIMETOCLEAR_FILENAME "qsession-timetoclear"
00055
00056 #define INTER_PREFIX "_Q_"
00057 #define INTER_SESSIONID INTER_PREFIX "SESSIONID"
00058 #define INTER_SESSION_REPO INTER_PREFIX "REPOSITORY"
00059 #define INTER_CREATED_SEC INTER_PREFIX "CREATED"
00060 #define INTER_INTERVAL_SEC INTER_PREFIX "INTERVAL"
00061 #define INTER_CONNECTIONS INTER_PREFIX "CONNECTIONS"
00062
00063 #define SESSION_DEFAULT_TIMEOUT_INTERVAL (30 * 60)
00064
00065 static bool _clearRepository(const char *session_repository_path);
00066 static int _isValidSession(const char *filepath);
00067 static bool _updateTimeout(const char *filepath, time_t timeout_interval);
00068
00082 Q_ENTRY *qSessionInit(Q_ENTRY *request, const char *dirpath) {
00083
00084 if (qCgiResponseGetContentType(request) != NULL) {
00085 DEBUG("Should be called before qRequestSetContentType().");
00086 return NULL;
00087 }
00088
00089 Q_ENTRY *session = qEntryInit();
00090 if(session == NULL) return NULL;
00091
00092
00093 bool new_session;
00094 char *sessionkey;
00095 if(qEntryGetStr(request, SESSION_ID) != NULL) {
00096 sessionkey = strdup(qEntryGetStr(request, SESSION_ID));
00097 new_session = false;
00098 } else {
00099 sessionkey = qStrUnique(getenv("REMOTE_ADDR"));
00100 new_session = true;
00101 }
00102
00103
00104 char session_repository_path[MAX_PATHLEN];
00105 char session_storage_path[MAX_PATHLEN];
00106 char session_timeout_path[MAX_PATHLEN];
00107 time_t session_timeout_interval = (time_t)SESSION_DEFAULT_TIMEOUT_INTERVAL;
00108
00109 if (dirpath != NULL) qStrCpy(session_repository_path, sizeof(session_repository_path), dirpath, sizeof(session_repository_path));
00110 else qStrCpy(session_repository_path, sizeof(session_repository_path), SESSION_DEFAULT_REPOSITORY, sizeof(session_repository_path));
00111 snprintf(session_storage_path, sizeof(session_storage_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
00112 snprintf(session_timeout_path, sizeof(session_timeout_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
00113
00114
00115 if (new_session == false) {
00116 int valid = _isValidSession(session_timeout_path);
00117 if (valid <= 0) {
00118 if(valid < 0) {
00119 _q_unlink(session_storage_path);
00120 _q_unlink(session_timeout_path);
00121 }
00122
00123
00124 free(sessionkey);
00125 sessionkey = qStrUnique(getenv("REMOTE_ADDR"));
00126 snprintf(session_storage_path, sizeof(session_storage_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
00127 snprintf(session_timeout_path, sizeof(session_timeout_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
00128
00129
00130 new_session = true;
00131 }
00132 }
00133
00134
00135 if (new_session == true) {
00136 qCgiResponseSetCookie(request, SESSION_ID, sessionkey, 0, "/", NULL, NULL);
00137 qEntryPutStr(request, SESSION_ID, sessionkey, true);
00138
00139
00140 char created_sec[10+1];
00141 snprintf(created_sec, sizeof(created_sec), "%ld", (long int)time(NULL));
00142 qEntryPutStr(session, INTER_SESSIONID, sessionkey, false);
00143 qEntryPutStr(session, INTER_SESSION_REPO, session_repository_path, false);
00144 qEntryPutStr(session, INTER_CREATED_SEC, created_sec, false);
00145 qEntryPutInt(session, INTER_CONNECTIONS, 1, false);
00146
00147
00148 qSessionSetTimeout(session, session_timeout_interval);
00149 } else {
00150
00151
00152 qEntryLoad(session, session_storage_path, '=', true);
00153
00154
00155 int conns = qEntryGetInt(session, INTER_CONNECTIONS);
00156 qEntryPutInt(session, INTER_CONNECTIONS, ++conns, true);
00157
00158
00159 qSessionSetTimeout(session, qEntryGetInt(session, INTER_INTERVAL_SEC));
00160 }
00161
00162 free(sessionkey);
00163
00164
00165 return session;
00166 }
00167
00178 bool qSessionSetTimeout(Q_ENTRY *session, time_t seconds) {
00179 if (seconds <= 0) return false;
00180 qEntryPutInt(session, INTER_INTERVAL_SEC, (int)seconds, true);
00181 return true;
00182 }
00183
00193 const char *qSessionGetId(Q_ENTRY *session) {
00194 return qEntryGetStr(session, INTER_SESSIONID);
00195 }
00196
00204 time_t qSessionGetCreated(Q_ENTRY *session) {
00205 const char *created = qEntryGetStr(session, INTER_CREATED_SEC);
00206 return (time_t)atol(created);
00207 }
00208
00216 bool qSessionSave(Q_ENTRY *session) {
00217 const char *sessionkey = qEntryGetStr(session, INTER_SESSIONID);
00218 const char *session_repository_path = qEntryGetStr(session, INTER_SESSION_REPO);
00219 int session_timeout_interval = qEntryGetInt(session, INTER_INTERVAL_SEC);
00220 if(sessionkey == NULL || session_repository_path == NULL) return false;
00221
00222 char session_storage_path[MAX_PATHLEN];
00223 char session_timeout_path[MAX_PATHLEN];
00224 snprintf(session_storage_path, sizeof(session_storage_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
00225 snprintf(session_timeout_path, sizeof(session_timeout_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
00226
00227 if (qEntrySave(session, session_storage_path, '=', true) == false) {
00228 DEBUG("Can't save session file %s", session_storage_path);
00229 return false;
00230 }
00231 if (_updateTimeout(session_timeout_path, session_timeout_interval) == 0) {
00232 DEBUG("Can't update file %s", session_timeout_path);
00233 return false;
00234 }
00235
00236 _clearRepository(session_repository_path);
00237 return true;
00238 }
00239
00251 bool qSessionDestroy(Q_ENTRY *session) {
00252 const char *sessionkey = qEntryGetStr(session, INTER_SESSIONID);
00253 const char *session_repository_path = qEntryGetStr(session, "INTER_SESSION_REPO");
00254 if(sessionkey == NULL || session_repository_path == NULL) {
00255 if(session != NULL) qEntryFree(session);
00256 return false;
00257 }
00258
00259 char session_storage_path[MAX_PATHLEN];
00260 char session_timeout_path[MAX_PATHLEN];
00261 snprintf(session_storage_path, sizeof(session_storage_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
00262 snprintf(session_timeout_path, sizeof(session_timeout_path), "%s/%s%s%s", session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
00263
00264 _q_unlink(session_storage_path);
00265 _q_unlink(session_timeout_path);
00266
00267 if(session != NULL) qEntryFree(session);
00268 return true;
00269 }
00270
00271 static bool _clearRepository(const char *session_repository_path) {
00272 #ifdef _WIN32
00273 return false;
00274 #else
00275
00276 DIR *dp;
00277 if ((dp = opendir(session_repository_path)) == NULL) {
00278 DEBUG("Can't open session repository %s", session_repository_path);
00279 return false;
00280 }
00281
00282 struct dirent *dirp;
00283 while((dirp = readdir(dp)) != NULL) {
00284 if (strstr(dirp->d_name, SESSION_PREFIX) && strstr(dirp->d_name, SESSION_TIMEOUT_EXTENSION)) {
00285 char timeoutpath[MAX_PATHLEN];
00286 snprintf(timeoutpath, sizeof(timeoutpath), "%s/%s", session_repository_path, dirp->d_name);
00287 if (_isValidSession(timeoutpath) <= 0) {
00288
00289 _q_unlink(timeoutpath);
00290
00291
00292 timeoutpath[strlen(timeoutpath) - strlen(SESSION_TIMEOUT_EXTENSION)] = '\0';
00293 strcat(timeoutpath, SESSION_STORAGE_EXTENSION);
00294 _q_unlink(timeoutpath);
00295 }
00296 }
00297 }
00298 closedir(dp);
00299
00300 return true;
00301 #endif
00302 }
00303
00304
00305 static int _isValidSession(const char *filepath) {
00306 time_t timeout, timenow;
00307 double timediff;
00308
00309 if ((timeout = (time_t)qCountRead(filepath)) == 0) return 0;
00310
00311 timenow = time(NULL);
00312 timediff = difftime(timeout, timenow);
00313
00314 if (timediff >= 0) return 1;
00315 return -1;
00316 }
00317
00318
00319 static bool _updateTimeout(const char *filepath, time_t timeout_interval) {
00320 if(timeout_interval <= 0) return false;
00321
00322 if(qCountSave(filepath, time(NULL) + timeout_interval) <= 0) return false;
00323 return true;
00324 }
00325
00326 #endif