Add improvements 2
This commit is contained in:
@@ -13,6 +13,7 @@ from fastapi.responses import JSONResponse
|
||||
from typing import Dict, Any
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
from app.core.service_discovery import ServiceDiscovery
|
||||
from shared.monitoring.metrics import MetricsCollector
|
||||
|
||||
@@ -136,107 +137,32 @@ class AuthProxy:
|
||||
return AUTH_SERVICE_URL
|
||||
|
||||
def _prepare_headers(self, headers, request=None) -> Dict[str, str]:
|
||||
"""Prepare headers for forwarding (remove hop-by-hop headers)"""
|
||||
# Remove hop-by-hop headers
|
||||
hop_by_hop_headers = {
|
||||
'connection', 'keep-alive', 'proxy-authenticate',
|
||||
'proxy-authorization', 'te', 'trailers', 'upgrade'
|
||||
}
|
||||
|
||||
# Convert headers to dict - get ALL headers including those added by middleware
|
||||
# Middleware adds headers to _list, so we need to read from there
|
||||
logger.debug(f"DEBUG: headers type: {type(headers)}, has _list: {hasattr(headers, '_list')}, has raw: {hasattr(headers, 'raw')}")
|
||||
logger.debug(f"DEBUG: headers.__dict__ keys: {list(headers.__dict__.keys())}")
|
||||
logger.debug(f"DEBUG: '_list' in headers.__dict__: {'_list' in headers.__dict__}")
|
||||
|
||||
if hasattr(headers, '_list'):
|
||||
logger.debug(f"DEBUG: Entering _list branch")
|
||||
logger.debug(f"DEBUG: headers object id: {id(headers)}, _list id: {id(headers.__dict__.get('_list', []))}")
|
||||
# Get headers from the _list where middleware adds them
|
||||
all_headers_list = headers.__dict__.get('_list', [])
|
||||
logger.debug(f"DEBUG: _list length: {len(all_headers_list)}")
|
||||
|
||||
# Debug: Show first few headers in the list
|
||||
debug_headers = []
|
||||
for i, (k, v) in enumerate(all_headers_list):
|
||||
if i < 5: # Show first 5 headers for debugging
|
||||
"""Prepare headers for forwarding using unified HeaderManager"""
|
||||
# Use unified HeaderManager to get all headers
|
||||
if request:
|
||||
all_headers = header_manager.get_all_headers_for_proxy(request)
|
||||
logger.debug(f"DEBUG: Added headers from HeaderManager: {list(all_headers.keys())}")
|
||||
else:
|
||||
# Fallback: convert headers to dict manually
|
||||
all_headers = {}
|
||||
if hasattr(headers, '_list'):
|
||||
for k, v in headers.__dict__.get('_list', []):
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
debug_headers.append(f"{key}: {value}")
|
||||
logger.debug(f"DEBUG: First headers in _list: {debug_headers}")
|
||||
|
||||
# Convert to dict for easier processing
|
||||
all_headers = {}
|
||||
for k, v in all_headers_list:
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
all_headers[key] = value
|
||||
|
||||
# Debug: Show if x-user-id and x-is-demo are in the dict
|
||||
logger.debug(f"DEBUG: x-user-id in all_headers: {'x-user-id' in all_headers}, x-is-demo in all_headers: {'x-is-demo' in all_headers}")
|
||||
logger.debug(f"DEBUG: all_headers keys: {list(all_headers.keys())[:10]}...") # Show first 10 keys
|
||||
|
||||
logger.info(f"📤 Forwarding headers to auth service - x_user_id: {all_headers.get('x-user-id', 'MISSING')}, x_is_demo: {all_headers.get('x-is-demo', 'MISSING')}, x_demo_session_id: {all_headers.get('x-demo-session-id', 'MISSING')}, headers: {list(all_headers.keys())}")
|
||||
|
||||
# Check if headers are missing and try to get them from request.state
|
||||
if request and hasattr(request, 'state') and hasattr(request.state, 'injected_headers'):
|
||||
logger.debug(f"DEBUG: Found injected_headers in request.state: {request.state.injected_headers}")
|
||||
# Add missing headers from request.state
|
||||
if 'x-user-id' not in all_headers and 'x-user-id' in request.state.injected_headers:
|
||||
all_headers['x-user-id'] = request.state.injected_headers['x-user-id']
|
||||
logger.debug(f"DEBUG: Added x-user-id from request.state: {all_headers['x-user-id']}")
|
||||
if 'x-user-email' not in all_headers and 'x-user-email' in request.state.injected_headers:
|
||||
all_headers['x-user-email'] = request.state.injected_headers['x-user-email']
|
||||
logger.debug(f"DEBUG: Added x-user-email from request.state: {all_headers['x-user-email']}")
|
||||
if 'x-user-role' not in all_headers and 'x-user-role' in request.state.injected_headers:
|
||||
all_headers['x-user-role'] = request.state.injected_headers['x-user-role']
|
||||
logger.debug(f"DEBUG: Added x-user-role from request.state: {all_headers['x-user-role']}")
|
||||
|
||||
# Add is_demo flag if this is a demo session
|
||||
if hasattr(request.state, 'is_demo_session') and request.state.is_demo_session:
|
||||
all_headers['x-is-demo'] = 'true'
|
||||
logger.debug(f"DEBUG: Added x-is-demo from request.state.is_demo_session")
|
||||
|
||||
# Filter out hop-by-hop headers
|
||||
filtered_headers = {
|
||||
k: v for k, v in all_headers.items()
|
||||
if k.lower() not in hop_by_hop_headers
|
||||
}
|
||||
elif hasattr(headers, 'raw'):
|
||||
logger.debug(f"DEBUG: Entering raw branch")
|
||||
|
||||
# Filter out hop-by-hop headers
|
||||
filtered_headers = {
|
||||
k: v for k, v in all_headers.items()
|
||||
if k.lower() not in hop_by_hop_headers
|
||||
}
|
||||
elif hasattr(headers, 'raw'):
|
||||
# Fallback to raw headers if _list not available
|
||||
all_headers = {
|
||||
k.decode() if isinstance(k, bytes) else k: v.decode() if isinstance(v, bytes) else v
|
||||
for k, v in headers.raw
|
||||
}
|
||||
logger.info(f"📤 Forwarding headers to auth service - x_user_id: {all_headers.get('x-user-id', 'MISSING')}, x_is_demo: {all_headers.get('x-is-demo', 'MISSING')}, x_demo_session_id: {all_headers.get('x-demo-session-id', 'MISSING')}, headers: {list(all_headers.keys())}")
|
||||
|
||||
filtered_headers = {
|
||||
k.decode() if isinstance(k, bytes) else k: v.decode() if isinstance(v, bytes) else v
|
||||
for k, v in headers.raw
|
||||
if (k.decode() if isinstance(k, bytes) else k).lower() not in hop_by_hop_headers
|
||||
}
|
||||
else:
|
||||
# Handle case where headers is already a dict
|
||||
logger.info(f"📤 Forwarding headers to auth service - x_user_id: {headers.get('x-user-id', 'MISSING')}, x_is_demo: {headers.get('x-is-demo', 'MISSING')}, x_demo_session_id: {headers.get('x-demo-session-id', 'MISSING')}, headers: {list(headers.keys())}")
|
||||
|
||||
filtered_headers = {
|
||||
k: v for k, v in headers.items()
|
||||
if k.lower() not in hop_by_hop_headers
|
||||
}
|
||||
|
||||
# Add gateway identifier
|
||||
filtered_headers['X-Forwarded-By'] = 'bakery-gateway'
|
||||
filtered_headers['X-Gateway-Version'] = '1.0.0'
|
||||
|
||||
return filtered_headers
|
||||
all_headers[key] = value
|
||||
elif hasattr(headers, 'raw'):
|
||||
for k, v in headers.raw:
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
all_headers[key] = value
|
||||
else:
|
||||
# Headers is already a dict
|
||||
all_headers = dict(headers)
|
||||
|
||||
# Debug logging
|
||||
logger.info(f"📤 Forwarding headers - x_user_id: {all_headers.get('x-user-id', 'MISSING')}, x_is_demo: {all_headers.get('x-is-demo', 'MISSING')}, x_demo_session_id: {all_headers.get('x-demo-session-id', 'MISSING')}, headers: {list(all_headers.keys())}")
|
||||
|
||||
return all_headers
|
||||
|
||||
def _prepare_response_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
|
||||
"""Prepare response headers"""
|
||||
|
||||
@@ -8,6 +8,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
@@ -29,12 +30,8 @@ async def proxy_demo_service(path: str, request: Request):
|
||||
if request.method in ["POST", "PUT", "PATCH"]:
|
||||
body = await request.body()
|
||||
|
||||
# Forward headers (excluding host)
|
||||
headers = {
|
||||
key: value
|
||||
for key, value in request.headers.items()
|
||||
if key.lower() not in ["host", "content-length"]
|
||||
}
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
|
||||
@@ -5,6 +5,7 @@ from fastapi.responses import JSONResponse
|
||||
import httpx
|
||||
import structlog
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = structlog.get_logger()
|
||||
router = APIRouter()
|
||||
@@ -26,12 +27,8 @@ async def proxy_geocoding(request: Request, path: str):
|
||||
if request.method in ["POST", "PUT", "PATCH"]:
|
||||
body = await request.body()
|
||||
|
||||
# Forward headers (excluding host)
|
||||
headers = {
|
||||
key: value
|
||||
for key, value in request.headers.items()
|
||||
if key.lower() not in ["host", "content-length"]
|
||||
}
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
# Make the proxied request
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
|
||||
@@ -8,6 +8,7 @@ from fastapi.responses import JSONResponse
|
||||
import httpx
|
||||
import structlog
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = structlog.get_logger()
|
||||
router = APIRouter()
|
||||
@@ -44,12 +45,8 @@ async def proxy_poi_context(request: Request, path: str):
|
||||
if request.method in ["POST", "PUT", "PATCH"]:
|
||||
body = await request.body()
|
||||
|
||||
# Copy headers (exclude host and content-length as they'll be set by httpx)
|
||||
headers = {
|
||||
key: value
|
||||
for key, value in request.headers.items()
|
||||
if key.lower() not in ["host", "content-length"]
|
||||
}
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
# Make the request to the external service
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
|
||||
@@ -8,6 +8,7 @@ import httpx
|
||||
import logging
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@@ -45,9 +46,8 @@ async def _proxy_to_pos_service(request: Request, target_path: str):
|
||||
try:
|
||||
url = f"{settings.POS_SERVICE_URL}{target_path}"
|
||||
|
||||
# Forward headers
|
||||
headers = dict(request.headers)
|
||||
headers.pop("host", None)
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
# Add query parameters
|
||||
params = dict(request.query_params)
|
||||
|
||||
@@ -9,6 +9,7 @@ import logging
|
||||
from typing import Optional
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@@ -98,29 +99,13 @@ async def _proxy_request(request: Request, target_path: str, service_url: str):
|
||||
try:
|
||||
url = f"{service_url}{target_path}"
|
||||
|
||||
# Forward headers and add user/tenant context
|
||||
headers = dict(request.headers)
|
||||
headers.pop("host", None)
|
||||
|
||||
# Add user context headers if available
|
||||
if hasattr(request.state, 'user') and request.state.user:
|
||||
user = request.state.user
|
||||
headers["x-user-id"] = str(user.get('user_id', ''))
|
||||
headers["x-user-email"] = str(user.get('email', ''))
|
||||
headers["x-user-role"] = str(user.get('role', 'user'))
|
||||
headers["x-user-full-name"] = str(user.get('full_name', ''))
|
||||
headers["x-tenant-id"] = str(user.get('tenant_id', ''))
|
||||
|
||||
# Add subscription context headers
|
||||
if user.get('subscription_tier'):
|
||||
headers["x-subscription-tier"] = str(user.get('subscription_tier', ''))
|
||||
logger.debug(f"Forwarding subscription tier: {user.get('subscription_tier')}")
|
||||
|
||||
if user.get('subscription_status'):
|
||||
headers["x-subscription-status"] = str(user.get('subscription_status', ''))
|
||||
logger.debug(f"Forwarding subscription status: {user.get('subscription_status')}")
|
||||
|
||||
logger.info(f"Forwarding subscription request to {url} with user context: user_id={user.get('user_id')}, email={user.get('email')}, subscription_tier={user.get('subscription_tier', 'not_set')}")
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
# Debug logging
|
||||
user_context = getattr(request.state, 'user', None)
|
||||
if user_context:
|
||||
logger.info(f"Forwarding subscription request to {url} with user context: user_id={user_context.get('user_id')}, email={user_context.get('email')}, subscription_tier={user_context.get('subscription_tier', 'not_set')}")
|
||||
else:
|
||||
logger.warning(f"No user context available when forwarding subscription request to {url}")
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import logging
|
||||
from typing import Optional
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@@ -715,36 +716,18 @@ async def _proxy_request(request: Request, target_path: str, service_url: str, t
|
||||
try:
|
||||
url = f"{service_url}{target_path}"
|
||||
|
||||
# Forward headers and add user/tenant context
|
||||
headers = dict(request.headers)
|
||||
headers.pop("host", None)
|
||||
|
||||
# Add tenant ID header if provided
|
||||
# Use unified HeaderManager for consistent header forwarding
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
|
||||
# Add tenant ID header if provided (override if needed)
|
||||
if tenant_id:
|
||||
headers["X-Tenant-ID"] = tenant_id
|
||||
|
||||
# Add user context headers if available
|
||||
if hasattr(request.state, 'user') and request.state.user:
|
||||
user = request.state.user
|
||||
headers["x-user-id"] = str(user.get('user_id', ''))
|
||||
headers["x-user-email"] = str(user.get('email', ''))
|
||||
headers["x-user-role"] = str(user.get('role', 'user'))
|
||||
headers["x-user-full-name"] = str(user.get('full_name', ''))
|
||||
headers["x-tenant-id"] = tenant_id or str(user.get('tenant_id', ''))
|
||||
|
||||
# Add subscription context headers
|
||||
if user.get('subscription_tier'):
|
||||
headers["x-subscription-tier"] = str(user.get('subscription_tier', ''))
|
||||
logger.debug(f"Forwarding subscription tier: {user.get('subscription_tier')}")
|
||||
|
||||
if user.get('subscription_status'):
|
||||
headers["x-subscription-status"] = str(user.get('subscription_status', ''))
|
||||
logger.debug(f"Forwarding subscription status: {user.get('subscription_status')}")
|
||||
|
||||
# Debug logging
|
||||
logger.info(f"Forwarding request to {url} with user context: user_id={user.get('user_id')}, email={user.get('email')}, tenant_id={tenant_id}, subscription_tier={user.get('subscription_tier', 'not_set')}")
|
||||
headers["x-tenant-id"] = tenant_id
|
||||
|
||||
# Debug logging
|
||||
user_context = getattr(request.state, 'user', None)
|
||||
if user_context:
|
||||
logger.info(f"Forwarding request to {url} with user context: user_id={user_context.get('user_id')}, email={user_context.get('email')}, tenant_id={tenant_id}, subscription_tier={user_context.get('subscription_tier', 'not_set')}")
|
||||
else:
|
||||
# Debug logging when no user context available
|
||||
logger.warning(f"No user context available when forwarding request to {url}. request.state.user: {getattr(request.state, 'user', 'NOT_SET')}")
|
||||
|
||||
# Get request body if present
|
||||
@@ -782,9 +765,10 @@ async def _proxy_request(request: Request, target_path: str, service_url: str, t
|
||||
|
||||
logger.info(f"Forwarding multipart request with files={list(files.keys()) if files else None}, data={list(data.keys()) if data else None}")
|
||||
|
||||
# Remove content-type from headers - httpx will set it with new boundary
|
||||
headers.pop("content-type", None)
|
||||
headers.pop("content-length", None)
|
||||
# For multipart requests, we need to get fresh headers since httpx will set content-type
|
||||
# Get all headers again to ensure we have the complete set
|
||||
headers = header_manager.get_all_headers_for_proxy(request)
|
||||
# httpx will automatically set content-type for multipart, so we don't need to remove it
|
||||
else:
|
||||
# For other content types, use body as before
|
||||
body = await request.body()
|
||||
|
||||
@@ -13,6 +13,7 @@ from typing import Dict, Any
|
||||
import json
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.header_manager import header_manager
|
||||
from app.core.service_discovery import ServiceDiscovery
|
||||
from shared.monitoring.metrics import MetricsCollector
|
||||
|
||||
@@ -136,64 +137,28 @@ class UserProxy:
|
||||
return AUTH_SERVICE_URL
|
||||
|
||||
def _prepare_headers(self, headers, request=None) -> Dict[str, str]:
|
||||
"""Prepare headers for forwarding (remove hop-by-hop headers)"""
|
||||
# Remove hop-by-hop headers
|
||||
hop_by_hop_headers = {
|
||||
'connection', 'keep-alive', 'proxy-authenticate',
|
||||
'proxy-authorization', 'te', 'trailers', 'upgrade'
|
||||
}
|
||||
|
||||
# Convert headers to dict if it's a Headers object
|
||||
# This ensures we get ALL headers including those added by middleware
|
||||
if hasattr(headers, '_list'):
|
||||
# Get headers from the _list where middleware adds them
|
||||
all_headers_list = headers.__dict__.get('_list', [])
|
||||
|
||||
# Convert to dict for easier processing
|
||||
all_headers = {}
|
||||
for k, v in all_headers_list:
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
all_headers[key] = value
|
||||
|
||||
# Check if headers are missing and try to get them from request.state
|
||||
if request and hasattr(request, 'state') and hasattr(request.state, 'injected_headers'):
|
||||
# Add missing headers from request.state
|
||||
if 'x-user-id' not in all_headers and 'x-user-id' in request.state.injected_headers:
|
||||
all_headers['x-user-id'] = request.state.injected_headers['x-user-id']
|
||||
if 'x-user-email' not in all_headers and 'x-user-email' in request.state.injected_headers:
|
||||
all_headers['x-user-email'] = request.state.injected_headers['x-user-email']
|
||||
if 'x-user-role' not in all_headers and 'x-user-role' in request.state.injected_headers:
|
||||
all_headers['x-user-role'] = request.state.injected_headers['x-user-role']
|
||||
|
||||
# Add is_demo flag if this is a demo session
|
||||
if hasattr(request.state, 'is_demo_session') and request.state.is_demo_session:
|
||||
all_headers['x-is-demo'] = 'true'
|
||||
|
||||
# Filter out hop-by-hop headers
|
||||
filtered_headers = {
|
||||
k: v for k, v in all_headers.items()
|
||||
if k.lower() not in hop_by_hop_headers
|
||||
}
|
||||
elif hasattr(headers, 'raw'):
|
||||
# FastAPI/Starlette Headers object - use raw to get all headers
|
||||
filtered_headers = {
|
||||
k.decode() if isinstance(k, bytes) else k: v.decode() if isinstance(v, bytes) else v
|
||||
for k, v in headers.raw
|
||||
if (k.decode() if isinstance(k, bytes) else k).lower() not in hop_by_hop_headers
|
||||
}
|
||||
"""Prepare headers for forwarding using unified HeaderManager"""
|
||||
# Use unified HeaderManager to get all headers
|
||||
if request:
|
||||
all_headers = header_manager.get_all_headers_for_proxy(request)
|
||||
else:
|
||||
# Already a dict
|
||||
filtered_headers = {
|
||||
k: v for k, v in headers.items()
|
||||
if k.lower() not in hop_by_hop_headers
|
||||
}
|
||||
|
||||
# Add gateway identifier
|
||||
filtered_headers['X-Forwarded-By'] = 'bakery-gateway'
|
||||
filtered_headers['X-Gateway-Version'] = '1.0.0'
|
||||
|
||||
return filtered_headers
|
||||
# Fallback: convert headers to dict manually
|
||||
all_headers = {}
|
||||
if hasattr(headers, '_list'):
|
||||
for k, v in headers.__dict__.get('_list', []):
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
all_headers[key] = value
|
||||
elif hasattr(headers, 'raw'):
|
||||
for k, v in headers.raw:
|
||||
key = k.decode() if isinstance(k, bytes) else k
|
||||
value = v.decode() if isinstance(v, bytes) else v
|
||||
all_headers[key] = value
|
||||
else:
|
||||
# Headers is already a dict
|
||||
all_headers = dict(headers)
|
||||
|
||||
return all_headers
|
||||
|
||||
def _prepare_response_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
|
||||
"""Prepare response headers"""
|
||||
|
||||
Reference in New Issue
Block a user