Compare commits

...

3 Commits

Author SHA1 Message Date
5f4e1b7207 Update services.py 2025-08-12 21:29:13 +10:00
9729004982 Hotfix - proxy pathing 2025-08-12 20:48:52 +10:00
5a6f2072d7 Hotifx
fix context relative path.
2025-08-12 19:28:47 +10:00
2 changed files with 50 additions and 29 deletions

66
app.py
View File

@ -5,6 +5,7 @@ CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
# Introduce app_dir variable that can be overridden by environment
app_dir = os.environ.get('APP_DIR', CURRENT_DIR)
sys.path.append(CURRENT_DIR)
#sys.path.append(os.path.abspath(os.path.dirname(__file__)))
import datetime
import shutil
import queue
@ -1790,25 +1791,39 @@ def proxy_hapi(subpath):
logger.debug(f"Proxy received request for path: '/fhir/{subpath}', cleaned subpath: '{clean_subpath}'")
# Determine the target FHIR server base URL
# NEW: Check for proxy-target query parameter first
target_server_query = request.args.get('proxy-target')
target_server_header = request.headers.get('X-Target-FHIR-Server')
final_base_url = None
is_custom_target = False
if target_server_header:
if target_server_query:
try:
parsed_url = urlparse(target_server_header)
if not parsed_url.scheme or not parsed_url.netloc:
raise ValueError("Invalid URL format in X-Target-FHIR-Server header")
final_base_url = target_server_header.rstrip('/')
is_custom_target = True
logger.info(f"Proxy target identified from header: {final_base_url}")
parsed_url = urlparse(target_server_query)
if not parsed_url.scheme or not parsed_url.netloc:
raise ValueError("Invalid URL format in proxy-target query parameter")
final_base_url = target_server_query.rstrip('/')
is_custom_target = True
logger.info(f"Proxy target identified from query parameter: {final_base_url}")
except ValueError as e:
logger.warning(f"Invalid URL in X-Target-FHIR-Server header: '{target_server_header}'. Falling back. Error: {e}")
final_base_url = current_app.config['HAPI_FHIR_URL'].rstrip('/')
logger.debug(f"Falling back to default local HAPI due to invalid header: {final_base_url}")
logger.warning(f"Invalid URL in proxy-target query parameter: '{target_server_query}'. Falling back. Error: {e}")
final_base_url = current_app.config['HAPI_FHIR_URL'].rstrip('/')
logger.debug(f"Falling back to default local HAPI due to invalid query: {final_base_url}")
elif target_server_header:
try:
parsed_url = urlparse(target_server_header)
if not parsed_url.scheme or not parsed_url.netloc:
raise ValueError("Invalid URL format in X-Target-FHIR-Server header")
final_base_url = target_server_header.rstrip('/')
is_custom_target = True
logger.info(f"Proxy target identified from header: {final_base_url}")
except ValueError as e:
logger.warning(f"Invalid URL in X-Target-FHIR-Server header: '{target_server_header}'. Falling back. Error: {e}")
final_base_url = current_app.config['HAPI_FHIR_URL'].rstrip('/')
logger.debug(f"Falling back to default local HAPI due to invalid header: {final_base_url}")
else:
final_base_url = current_app.config['HAPI_FHIR_URL'].rstrip('/')
logger.debug(f"No target header found, proxying to default local HAPI: {final_base_url}")
logger.debug(f"No target info found, proxying to default local HAPI: {final_base_url}")
# Construct the final URL for the target server request
# Append the cleaned subpath only if it's not empty
@ -1890,7 +1905,6 @@ def proxy_hapi(subpath):
except Exception as e:
logger.error(f"Unexpected proxy error for {final_url}: {str(e)}", exc_info=True)
return jsonify({'resourceType': 'OperationOutcome', 'issue': [{'severity': 'error', 'code': 'exception', 'diagnostics': 'An unexpected error occurred within the FHIR proxy.', 'details': {'text': str(e)}}]}), 500
# --- End of corrected proxy_hapi function ---
@ -2402,19 +2416,21 @@ def api_retrieve_bundles():
output_zip = os.path.join(temp_dir, zip_filename)
def generate():
try:
yield from services.retrieve_bundles(
fhir_server_url=fhir_server_url,
resources=resources,
output_zip=output_zip,
validate_references=validate_references,
fetch_reference_bundles=fetch_reference_bundles,
auth_type=auth_type,
auth_token=auth_token
)
except Exception as e:
logger.error(f"Error in retrieve_bundles: {e}", exc_info=True)
yield json.dumps({"type": "error", "message": f"Unexpected error: {str(e)}"}) + "\n"
# Push the application context manually for the generator's lifetime
with app.app_context():
try:
yield from services.retrieve_bundles(
fhir_server_url=fhir_server_url,
resources=resources,
output_zip=output_zip,
validate_references=validate_references,
fetch_reference_bundles=fetch_reference_bundles,
auth_type=auth_type,
auth_token=auth_token
)
except Exception as e:
logger.error(f"Error in retrieve_bundles: {e}", exc_info=True)
yield json.dumps({"type": "error", "message": f"Unexpected error: {str(e)}"}) + "\n"
response = Response(generate(), mimetype='application/x-ndjson')
response.headers['X-Zip-Path'] = os.path.join('/tmp', zip_filename)

