Set Cache-control on all generated pages, centralize in Endpoint
[cascardo/ipsilon.git] / ipsilon / util / endpoint.py
1 # Copyright (C) 2015  Ipsilon Contributors see COPYING for license
2
3 import cherrypy
4 from ipsilon.util.log import Log
5 from ipsilon.util.user import UserSession
6 from urllib import unquote
7 try:
8     from urlparse import urlparse
9 except ImportError:
10     # pylint: disable=no-name-in-module, import-error
11     from urllib.parse import urlparse
12
13
14 class Endpoint(Log):
15     def __init__(self, site):
16         self._site = site
17         self.basepath = cherrypy.config.get('base.mount', "")
18         self.user = None
19         self.default_headers = {
20             'Cache-Control': 'no-cache, no-store, must-revalidate, private',
21             'Pragma': 'no-cache',
22         }
23         self.auth_protect = False
24
25     def get_url(self):
26         return cherrypy.url(relative=False)
27
28     def instance_base_url(self):
29         url = self.get_url()
30         s = urlparse(unquote(url))
31         return '%s://%s%s' % (s.scheme, s.netloc, self.basepath)
32
33     def _check_referer(self, referer, url):
34         r = urlparse(unquote(referer))
35         u = urlparse(unquote(url))
36         if r.scheme != u.scheme:
37             return False
38         if r.netloc != u.netloc:
39             return False
40         if r.path.startswith(self.basepath):
41             return True
42         return False
43
44     def __call__(self, *args, **kwargs):
45         # pylint: disable=star-args
46         cherrypy.response.headers.update(self.default_headers)
47
48         self.user = UserSession().get_user()
49
50         if self.auth_protect and self.user.is_anonymous:
51             raise cherrypy.HTTPError(401)
52
53         self._debug("method: %s" % cherrypy.request.method)
54         op = getattr(self, cherrypy.request.method, None)
55         if callable(op):
56             # Basic CSRF protection
57             if cherrypy.request.method != 'GET':
58                 url = self.get_url()
59                 if 'referer' not in cherrypy.request.headers:
60                     self._debug("Missing referer in %s request to %s"
61                                 % (cherrypy.request.method, url))
62                     raise cherrypy.HTTPError(403)
63                 referer = cherrypy.request.headers['referer']
64                 if not self._check_referer(referer, url):
65                     self._debug("Wrong referer %s in request to %s"
66                                 % (referer, url))
67                     raise cherrypy.HTTPError(403)
68             return op(*args, **kwargs)
69         else:
70             op = getattr(self, 'root', None)
71             if callable(op):
72                 return op(*args, **kwargs)
73
74         return self.default(*args, **kwargs)
75
76     def default(self, *args, **kwargs):
77         raise cherrypy.NotFound()
78
79     def add_subtree(self, name, page):
80         self.__dict__[name] = page
81
82     def del_subtree(self, name):
83         del self.__dict__[name]
84
85     exposed = True