openwebrx-clone/owrx/http.py
2020-04-25 21:55:52 +02:00

129 lines
4.7 KiB
Python

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
from owrx.controllers.settings import SettingsController, GeneralSettingsController, SdrSettingsController
from owrx.controllers.session import SessionController
from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import re
from abc import ABC, abstractmethod
from http.cookies import SimpleCookie
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class RequestHandler(BaseHTTPRequestHandler):
def __init__(self, request, client_address, server):
self.router = Router()
super().__init__(request, client_address, server)
def log_message(self, format, *args):
logger.debug("%s - - [%s] %s", self.address_string(), self.log_date_time_string(), format % args)
def do_GET(self):
self.router.route(self, "GET")
def do_POST(self):
self.router.route(self, "POST")
class Request(object):
def __init__(self, url, method, cookies):
self.path = url.path
self.query = parse_qs(url.query)
self.matches = None
self.method = method
self.cookies = cookies
def setMatches(self, matches):
self.matches = matches
class Route(ABC):
def __init__(self, controller, method="GET", options=None):
self.controller = controller
self.controllerOptions = options if options is not None else {}
self.method = method
@abstractmethod
def matches(self, request):
pass
class StaticRoute(Route):
def __init__(self, route, controller, method="GET", options=None):
self.route = route
super().__init__(controller, method, options)
def matches(self, request):
return request.path == self.route and self.method == request.method
class RegexRoute(Route):
def __init__(self, regex, controller, method="GET", options=None):
self.regex = re.compile(regex)
super().__init__(controller, method, options)
def matches(self, request):
matches = self.regex.match(request.path)
# this is probably not the cleanest way to do it...
request.setMatches(matches)
return matches is not None and self.method == request.method
class Router(object):
def __init__(self):
self.routes = [
StaticRoute("/", IndexController),
StaticRoute("/status", StatusController),
StaticRoute("/status.json", StatusController, options={"action": "jsonAction"}),
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),
StaticRoute("/settings", SettingsController),
StaticRoute("/generalsettings", GeneralSettingsController),
StaticRoute("/generalsettings", GeneralSettingsController, method="POST", options={"action": "processFormData"}),
StaticRoute("/sdrsettings", SdrSettingsController),
StaticRoute("/login", SessionController, options={"action": "loginAction"}),
StaticRoute("/login", SessionController, method="POST", options={"action": "processLoginAction"}),
StaticRoute("/logout", SessionController, options={"action": "logoutAction"}),
]
def find_route(self, request):
for r in self.routes:
if r.matches(request):
return r
def route(self, handler, method):
url = urlparse(handler.path)
cookies = SimpleCookie()
if "Cookie" in handler.headers:
cookies.load(handler.headers["Cookie"])
request = Request(url, method, cookies)
route = self.find_route(request)
if route is not None:
controller = route.controller
controller(handler, request, route.controllerOptions).handle_request()
else:
handler.send_error(404, "Not Found", "The page you requested could not be found.")