View File

@ -11,7 +11,7 @@ from flask import current_app, Blueprint, request, jsonify
from fhirpathpy import evaluate
from collections import defaultdict, deque
from pathlib import Path
from urllib.parse import quote, urlparse
from urllib.parse import quote, urlparse, urljoin
from types import SimpleNamespace
import datetime
import subprocess
@ -4586,16 +4586,20 @@ def retrieve_bundles(fhir_server_url, resources, output_zip, validate_references
# Determine Base URL and Headers for Proxy
base_proxy_url = f"{current_app.config['APP_BASE_URL'].rstrip('/')}/fhir"
headers = {'Accept': 'application/fhir+json, application/fhir+xml;q=0.9, */*;q=0.8'}
is_custom_url = fhir_server_url != '/fhir' and fhir_server_url is not None and fhir_server_url.startswith('http')
if is_custom_url:
headers['X-Target-FHIR-Server'] = fhir_server_url.rstrip('/')
# NEW: Add the custom URL as a query parameter for the proxy to use.
# This bypasses issues where reverse proxies might strip custom headers.
base_proxy_url = f"{base_proxy_url}?proxy-target={fhir_server_url.rstrip('/')}"
if auth_type in ['bearer', 'basic'] and auth_token:
auth_display = 'Basic <redacted>' if auth_type == 'basic' else (auth_token[:10] + '...' if len(auth_token) > 10 else auth_token)
yield json.dumps({"type": "info", "message": f"Using {auth_type} auth with header: Authorization: {auth_display}"}) + "\n"
headers['Authorization'] = auth_token
else:
yield json.dumps({"type": "info", "message": "Using no authentication for custom URL"}) + "\n"
logger.debug(f"Will use proxy with X-Target-FHIR-Server: {headers['X-Target-FHIR-Server']}")
logger.debug(f"Will use proxy with proxy-target: {fhir_server_url}")
else:
yield json.dumps({"type": "info", "message": "Using no authentication for local HAPI server"}) + "\n"
logger.debug("Will use proxy targeting local HAPI server")
@ -4603,7 +4607,8 @@ def retrieve_bundles(fhir_server_url, resources, output_zip, validate_references
# Fetch Initial Bundles
initial_bundle_files = []
for resource_type in resources:
url = f"{base_proxy_url}/{quote(resource_type)}"
#url = f"{base_proxy_url}/{quote(resource_type)}"
url = urljoin(base_proxy_url, quote(resource_type))
yield json.dumps({"type": "progress", "message": f"Fetching bundle for {resource_type} via proxy..."}) + "\n"
logger.debug(f"Sending GET request to proxy {url} with headers: {json.dumps(headers)}")
try: