Browse Source

Move tweens into a module

merge-requests/64/head
Deimos 6 years ago
parent
commit
b979049235
  1. 96
      tildes/tildes/__init__.py
  2. 96
      tildes/tildes/tweens.py

96
tildes/tildes/__init__.py

@ -3,17 +3,13 @@
"""Configure and initialize the Pyramid app.""" """Configure and initialize the Pyramid app."""
from time import time
from typing import Any, Callable, Dict, Optional, Tuple
from typing import Any, Dict, Optional, Tuple
from marshmallow.exceptions import ValidationError from marshmallow.exceptions import ValidationError
from paste.deploy.config import PrefixMiddleware from paste.deploy.config import PrefixMiddleware
from prometheus_client import Histogram
from pyramid.config import Configurator from pyramid.config import Configurator
from pyramid.httpexceptions import HTTPTooManyRequests from pyramid.httpexceptions import HTTPTooManyRequests
from pyramid.registry import Registry
from pyramid.request import Request from pyramid.request import Request
from pyramid.response import Response
from redis import Redis from redis import Redis
import sentry_sdk import sentry_sdk
from sentry_sdk.integrations.pyramid import PyramidIntegration from sentry_sdk.integrations.pyramid import PyramidIntegration
@ -43,9 +39,9 @@ def main(global_config: Dict[str, str], **settings: str) -> PrefixMiddleware:
config.scan("tildes.views") config.scan("tildes.views")
config.add_tween("tildes.http_method_tween_factory")
config.add_tween("tildes.metrics_tween_factory")
config.add_tween("tildes.theme_cookie_tween_factory")
config.add_tween("tildes.tweens.http_method_tween_factory")
config.add_tween("tildes.tweens.metrics_tween_factory")
config.add_tween("tildes.tweens.theme_cookie_tween_factory")
config.add_static_view("images", "/images") config.add_static_view("images", "/images")
@ -86,90 +82,6 @@ def main(global_config: Dict[str, str], **settings: str) -> PrefixMiddleware:
return prefixed_app return prefixed_app
def http_method_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that can override the request's HTTP method."""
def method_override_tween(request: Request) -> Request:
"""Override HTTP method with one specified in header."""
valid_overrides_by_method = {"POST": ["DELETE", "PATCH", "PUT"]}
original_method = request.method.upper()
valid_overrides = valid_overrides_by_method.get(original_method, [])
override = request.headers.get("X-HTTP-Method-Override", "").upper()
if override in valid_overrides:
request.method = override
return handler(request)
return method_override_tween
def metrics_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that gathers metrics for Prometheus."""
request_histogram = Histogram(
"tildes_pyramid_requests_seconds",
"Request processing times",
labelnames=["route", "status_code", "method", "logged_in"],
)
def metrics_tween(request: Request) -> Response:
"""Gather metrics for each request."""
start_time = time()
response = handler(request)
duration = time() - start_time
# ignore requests for invalid addresses
if not request.matched_route:
return response
request_histogram.labels(
route=request.matched_route.name,
status_code=response.status_code,
method=request.method,
logged_in=str(bool(request.user)).lower(),
).observe(duration)
return response
return metrics_tween
def theme_cookie_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that sets the theme cookie."""
def theme_cookie_tween(request: Request) -> Response:
"""Set the theme cookie if needed (currently always, see comment below)."""
response = handler(request)
current_theme = request.cookies.get("theme", "")
if not current_theme and request.user:
current_theme = request.user.theme_default
# Currently, we want to always set the theme cookie. This is because we
# recently started setting the domain on this cookie (to be able to apply the
# user's theme to the Blog/Docs sites), and all older cookies won't have a
# domain set. This will basically let us convert the old no-domain cookies to
# new ones. After a decent amount of time (maybe sometime in April 2019), we
# can change this to only set the cookie when it's not already present and the
# user has a default theme set (so their default theme will work for Blog/Docs).
if current_theme:
response.set_cookie(
"theme",
current_theme,
max_age=315360000,
secure=True,
domain="." + request.domain,
)
return response
return theme_cookie_tween
def get_redis_connection(request: Request) -> Redis: def get_redis_connection(request: Request) -> Redis:
"""Return a connection to the Redis server.""" """Return a connection to the Redis server."""
socket = request.registry.settings["redis.unix_socket_path"] socket = request.registry.settings["redis.unix_socket_path"]

96
tildes/tildes/tweens.py

@ -0,0 +1,96 @@
# Copyright (c) 2019 Tildes contributors <code@tildes.net>
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Contains Pyramid "tweens", used to insert additional logic into request-handling."""
from time import time
from typing import Callable
from prometheus_client import Histogram
from pyramid.registry import Registry
from pyramid.request import Request
from pyramid.response import Response
def http_method_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that can override the request's HTTP method."""
def method_override_tween(request: Request) -> Response:
"""Override HTTP method with one specified in header."""
valid_overrides_by_method = {"POST": ["DELETE", "PATCH", "PUT"]}
original_method = request.method.upper()
valid_overrides = valid_overrides_by_method.get(original_method, [])
override = request.headers.get("X-HTTP-Method-Override", "").upper()
if override in valid_overrides:
request.method = override
return handler(request)
return method_override_tween
def metrics_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that gathers metrics for Prometheus."""
request_histogram = Histogram(
"tildes_pyramid_requests_seconds",
"Request processing times",
labelnames=["route", "status_code", "method", "logged_in"],
)
def metrics_tween(request: Request) -> Response:
"""Gather metrics for each request."""
start_time = time()
response = handler(request)
duration = time() - start_time
# ignore requests for invalid addresses
if not request.matched_route:
return response
request_histogram.labels(
route=request.matched_route.name,
status_code=response.status_code,
method=request.method,
logged_in=str(bool(request.user)).lower(),
).observe(duration)
return response
return metrics_tween
def theme_cookie_tween_factory(handler: Callable, registry: Registry) -> Callable:
# pylint: disable=unused-argument
"""Return a tween function that sets the theme cookie."""
def theme_cookie_tween(request: Request) -> Response:
"""Set the theme cookie if needed (currently always, see comment below)."""
response = handler(request)
current_theme = request.cookies.get("theme", "")
if not current_theme and request.user:
current_theme = request.user.theme_default
# Currently, we want to always set the theme cookie. This is because we
# recently started setting the domain on this cookie (to be able to apply the
# user's theme to the Blog/Docs sites), and all older cookies won't have a
# domain set. This will basically let us convert the old no-domain cookies to
# new ones. After a decent amount of time (maybe sometime in April 2019), we
# can change this to only set the cookie when it's not already present and the
# user has a default theme set (so their default theme will work for Blog/Docs).
if current_theme:
response.set_cookie(
"theme",
current_theme,
max_age=315360000,
secure=True,
domain="." + request.domain,
)
return response
return theme_cookie_tween
Loading…
Cancel
Save