From 82d77c4608b92304c7737ec4a3d5ab331efd82e9 Mon Sep 17 00:00:00 2001 From: Aditya Toshniwal Date: Thu, 5 Jul 2018 11:12:03 +0100 Subject: [PATCH] Don't create a session when the /misc/ping test endpoint is called. Fixes #3371 --- docs/en_US/release_notes_3_2.rst | 1 + web/config.py | 8 ++++ web/pgadmin/__init__.py | 4 +- web/pgadmin/browser/static/js/browser.js | 2 +- web/pgadmin/misc/__init__.py | 13 ++++-- web/pgadmin/utils/session.py | 51 ++++++++++++++++++------ 6 files changed, 61 insertions(+), 18 deletions(-) diff --git a/docs/en_US/release_notes_3_2.rst b/docs/en_US/release_notes_3_2.rst index f354780a0..8213c3655 100644 --- a/docs/en_US/release_notes_3_2.rst +++ b/docs/en_US/release_notes_3_2.rst @@ -19,4 +19,5 @@ Bug fixes | `Bug #3309 `_ - Fix Directory format support for backups. | `Bug #3319 `_ - Cleanup and fix handling of Query Tool Cancel button status. | `Bug #3363 `_ - Fix restoring of restore options for sections. +| `Bug #3371 `_ - Don't create a session when the /misc/ping test endpoint is called. | `Bug #3457 `_ - Fix debugging of procedures in EPAS packages. diff --git a/web/config.py b/web/config.py index a8a9ce013..1e3b55355 100644 --- a/web/config.py +++ b/web/config.py @@ -391,3 +391,11 @@ if (SUPPORT_SSH_TUNNEL is True and ((sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 4))): SUPPORT_SSH_TUNNEL = False + + +######################################################################### +# Skip storing session in files and cache for specific paths +######################################################################### +SESSION_SKIP_PATHS = [ + '/misc/ping' +] diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index e4c9c484a..5926559d8 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -354,7 +354,9 @@ def create_app(app_name=None): # register custom unauthorised handler. app.login_manager.unauthorized_handler(pga_unauthorised) - app.session_interface = create_session_interface(app) + app.session_interface = create_session_interface( + app, config.SESSION_SKIP_PATHS + ) # Make the Session more secure against XSS & CSRF when running in web mode if config.SERVER_MODE: diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index b26738cfe..d0efe4689 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -490,7 +490,7 @@ define('pgadmin.browser', [ // Ping the server every 5 minutes setInterval(function() { $.ajax({ - url: url_for('misc.ping'), + url: url_for('misc.cleanup'), type:'POST', success: function() {}, error: function() {}, diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index 55e3fe73a..ad4f9254b 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -74,7 +74,7 @@ class MiscModule(PgAdminModule): Returns: list: a list of url endpoints exposed to the client. """ - return ['misc.ping', 'misc.index'] + return ['misc.ping', 'misc.index', 'misc.cleanup'] # Initialise the module @@ -92,14 +92,19 @@ def index(): ########################################################################## # A special URL used to "ping" the server ########################################################################## -@blueprint.route("/ping", methods=('get', 'post')) +@blueprint.route("/ping") def ping(): """Generate a "PING" response to indicate that the server is alive.""" - driver.ping() - return "PING" +# For Garbage Collecting closed connections +@blueprint.route("/cleanup", methods=['POST']) +def cleanup(): + driver.ping() + return "" + + @blueprint.route("/explain/explain.js") def explain_js(): """ diff --git a/web/pgadmin/utils/session.py b/web/pgadmin/utils/session.py index 266f83b3c..fa313e0ad 100644 --- a/web/pgadmin/utils/session.py +++ b/web/pgadmin/utils/session.py @@ -102,10 +102,11 @@ class SessionManager(object): class CachingSessionManager(SessionManager): - def __init__(self, parent, num_to_store): + def __init__(self, parent, num_to_store, skip_paths=[]): self.parent = parent self.num_to_store = num_to_store self._cache = OrderedDict() + self.skip_paths = skip_paths def _normalize(self): if len(self._cache) > self.num_to_store: @@ -115,6 +116,12 @@ class CachingSessionManager(SessionManager): def new_session(self): session = self.parent.new_session() + + # Do not store the session if skip paths + for sp in self.skip_paths: + if request.path.startswith(sp): + return session + self._cache[session.sid] = session self._normalize() @@ -143,6 +150,11 @@ class CachingSessionManager(SessionManager): if not session: session = self.parent.get(sid, digest) + # Do not store the session if skip paths + for sp in self.skip_paths: + if request.path.startswith(sp): + return session + self._cache[sid] = session self._normalize() @@ -150,23 +162,31 @@ class CachingSessionManager(SessionManager): def put(self, session): self.parent.put(session) + + # Do not store the session if skip paths + for sp in self.skip_paths: + if request.path.startswith(sp): + return + if session.sid in self._cache: try: del self._cache[session.sid] except Exception: pass + self._cache[session.sid] = session self._normalize() class FileBackedSessionManager(SessionManager): - def __init__(self, path, secret, disk_write_delay): + def __init__(self, path, secret, disk_write_delay, skip_paths=[]): self.path = path self.secret = secret self.disk_write_delay = disk_write_delay if not os.path.exists(self.path): os.makedirs(self.path) + self.skip_paths = skip_paths def exists(self, sid): fname = os.path.join(self.path, sid) @@ -185,6 +205,11 @@ class FileBackedSessionManager(SessionManager): sid = str(uuid4()) fname = os.path.join(self.path, sid) + # Do not store the session if skip paths + for sp in self.skip_paths: + if request.path.startswith(sp): + return ManagedSession(sid=sid) + # touch the file with open(fname, 'wb'): pass @@ -233,6 +258,12 @@ class FileBackedSessionManager(SessionManager): session.last_write = current_time session.force_write = False + + # Do not store the session if skip paths + for sp in self.skip_paths: + if request.path.startswith(sp): + return + fname = os.path.join(self.path, session.sid) with open(fname, 'wb') as f: dump( @@ -242,9 +273,8 @@ class FileBackedSessionManager(SessionManager): class ManagedSessionInterface(SessionInterface): - def __init__(self, manager, skip_paths, cookie_timedelta): + def __init__(self, manager, cookie_timedelta): self.manager = manager - self.skip_paths = skip_paths self.cookie_timedelta = cookie_timedelta def get_expiration_time(self, app, session): @@ -256,11 +286,6 @@ class ManagedSessionInterface(SessionInterface): cookie_val = request.cookies.get(app.session_cookie_name) if not cookie_val or '!' not in cookie_val: - # Don't bother creating a cookie for static resources - for sp in self.skip_paths: - if request.path.startswith(sp): - return None - return self.manager.new_session() sid, digest = cookie_val.split('!', 1) @@ -301,10 +326,12 @@ def create_session_interface(app, skip_paths=[]): FileBackedSessionManager( app.config['SESSION_DB_PATH'], app.config['SECRET_KEY'], - app.config.get('PGADMIN_SESSION_DISK_WRITE_DELAY', 10) + app.config.get('PGADMIN_SESSION_DISK_WRITE_DELAY', 10), + skip_paths ), - 1000 - ), skip_paths, + 1000, + skip_paths + ), datetime.timedelta(days=1))