]>
git.ipfire.org Git - ipfire.org.git/blob - src/web/base.py
13 from ..decorators
import *
16 class ratelimit(object):
17 def __init__(self
, minutes
=15, requests
=180):
18 self
.minutes
= minutes
19 self
.requests
= requests
21 def __call__(self
, method
):
22 @functools.wraps(method
)
23 def wrapper(handler
, *args
, **kwargs
):
24 # Pass the request to the rate limiter and get a request object
25 req
= handler
.backend
.ratelimiter
.handle_request(handler
.request
,
26 handler
, minutes
=self
.minutes
, limit
=self
.requests
)
28 # If the rate limit has been reached, we won't allow
29 # processing the request and therefore send HTTP error code 429.
30 if req
.is_ratelimited():
31 raise tornado
.web
.HTTPError(429, "Rate limit exceeded")
33 return method(handler
, *args
, **kwargs
)
38 class BaseHandler(tornado
.web
.RequestHandler
):
40 # Mark this as private when someone is logged in
42 self
.set_header("Cache-Control", "private")
44 # Always send Vary: Cookie
45 self
.set_header("Vary", "Cookie")
47 def set_expires(self
, seconds
):
49 self
.add_header("Cache-Control", "max-age=%s, must-revalidate" % seconds
)
52 expires
= datetime
.datetime
.utcnow() + datetime
.timedelta(seconds
=seconds
)
53 self
.set_header("Expires", expires
)
55 def write_error(self
, status_code
, **kwargs
):
56 # Translate code into message
58 message
= http
.client
.responses
[status_code
]
62 self
.render("error.html", status_code
=status_code
, message
=message
, **kwargs
)
66 # Return hostname in production
67 if self
.request
.host
.endswith("ipfire.org"):
68 return self
.request
.host
70 # Remove the development prefix
71 subdomain
, delimier
, domain
= self
.request
.host
.partition(".")
73 return "%s.ipfire.org" % subdomain
75 # Return whatever it is
76 return self
.request
.host
78 def get_template_namespace(self
):
79 ns
= tornado
.web
.RequestHandler
.get_template_namespace(self
)
81 now
= datetime
.date
.today()
84 "backend" : self
.backend
,
85 "debug" : self
.application
.settings
.get("debug", False),
86 "format_size" : util
.format_size
,
87 "format_time" : util
.format_time
,
88 "hostname" : self
.hostname
,
95 def get_remote_ip(self
):
96 # Fix for clients behind a proxy that sends "X-Forwarded-For".
97 remote_ips
= self
.request
.remote_ip
.split(", ")
99 for remote_ip
in remote_ips
:
101 addr
= ipaddress
.ip_address(remote_ip
)
103 # Skip invalid IP addresses.
106 # Check if the given IP address is from a
113 # Return the last IP if nothing else worked
114 return remote_ips
.pop()
117 def current_address(self
):
118 address
= self
.get_remote_ip()
121 return util
.Address(self
.backend
, address
)
124 def current_country_code(self
):
125 if self
.current_address
:
126 return self
.current_address
.country_code
128 def get_argument_int(self
, *args
, **kwargs
):
129 arg
= self
.get_argument(*args
, **kwargs
)
131 if arg
is None or arg
== "":
137 raise tornado
.web
.HTTPError(400, "Could not convert integer: %s" % arg
)
139 def get_argument_float(self
, *args
, **kwargs
):
140 arg
= self
.get_argument(*args
, **kwargs
)
142 if arg
is None or arg
== "":
148 raise tornado
.web
.HTTPError(400, "Could not convert float: %s" % arg
)
150 def get_argument_date(self
, arg
, *args
, **kwargs
):
151 value
= self
.get_argument(arg
, *args
, **kwargs
)
156 return dateutil
.parser
.parse(value
)
158 raise tornado
.web
.HTTPError(400)
160 def get_file(self
, name
):
162 file = self
.request
.files
[name
][0]
164 return file["filename"], file["body"], file["content_type"]
170 def get_current_user(self
):
171 session_id
= self
.get_cookie("session_id")
175 # Get account from the session object
176 account
= self
.backend
.accounts
.get_by_session(session_id
, self
.request
.host
)
178 # If the account was not found or the session was not valid
179 # any more, we will remove the cookie.
181 self
.clear_cookie("session_id")
187 return self
.application
.backend
191 return self
.backend
.db
195 return self
.backend
.accounts
199 return self
.backend
.downloads
203 return self
.backend
.fireinfo
207 return self
.backend
.iuse
211 return self
.backend
.memcache
215 return self
.backend
.mirrors
219 return self
.backend
.netboot
223 return self
.backend
.releases
226 class APIHandler(BaseHandler
):
227 def check_xsrf_cookie(self
):
229 Do nothing here, because we cannot verify the XSRF token
234 class NotFoundHandler(BaseHandler
):
236 # Raises 404 as soon as it is called
237 raise tornado
.web
.HTTPError(404)
240 class ErrorHandler(BaseHandler
):
242 Raises any error we want
248 raise tornado
.web
.HTTPError(400)
250 raise tornado
.web
.HTTPError(code
)