Skip to content

Commit

Permalink
add a py sdk example for a proxy backend
Browse files Browse the repository at this point in the history
  • Loading branch information
qrkourier committed Jan 28, 2025
1 parent 701f897 commit e32d29a
Showing 1 changed file with 114 additions and 0 deletions.
114 changes: 114 additions & 0 deletions sdk/python/examples/proxy/proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import zrok
from zrok.model import ShareRequest
import requests
import atexit
import urllib.parse
import logging
import sys
from waitress import serve
from flask import Flask, request, Response

# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

app = Flask(__name__)
target_url = None
zrok_opts = {}
bindPort = 18081

# List of hop-by-hop headers that should not be forwarded
HOP_BY_HOP_HEADERS = {
'connection',
'keep-alive',
'proxy-authenticate',
'proxy-authorization',
'te',
'trailers',
'transfer-encoding',
'upgrade'
}


@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'])
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'])
def proxy(path):
global target_url
logger.info(f"Incoming {request.method} request to {request.path}")
logger.info(f"Headers: {dict(request.headers)}")

# Forward the request to target URL
full_url = urllib.parse.urljoin(target_url, request.path)
logger.info(f"Forwarding to: {full_url}")

# Copy request headers, excluding hop-by-hop headers
headers = {k: v for k, v in request.headers.items() if k.lower() not in HOP_BY_HOP_HEADERS and k.lower() != 'host'}

try:
response = requests.request(
method=request.method,
url=full_url,
headers=headers,
data=request.get_data(),
stream=True
)

logger.info(f"Response status: {response.status_code}")
logger.info(f"Response headers: {dict(response.headers)}")

# Filter out hop-by-hop headers from the response
filtered_headers = {k: v for k, v in response.headers.items() if k.lower() not in HOP_BY_HOP_HEADERS}

return Response(
response.iter_content(chunk_size=8192),
status=response.status_code,
headers=filtered_headers
)

except Exception as e:
logger.error(f"Proxy error: {str(e)}", exc_info=True)
return str(e), 502


@zrok.decor.zrok(opts=zrok_opts)
def run_proxy():
# the port is only used to integrate Zrok with frameworks that expect a "hostname:port" combo
serve(app, port=bindPort)


if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: proxy.py <target_url>")
sys.exit(1)

target_url = sys.argv[1]
logger.info("=== Starting proxy server ===")
logger.info(f"Target URL: {target_url}")
logger.info(f"Logging level: {logger.getEffectiveLevel()}")

root = zrok.environment.root.Load()
try:
shr = zrok.share.CreateShare(root=root, request=ShareRequest(
BackendMode=zrok.model.PROXY_BACKEND_MODE,
ShareMode=zrok.model.PUBLIC_SHARE_MODE,
Frontends=['public'],
Target="http-proxy"
))
shrToken = shr.Token
print("Access proxy at: ", "\n".join(shr.FrontendEndpoints))

def cleanup():
zrok.share.DeleteShare(root=root, shr=shr)
print("Share deleted")
atexit.register(cleanup)

zrok_opts['cfg'] = zrok.decor.Opts(root=root, shrToken=shrToken, bindPort=bindPort)

run_proxy()

except Exception as e:
print("Error:", e)
sys.exit(1)

0 comments on commit e32d29a

Please sign in to comment.