Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

Commit a68bc28

Browse files
committed
fix: bypass WebSocket in all BaseHTTPMiddleware to prevent WS protocol breakage
1 parent c06f21d commit a68bc28

3 files changed

Lines changed: 31 additions & 2 deletions

File tree

‎src/api/middleware.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class RequestContextMiddleware(BaseHTTPMiddleware):
2929
async def dispatch(
3030
self, request: Request, call_next: RequestResponseEndpoint,
3131
) -> Response:
32+
# Skip WebSocket connections — BaseHTTPMiddleware breaks WS protocol
33+
if request.scope.get("type") == "websocket":
34+
return await call_next(request)
35+
3236
request_id = request.headers.get("X-Request-ID") or uuid.uuid4().hex
3337
request.state.request_id = request_id
3438

@@ -53,6 +57,9 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
5357
async def dispatch(
5458
self, request: Request, call_next: RequestResponseEndpoint,
5559
) -> Response:
60+
if request.scope.get("type") == "websocket":
61+
return await call_next(request)
62+
5663
response = await call_next(request)
5764
response.headers["X-Content-Type-Options"] = "nosniff"
5865
response.headers["X-Frame-Options"] = "DENY"
@@ -70,6 +77,9 @@ class MaxBodySizeMiddleware(BaseHTTPMiddleware):
7077
async def dispatch(
7178
self, request: Request, call_next: RequestResponseEndpoint,
7279
) -> Response:
80+
if request.scope.get("type") == "websocket":
81+
return await call_next(request)
82+
7383
content_length = request.headers.get("content-length")
7484
if content_length and int(content_length) > settings.max_request_body_bytes:
7585
from fastapi.responses import JSONResponse
@@ -92,6 +102,9 @@ class PrometheusMiddleware(BaseHTTPMiddleware):
92102
async def dispatch(
93103
self, request: Request, call_next: RequestResponseEndpoint,
94104
) -> Response:
105+
if request.scope.get("type") == "websocket":
106+
return await call_next(request)
107+
95108
from src.config.metrics import METRICS
96109

97110
# Normalise path to avoid high-cardinality (collapse IDs)
@@ -132,6 +145,9 @@ class AnalyticsMiddleware(BaseHTTPMiddleware):
132145
async def dispatch(
133146
self, request: Request, call_next: RequestResponseEndpoint,
134147
) -> Response:
148+
if request.scope.get("type") == "websocket":
149+
return await call_next(request)
150+
135151
from src.config.analytics import analytics
136152

137153
start = time.perf_counter()

‎src/api/routes/auth.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ def verify_google_token(credential: str) -> dict:
113113
idinfo = id_token.verify_oauth2_token(
114114
credential,
115115
google_requests.Request(),
116-
settings.google_client_id
116+
settings.google_client_id,
117+
clock_skew_in_seconds=60
117118
)
118119

119120
# Check issuer

‎src/graph/neo4j_client.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,21 @@ def initialize_date_nodes(self) -> None:
141141
UNWIND $dates AS date_str
142142
MERGE (d:{GraphSchema.LABEL_DATE} {{ {GraphSchema.PROP_DATE_VAL}: date_str }})
143143
"""
144+
dummy_query = f"""
145+
CREATE (dummy:__Dummy__ {{
146+
{GraphSchema.PROP_EVENT_NAME}: "",
147+
{GraphSchema.PROP_DESC}: "",
148+
{GraphSchema.PROP_YEAR}: "",
149+
{GraphSchema.PROP_TIME}: "",
150+
{GraphSchema.PROP_DATE_EXPRESSION}: "",
151+
{GraphSchema.PROP_EMBEDDING}: []
152+
}})
153+
DELETE dummy
154+
"""
144155
with self._session() as session:
145156
session.run(query, dates=dates)
146-
logger.info("Initialised %d date nodes.", len(dates))
157+
session.run(dummy_query)
158+
logger.info("Initialised %d date nodes and registered property keys.", len(dates))
147159

148160
@_neo4j_retry()
149161
def create_user_node(self, user_id: str) -> None:

0 commit comments

Comments
 (0)