]>
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
):
39 def set_expires(self
, seconds
):
41 self
.add_header("Cache-Control", "max-age=%s, must-revalidate" % seconds
)
44 expires
= datetime
.datetime
.utcnow() + datetime
.timedelta(seconds
=seconds
)
45 self
.add_header("Expires", expires
)
47 def write_error(self
, status_code
, **kwargs
):
48 # Translate code into message
50 message
= http
.client
.responses
[status_code
]
54 self
.render("error.html", status_code
=status_code
, message
=message
, **kwargs
)
56 def xsrf_form_html(self
, *args
, **kwargs
):
57 # Set Vary: Cookie header
58 self
.add_header("Vary", "Cookie")
60 return super().xsrf_form_html(*args
, **kwargs
)
64 # Return hostname in production
65 if self
.request
.host
.endswith("ipfire.org"):
66 return self
.request
.host
68 # Remove the development prefix
69 subdomain
, delimier
, domain
= self
.request
.host
.partition(".")
71 return "%s.ipfire.org" % subdomain
73 # Return whatever it is
74 return self
.request
.host
76 def get_template_namespace(self
):
77 ns
= tornado
.web
.RequestHandler
.get_template_namespace(self
)
79 now
= datetime
.date
.today()
82 "backend" : self
.backend
,
83 "debug" : self
.application
.settings
.get("debug", False),
84 "format_size" : util
.format_size
,
85 "format_time" : util
.format_time
,
86 "hostname" : self
.hostname
,
93 def get_remote_ip(self
):
94 # Fix for clients behind a proxy that sends "X-Forwarded-For".
95 remote_ips
= self
.request
.remote_ip
.split(", ")
97 for remote_ip
in remote_ips
:
99 addr
= ipaddress
.ip_address(remote_ip
)
101 # Skip invalid IP addresses.
104 # Check if the given IP address is from a
111 # Return the last IP if nothing else worked
112 return remote_ips
.pop()
115 def current_address(self
):
116 address
= self
.get_remote_ip()
119 return util
.Address(self
.backend
, address
)
122 def current_country_code(self
):
123 if self
.current_address
:
124 return self
.current_address
.country_code
126 def get_argument_int(self
, *args
, **kwargs
):
127 arg
= self
.get_argument(*args
, **kwargs
)
129 if arg
is None or arg
== "":
135 raise tornado
.web
.HTTPError(400, "Could not convert integer: %s" % arg
)
137 def get_argument_float(self
, *args
, **kwargs
):
138 arg
= self
.get_argument(*args
, **kwargs
)
140 if arg
is None or arg
== "":
146 raise tornado
.web
.HTTPError(400, "Could not convert float: %s" % arg
)
148 def get_argument_date(self
, arg
, *args
, **kwargs
):
149 value
= self
.get_argument(arg
, *args
, **kwargs
)
154 return dateutil
.parser
.parse(value
)
156 raise tornado
.web
.HTTPError(400)
158 def get_file(self
, name
):
160 file = self
.request
.files
[name
][0]
162 return file["filename"], file["body"], file["content_type"]
168 def get_current_user(self
):
169 session_id
= self
.get_cookie("session_id")
173 # Get account from the session object
174 account
= self
.backend
.accounts
.get_by_session(session_id
, self
.request
.host
)
176 # If the account was not found or the session was not valid
177 # any more, we will remove the cookie.
179 self
.clear_cookie("session_id")
185 return self
.application
.backend
189 return self
.backend
.db
193 return self
.backend
.accounts
197 return self
.backend
.downloads
201 return self
.backend
.fireinfo
205 return self
.backend
.iuse
209 return self
.backend
.memcache
213 return self
.backend
.mirrors
217 return self
.backend
.netboot
221 return self
.backend
.releases
225 return self
.backend
.talk
228 class APIHandler(BaseHandler
):
229 def check_xsrf_cookie(self
):
231 Do nothing here, because we cannot verify the XSRF token
236 class NotFoundHandler(BaseHandler
):
238 # Raises 404 as soon as it is called
239 raise tornado
.web
.HTTPError(404)
242 class ErrorHandler(BaseHandler
):
244 Raises any error we want
250 raise tornado
.web
.HTTPError(400)
252 raise tornado
.web
.HTTPError(code
)