openwebrx-clone/owrx/http.py

127 lines
4.5 KiB
Python
Raw Normal View History

from owrx.controllers.status import StatusController
from owrx.controllers.template import (
IndexController,
MapController,
FeatureController
)
from owrx.controllers.assets import (
OwrxAssetsController,
AprsSymbolsController
)
from owrx.controllers.websocket import WebSocketController
from owrx.controllers.api import ApiController
from owrx.controllers.metrics import MetricsController
2020-03-26 20:52:34 +00:00
from owrx.controllers.settings import SettingsController
2020-02-23 18:23:18 +00:00
from owrx.controllers.session import SessionController
2019-05-03 20:59:24 +00:00
from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import re
2020-02-23 16:53:02 +00:00
from abc import ABC, abstractmethod
2020-02-23 20:52:13 +00:00
from http.cookies import SimpleCookie
2019-05-03 20:59:24 +00:00
2019-05-10 19:50:58 +00:00
import logging
2019-05-10 19:50:58 +00:00
logger = logging.getLogger(__name__)
2019-09-22 18:51:33 +00:00
logger.setLevel(logging.INFO)
2019-05-10 19:50:58 +00:00
2019-05-03 20:59:24 +00:00
class RequestHandler(BaseHTTPRequestHandler):
def __init__(self, request, client_address, server):
self.router = Router()
super().__init__(request, client_address, server)
2019-09-22 18:51:33 +00:00
def log_message(self, format, *args):
2019-09-23 01:15:24 +00:00
logger.debug("%s - - [%s] %s", self.address_string(), self.log_date_time_string(), format % args)
2019-09-22 18:51:33 +00:00
2019-05-03 20:59:24 +00:00
def do_GET(self):
2020-02-23 19:25:36 +00:00
self.router.route(self, "GET")
def do_POST(self):
self.router.route(self, "POST")
2019-05-03 20:59:24 +00:00
class Request(object):
2020-02-23 20:52:13 +00:00
def __init__(self, url, method, cookies):
2020-02-23 16:53:02 +00:00
self.path = url.path
self.query = parse_qs(url.query)
self.matches = None
2020-02-23 19:25:36 +00:00
self.method = method
2020-02-23 20:52:13 +00:00
self.cookies = cookies
2020-02-23 16:53:02 +00:00
def setMatches(self, matches):
self.matches = matches
2020-02-23 16:53:02 +00:00
class Route(ABC):
2020-02-23 19:25:36 +00:00
def __init__(self, controller, method="GET", options=None):
2020-02-23 16:53:02 +00:00
self.controller = controller
2020-02-23 19:25:36 +00:00
self.controllerOptions = options if options is not None else {}
self.method = method
2020-02-23 16:53:02 +00:00
@abstractmethod
def matches(self, request):
pass
class StaticRoute(Route):
2020-02-23 19:25:36 +00:00
def __init__(self, route, controller, method="GET", options=None):
2020-02-23 16:53:02 +00:00
self.route = route
2020-02-23 19:25:36 +00:00
super().__init__(controller, method, options)
2020-02-23 16:53:02 +00:00
def matches(self, request):
2020-02-23 19:25:36 +00:00
return request.path == self.route and self.method == request.method
2020-02-23 16:53:02 +00:00
class RegexRoute(Route):
2020-02-23 19:25:36 +00:00
def __init__(self, regex, controller, method="GET", options=None):
2020-02-23 16:53:02 +00:00
self.regex = re.compile(regex)
2020-02-23 19:25:36 +00:00
super().__init__(controller, method, options)
2020-02-23 16:53:02 +00:00
def matches(self, request):
matches = self.regex.match(request.path)
# this is probably not the cleanest way to do it...
request.setMatches(matches)
2020-02-23 19:25:36 +00:00
return matches is not None and self.method == request.method
2020-02-23 16:53:02 +00:00
2019-05-03 20:59:24 +00:00
class Router(object):
2020-02-23 16:53:02 +00:00
def __init__(self):
self.routes = [
StaticRoute("/", IndexController),
StaticRoute("/status", StatusController),
2020-02-23 19:25:36 +00:00
StaticRoute("/status.json", StatusController, options={"action": "jsonAction"}),
2020-02-23 16:53:02 +00:00
RegexRoute("/static/(.+)", OwrxAssetsController),
RegexRoute("/aprs-symbols/(.+)", AprsSymbolsController),
StaticRoute("/ws/", WebSocketController),
RegexRoute("(/favicon.ico)", OwrxAssetsController),
# backwards compatibility for the sdr.hu portal
RegexRoute("(/gfx/openwebrx-avatar.png)", OwrxAssetsController),
StaticRoute("/map", MapController),
StaticRoute("/features", FeatureController),
StaticRoute("/api/features", ApiController),
StaticRoute("/metrics", MetricsController),
2020-03-26 20:52:34 +00:00
StaticRoute("/admin", SettingsController),
2020-03-26 22:04:02 +00:00
StaticRoute("/admin", SettingsController, method="POST", options={"action": "processFormData"}),
2020-02-23 19:25:36 +00:00
StaticRoute("/login", SessionController, options={"action": "loginAction"}),
StaticRoute("/login", SessionController, method="POST", options={"action": "processLoginAction"}),
StaticRoute("/logout", SessionController, options={"action": "logoutAction"}),
2020-02-23 16:53:02 +00:00
]
def find_route(self, request):
for r in self.routes:
if r.matches(request):
return r
2020-02-23 19:25:36 +00:00
def route(self, handler, method):
url = urlparse(handler.path)
2020-02-23 20:52:13 +00:00
cookies = SimpleCookie()
if "Cookie" in handler.headers:
cookies.load(handler.headers["Cookie"])
request = Request(url, method, cookies)
2020-02-23 16:53:02 +00:00
route = self.find_route(request)
if route is not None:
controller = route.controller
controller(handler, request, route.controllerOptions).handle_request()
2019-05-03 20:59:24 +00:00
else:
handler.send_error(404, "Not Found", "The page you requested could not be found.")