Blob Blame Raw

import time
import uuid
import threading


class Session:
  def __init__(self, manager, user_id):
    self.manager = manager
    self.server = manager.server
    self.id = uuid.uuid4().hex
    self.user_id = user_id
    self.maxtime = self.server.config['session']['time']
    self.touch()
        
  def touch(self):
    self.time = time.monotonic()

  def expired(self):
    return self.time + self.maxtime < time.monotonic()
        

class SessionManager:
  COOKIE='session'
  
  def __init__(self, server):
    self.server = server
    self.lock = threading.Lock()
    self.sessions = dict()
    self.timer = threading.Timer(server.config['session']['time']*0.1, self.remove_expired)
    self.timer.start()
    
  def remove_expired(self):
    with self.lock:
      remove = list()
      for id, session in self.sessions.items():
        if session.expired():
          remove.append(id)
      for id in remove:
        del self.sessions[id]
        
  def delete_by_user_id(self, user_id):
    assert(type(user_id) is int)
    with self.lock:
      remove = list()
      for id, session in self.sessions.items():
        if session.user_id == user_id:
          remove.append(id)
      for id in remove:
        del self.sessions[id]
  
  def add_cookie_header(self, request):
    remove = list()
    j = 0
    for i in request.answer.headers:
      if i[0] == 'Set-Cookie':
        remove.insert(0, j)
      j += 1
    for i in remove:
      del request.answer.headers[i]
    
    value = None
    if request.session:
      path = self.server.config['urlprefix'] + '/'
      value = '%s=%s; Path=%s; Max-Age=%d; Secure' \
            % (self.COOKIE, request.session.id, path, request.session.maxtime)
    else:
      value = '%s=; Expires=Thu, 01 Jan 1970 00:00:00 GMT' \
            % (self.COOKIE)
    request.answer.headers.append( ('Set-Cookie', value) )
  
  def create_session(self, request, user_id):
    assert(type(user_id) is int)
    assert(user_id)
    with self.lock:
      session = Session(self, user_id)
      self.sessions[session.id] = session
      request.session = session
    self.add_cookie_header(request)

  def attach_session(self, request):
    request.session = None
    
    # parse cookie
    id = None
    for i in request.cookie.split(';'):
      j = i.split('=')
      if len(j) == 2:
        if j[0].strip() == self.COOKIE:
          if not id is None: # double cookie equals no cookie
            id = None
            break
          id = j[1].strip()

    if id:
      with self.lock:
        session = self.sessions.get(id)
        if session:
          if session.expired():
            del self.sessions[id]
          else:
            session.touch()
            request.session = session

    if request.session or request.cookie: # need we add new or delete existant cookie
      self.add_cookie_header(request)

  def close_session(self, request):
    if request.session:
      with self.lock:
        if request.session.id in self.sessions:
          del self.sessions[request.session.id]
      request.session = None
    if request.cookie:
      self.add_cookie_header(request)