-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
152 lines (122 loc) · 6.31 KB
/
server.py
File metadata and controls
152 lines (122 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import http.server
import socketserver
import requests
import urllib.parse
import logging
import sys
import os
from http.cookies import SimpleCookie
import certifi
import ssl
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# MapMetrics gateway configuration
GATEWAY_HOST = "gateway.mapmetrics1.org"
GATEWAY_SCHEME = "https"
# Store cookies for reuse
cookies_store = {}
class ProxyHandler(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', 'https://localhost:8000')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
self.send_header('Access-Control-Allow-Credentials', 'true')
super().end_headers()
def do_OPTIONS(self):
self.send_response(200)
self.end_headers()
def do_GET(self):
try:
# Parse the request path
parsed_path = urllib.parse.urlparse(self.path)
path_parts = parsed_path.path.strip('/').split('/')
# Check if this is a proxy request
if path_parts[0] == 'proxy':
# Extract the path after /proxy/
proxy_path = '/'.join(path_parts[1:])
# Construct the target URL
target_url = f"{GATEWAY_SCHEME}://{GATEWAY_HOST}/{proxy_path}"
if parsed_path.query:
target_url += f"?{parsed_path.query}"
logger.info(f"Proxying request:")
logger.info(f"Original path: {self.path}")
logger.info(f"Proxy path: {proxy_path}")
logger.info(f"Target URL: {target_url}")
# Get cookies from the request
cookie_header = self.headers.get('Cookie', '')
cookies = SimpleCookie(cookie_header)
# Convert SimpleCookie to dict for requests
cookies_dict = {k: v.value for k, v in cookies.items()}
# Add any stored cookies
for key, value in cookies_store.items():
if key not in cookies_dict:
cookies_dict[key] = value
# Prepare headers for the gateway request
headers = {
'Accept': 'application/x-protobuf',
'User-Agent': 'MapMetrics-GL/1.0',
'Origin': self.headers.get('Origin', 'http://localhost:8000')
}
# Add Authorization header if present
auth_header = self.headers.get('Authorization')
if auth_header:
headers['Authorization'] = auth_header
logger.info(f"Request headers: {headers}")
logger.info(f"Request cookies: {cookies_dict}")
try:
# Make the request to the gateway
response = requests.get(
target_url,
headers=headers,
cookies=cookies_dict,
verify=certifi.where(),
stream=True,
timeout=30
)
logger.info(f"Response status: {response.status_code}")
logger.info(f"Response headers: {dict(response.headers)}")
# Store any new cookies from the response
if 'set-cookie' in response.headers:
new_cookies = SimpleCookie(response.headers['set-cookie'])
for key, value in new_cookies.items():
cookies_store[key] = value.value
# Set the cookie for gateway.mapmetrics.org domain
self.send_header('Set-Cookie', f"{key}={value.value}; Path=/; Domain=gateway.mapmetrics2.org; HttpOnly; SameSite=None; Secure")
# Forward the response status
self.send_response(response.status_code)
# Forward response headers
for key, value in response.headers.items():
if key.lower() not in ['transfer-encoding', 'connection', 'content-encoding', 'set-cookie', 'access-control-allow-origin', 'access-control-allow-methods', 'access-control-allow-headers', 'access-control-allow-credentials']:
self.send_header(key, value)
self.end_headers()
# Stream the response content in smaller chunks
try:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
self.wfile.write(chunk)
self.wfile.flush()
except (ConnectionResetError, BrokenPipeError) as e:
logger.error(f"Connection error while streaming: {str(e)}")
return
return
except requests.exceptions.RequestException as e:
logger.error(f"Request error: {str(e)}")
self.send_error(500, f"Proxy request failed: {str(e)}")
return
# If not a proxy request, serve the file
return super().do_GET()
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
self.send_error(500, f"Internal Server Error: {str(e)}")
def run(port=8000):
server_address = ('', port)
httpd = socketserver.TCPServer(server_address, ProxyHandler)
# SSL configuration
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('localhost.crt', 'localhost.key') # You'll need to generate these
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print(f"Starting HTTPS server on port {port}...")
httpd.serve_forever()
if __name__ == '__main__':
run()