From 598ad2900b440891c0d260294d6c45e98c20ac3b Mon Sep 17 00:00:00 2001 From: lorenzoriches Date: Thu, 3 Jun 2021 10:17:06 +0200 Subject: [PATCH 1/8] GetCapabilities returns a 404 --- .../application/titiler/application/main.py | 3 +++ .../titiler/application/middleware.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/titiler/application/titiler/application/main.py b/titiler/application/titiler/application/main.py index e028a2522..84847511e 100644 --- a/titiler/application/titiler/application/main.py +++ b/titiler/application/titiler/application/main.py @@ -9,6 +9,7 @@ CacheControlMiddleware, LoggerMiddleware, TotalTimeMiddleware, + CaseInsensitiveMiddleware ) from titiler.application.routers import cog, mosaic, stac, tms from titiler.application.settings import ApiSettings @@ -67,6 +68,8 @@ exclude_path={r"/healthz"}, ) +app.add_middleware(CaseInsensitiveMiddleware) + if api_settings.debug: app.add_middleware(LoggerMiddleware, headers=True, querystrings=True) app.add_middleware(TotalTimeMiddleware) diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index 17b67a06a..65c8ab057 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -88,3 +88,21 @@ async def dispatch(self, request: Request, call_next): response = await call_next(request) return response + + +class CaseInsensitiveMiddleware(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): + self.DECODE_FORMAT = "latin-1" + + raw = request.scope["query_string"].decode(self.DECODE_FORMAT).lower() + request.scope["query_string"] = raw.encode(self.DECODE_FORMAT) + + path = request.scope["path"].lower() + request.scope["path"] = path + + response = await call_next(request) + return response \ No newline at end of file From b7da9c84eab12634ef0d43cf55734e64cdd9ecae Mon Sep 17 00:00:00 2001 From: lorenzoriches Date: Thu, 3 Jun 2021 10:47:32 +0200 Subject: [PATCH 2/8] make only query params lowercase --- titiler/application/titiler/application/middleware.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index 65c8ab057..c37e10768 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -101,8 +101,5 @@ async def dispatch(self, request: Request, call_next): raw = request.scope["query_string"].decode(self.DECODE_FORMAT).lower() request.scope["query_string"] = raw.encode(self.DECODE_FORMAT) - path = request.scope["path"].lower() - request.scope["path"] = path - response = await call_next(request) return response \ No newline at end of file From 82f77d05dd61fd5f14c211337eeb7ee646560264 Mon Sep 17 00:00:00 2001 From: lorenzoriches Date: Fri, 4 Jun 2021 10:01:06 +0200 Subject: [PATCH 3/8] changed middleware to LowerCaseQueryStringMiddleware and made it optional with API setting. --- titiler/application/titiler/application/main.py | 6 +++--- titiler/application/titiler/application/middleware.py | 2 +- titiler/application/titiler/application/settings.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/titiler/application/titiler/application/main.py b/titiler/application/titiler/application/main.py index 84847511e..12fd9481d 100644 --- a/titiler/application/titiler/application/main.py +++ b/titiler/application/titiler/application/main.py @@ -9,7 +9,7 @@ CacheControlMiddleware, LoggerMiddleware, TotalTimeMiddleware, - CaseInsensitiveMiddleware + LowerCaseQueryStringMiddleware ) from titiler.application.routers import cog, mosaic, stac, tms from titiler.application.settings import ApiSettings @@ -68,12 +68,12 @@ exclude_path={r"/healthz"}, ) -app.add_middleware(CaseInsensitiveMiddleware) - if api_settings.debug: app.add_middleware(LoggerMiddleware, headers=True, querystrings=True) app.add_middleware(TotalTimeMiddleware) +if api_settings.lower_case_query_parameters: + app.add_middleware(LowerCaseQueryStringMiddleware) @app.get("/healthz", description="Health Check", tags=["Health Check"]) def ping(): diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index c37e10768..38b12dcce 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -90,7 +90,7 @@ async def dispatch(self, request: Request, call_next): return response -class CaseInsensitiveMiddleware(BaseHTTPMiddleware): +class LowerCaseQueryStringMiddleware(BaseHTTPMiddleware): """Middleware to make URL parameters case-insensitive. taken from: https://github.com/tiangolo/fastapi/issues/826 """ diff --git a/titiler/application/titiler/application/settings.py b/titiler/application/titiler/application/settings.py index 6a4909a5d..8d32c247b 100644 --- a/titiler/application/titiler/application/settings.py +++ b/titiler/application/titiler/application/settings.py @@ -15,6 +15,8 @@ class ApiSettings(pydantic.BaseSettings): disable_stac: bool = False disable_mosaic: bool = False + lower_case_query_parameters: bool = False + @pydantic.validator("cors_origins") def parse_cors_origin(cls, v): """Parse CORS origins.""" From ffac04876d53d025375a325904712b3a6c102083 Mon Sep 17 00:00:00 2001 From: lorenzoriches Date: Fri, 4 Jun 2021 13:04:27 +0200 Subject: [PATCH 4/8] changed middleware to LowerCaseQueryStringMiddleware and made it optional with API setting. Only lowercase of query keys. --- titiler/application/titiler/application/middleware.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index 38b12dcce..b627c79bb 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -98,8 +98,15 @@ class LowerCaseQueryStringMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): self.DECODE_FORMAT = "latin-1" - raw = request.scope["query_string"].decode(self.DECODE_FORMAT).lower() - request.scope["query_string"] = raw.encode(self.DECODE_FORMAT) + query_string = "" + for k in request.query_params: + query_string += k.lower() + '=' + request.query_params[k] + request.scope["query_string"] = query_string.encode(self.DECODE_FORMAT) + + print(request.scope["query_string"]) + + #raw = request.scope["query_string"].decode(self.DECODE_FORMAT).lower() + #request.scope["query_string"] = raw.encode(self.DECODE_FORMAT) response = await call_next(request) return response \ No newline at end of file From c2a94f718529b097513a48d56deb78dd309bc6c8 Mon Sep 17 00:00:00 2001 From: lorenzoriches Date: Mon, 7 Jun 2021 10:41:02 +0200 Subject: [PATCH 5/8] changed middleware to LowerCaseQueryStringMiddleware and made it optional with API setting. Hack to lowercase only query keys. --- titiler/application/titiler/application/middleware.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index b627c79bb..20e7d239e 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -100,13 +100,11 @@ async def dispatch(self, request: Request, call_next): query_string = "" for k in request.query_params: - query_string += k.lower() + '=' + request.query_params[k] - request.scope["query_string"] = query_string.encode(self.DECODE_FORMAT) + query_string += k.lower() + '=' + request.query_params[k] + "&" - print(request.scope["query_string"]) + query_string = query_string[:-1] + request.scope["query_string"] = query_string.encode(self.DECODE_FORMAT) - #raw = request.scope["query_string"].decode(self.DECODE_FORMAT).lower() - #request.scope["query_string"] = raw.encode(self.DECODE_FORMAT) response = await call_next(request) return response \ No newline at end of file From c6ef12019311853fdae7ba6ed7a245fe284d4d2f Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 11 Jun 2021 11:20:25 +0200 Subject: [PATCH 6/8] add test case --- .../application/tests/test_case_middleware.py | 28 +++++++++++++++++++ .../titiler/application/middleware.py | 7 +++-- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 titiler/application/tests/test_case_middleware.py diff --git a/titiler/application/tests/test_case_middleware.py b/titiler/application/tests/test_case_middleware.py new file mode 100644 index 000000000..3fcc125fe --- /dev/null +++ b/titiler/application/tests/test_case_middleware.py @@ -0,0 +1,28 @@ +"""Test titiler.application.middleware.LowerCaseQueryStringMiddleware.""" + + +from titiler.application.middleware import LowerCaseQueryStringMiddleware + +from fastapi import FastAPI, Query + +from starlette.testclient import TestClient + + +def test_lowercase_middleware(): + """Make sure upper and lower case QS are accepted.""" + app = FastAPI() + + @app.get("/route1") + async def route1(value: str = Query(...)): + """route1.""" + return {"value": value} + + app.add_middleware(LowerCaseQueryStringMiddleware) + + client = TestClient(app) + + response = client.get("/route1?value=lorenzori") + assert response.json() == {"value": "lorenzori"} + + response = client.get("/route1?VALUE=lorenzori") + assert response.json() == {"value": "lorenzori"} diff --git a/titiler/application/titiler/application/middleware.py b/titiler/application/titiler/application/middleware.py index 20e7d239e..490e98351 100644 --- a/titiler/application/titiler/application/middleware.py +++ b/titiler/application/titiler/application/middleware.py @@ -96,15 +96,16 @@ class LowerCaseQueryStringMiddleware(BaseHTTPMiddleware): """ 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 += 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 \ No newline at end of file + return response From de1702c0de13fc2158d596d50899df9a7284b569 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 11 Jun 2021 11:34:31 +0200 Subject: [PATCH 7/8] linting --- titiler/application/titiler/application/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/titiler/application/titiler/application/main.py b/titiler/application/titiler/application/main.py index 12fd9481d..d5ed02a00 100644 --- a/titiler/application/titiler/application/main.py +++ b/titiler/application/titiler/application/main.py @@ -8,8 +8,8 @@ from titiler.application.middleware import ( CacheControlMiddleware, LoggerMiddleware, + LowerCaseQueryStringMiddleware, TotalTimeMiddleware, - LowerCaseQueryStringMiddleware ) from titiler.application.routers import cog, mosaic, stac, tms from titiler.application.settings import ApiSettings @@ -75,6 +75,7 @@ if api_settings.lower_case_query_parameters: app.add_middleware(LowerCaseQueryStringMiddleware) + @app.get("/healthz", description="Health Check", tags=["Health Check"]) def ping(): """Health check.""" From ce07f2ba31daf08f2472a36fe7c413569cc84fef Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 11 Jun 2021 12:03:59 +0200 Subject: [PATCH 8/8] update changelog --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 55191862e..617ac2498 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,10 @@ * update `tilejson` and `WMTSCapabilities.xml` endpoints to allow list querystrings (as done previously in https://github.com/developmentseed/titiler/issues/319) +### titiler.application + +* add `titiler.application.middleware.LowerCaseQueryStringMiddleware` to cast all query string parameter to lowercase (author @lorenzori, https://github.com/developmentseed/titiler/pull/321) + ## 0.3.2 (2021-05-26) ### titiler.core