Skip to content

Commit

Permalink
move middlewares to titiler.core (#365)
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentsarago authored Sep 1, 2021
1 parent 652b20d commit 131f500
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 118 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release Notes

## Next

### titiler.core

- move `titiler.application.middleware` to `titiler.core.middleware` (https://github.com/developmentseed/titiler/pull/365)

## 0.3.7 (2021-09-01)

### titiler.core
Expand Down
10 changes: 5 additions & 5 deletions src/titiler/application/titiler/application/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
from brotli_asgi import BrotliMiddleware

from titiler.application.custom import templates
from titiler.application.middleware import (
from titiler.application.routers import cog, mosaic, stac, tms
from titiler.application.settings import ApiSettings
from titiler.application.version import __version__ as titiler_version
from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
from titiler.core.middleware import (
CacheControlMiddleware,
LoggerMiddleware,
LowerCaseQueryStringMiddleware,
TotalTimeMiddleware,
)
from titiler.application.routers import cog, mosaic, stac, tms
from titiler.application.settings import ApiSettings
from titiler.application.version import __version__ as titiler_version
from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
from titiler.mosaic.errors import MOSAIC_STATUS_CODES

from fastapi import FastAPI
Expand Down
115 changes: 6 additions & 109 deletions src/titiler/application/titiler/application/middleware.py
Original file line number Diff line number Diff line change
@@ -1,111 +1,8 @@
"""Titiler middlewares."""

import logging
import re
import time
from typing import Optional, Set

from fastapi.logger import logger

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.types import ASGIApp


class CacheControlMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add CacheControl in response headers."""

def __init__(
self,
app: ASGIApp,
cachecontrol: Optional[str] = None,
exclude_path: Optional[Set[str]] = None,
) -> None:
"""Init Middleware.
Args:
app (ASGIApp): starlette/FastAPI application.
cachecontrol (str): Cache-Control string to add to the response.
exclude_path (set): Set of regex expression to use to filter the path.
"""
super().__init__(app)
self.cachecontrol = cachecontrol
self.exclude_path = exclude_path or set()

async def dispatch(self, request: Request, call_next):
"""Add cache-control."""
response = await call_next(request)
if self.cachecontrol and not response.headers.get("Cache-Control"):
for path in self.exclude_path:
if re.match(path, request.url.path):
return response

if request.method in ["HEAD", "GET"] and response.status_code < 500:
response.headers["Cache-Control"] = self.cachecontrol

return response


class TotalTimeMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add Total process time in response headers."""

async def dispatch(self, request: Request, call_next):
"""Add X-Process-Time."""
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
timings = response.headers.get("Server-Timing")
app_time = "total;dur={}".format(round(process_time * 1000, 2))
response.headers["Server-Timing"] = (
f"{timings}, {app_time}" if timings else app_time
)
return response


class LoggerMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add logging."""

def __init__(
self, app: ASGIApp, querystrings: bool = False, headers: bool = False,
) -> None:
"""Init Middleware."""
super().__init__(app)
self.logger = logger
logger.setLevel(logging.DEBUG)

self.querystrings = querystrings
self.headers = headers

async def dispatch(self, request: Request, call_next):
"""Add logs."""
self.logger.debug(str(request.url))
qs = dict(request.query_params)
if qs and self.querystrings:
self.logger.debug(qs)
if self.headers:
self.logger.debug(dict(request.headers))

response = await call_next(request)
return response


class LowerCaseQueryStringMiddleware(BaseHTTPMiddleware):
"""Middleware to make URL parameters case-insensitive.
taken from: https://github.com/tiangolo/fastapi/issues/826
"""

async def dispatch(self, request: Request, call_next):
"""dispatch request."""

self.DECODE_FORMAT = "latin-1"

query_string = ""
for k in request.query_params:
query_string += k.lower() + "=" + request.query_params[k] + "&"

query_string = query_string[:-1]
request.scope["query_string"] = query_string.encode(self.DECODE_FORMAT)

response = await call_next(request)
return response
from titiler.core.middleware import ( # noqa
CacheControlMiddleware,
LoggerMiddleware,
LowerCaseQueryStringMiddleware,
TotalTimeMiddleware,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Test titiler.middleware.CacheControlMiddleware."""
"""Test titiler.core.CacheControlMiddleware."""


from titiler.application.middleware import CacheControlMiddleware
from titiler.core.middleware import CacheControlMiddleware

from fastapi import FastAPI, Path

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Test titiler.application.middleware.LowerCaseQueryStringMiddleware."""
"""Test titiler.core.middleware.LowerCaseQueryStringMiddleware."""


from titiler.application.middleware import LowerCaseQueryStringMiddleware
from titiler.core.middleware import LowerCaseQueryStringMiddleware

from fastapi import FastAPI, Query

Expand Down
111 changes: 111 additions & 0 deletions src/titiler/core/titiler/core/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Titiler middlewares."""

import logging
import re
import time
from typing import Optional, Set

from fastapi.logger import logger

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.types import ASGIApp


class CacheControlMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add CacheControl in response headers."""

def __init__(
self,
app: ASGIApp,
cachecontrol: Optional[str] = None,
exclude_path: Optional[Set[str]] = None,
) -> None:
"""Init Middleware.
Args:
app (ASGIApp): starlette/FastAPI application.
cachecontrol (str): Cache-Control string to add to the response.
exclude_path (set): Set of regex expression to use to filter the path.
"""
super().__init__(app)
self.cachecontrol = cachecontrol
self.exclude_path = exclude_path or set()

async def dispatch(self, request: Request, call_next):
"""Add cache-control."""
response = await call_next(request)
if self.cachecontrol and not response.headers.get("Cache-Control"):
for path in self.exclude_path:
if re.match(path, request.url.path):
return response

if request.method in ["HEAD", "GET"] and response.status_code < 500:
response.headers["Cache-Control"] = self.cachecontrol

return response


class TotalTimeMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add Total process time in response headers."""

async def dispatch(self, request: Request, call_next):
"""Add X-Process-Time."""
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
timings = response.headers.get("Server-Timing")
app_time = "total;dur={}".format(round(process_time * 1000, 2))
response.headers["Server-Timing"] = (
f"{timings}, {app_time}" if timings else app_time
)
return response


class LoggerMiddleware(BaseHTTPMiddleware):
"""MiddleWare to add logging."""

def __init__(
self, app: ASGIApp, querystrings: bool = False, headers: bool = False,
) -> None:
"""Init Middleware."""
super().__init__(app)
self.logger = logger
logger.setLevel(logging.DEBUG)

self.querystrings = querystrings
self.headers = headers

async def dispatch(self, request: Request, call_next):
"""Add logs."""
self.logger.debug(str(request.url))
qs = dict(request.query_params)
if qs and self.querystrings:
self.logger.debug(qs)
if self.headers:
self.logger.debug(dict(request.headers))

response = await call_next(request)
return response


class LowerCaseQueryStringMiddleware(BaseHTTPMiddleware):
"""Middleware to make URL parameters case-insensitive.
taken from: https://github.com/tiangolo/fastapi/issues/826
"""

async def dispatch(self, request: Request, call_next):
"""dispatch request."""

self.DECODE_FORMAT = "latin-1"

query_string = ""
for k in request.query_params:
query_string += k.lower() + "=" + request.query_params[k] + "&"

query_string = query_string[:-1]
request.scope["query_string"] = query_string.encode(self.DECODE_FORMAT)

response = await call_next(request)
return response

0 comments on commit 131f500

Please sign in to comment.