Guest User

proxy.py

a guest
Aug 18th, 2026
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.78 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. import json
  3. import sys
  4. from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
  5. from urllib import error as urlerror
  6. from urllib import request as urlrequest
  7. from urllib.parse import urlsplit, urlunsplit
  8.  
  9.  
  10. LISTEN_HOST = "0.0.0.0"
  11. LISTEN_PORT = 1234
  12. TARGET = "http://127.0.0.1:1235"
  13. TEMPERATURE = 0.6
  14. TOP_P = 0.95
  15. TOP_K = 20
  16. MIN_P = 0.0
  17. REASONING_EFFORT = "low"
  18. CHAT_TEMPLATE_KWARGS = '{"preserve_thinking": true, "reasoning_effort": "low"}'
  19. UPSTREAM_TIMEOUT = None
  20.  
  21. HOP_BY_HOP_HEADERS = {
  22. "connection",
  23. "keep-alive",
  24. "proxy-authenticate",
  25. "proxy-authorization",
  26. "proxy-connection",
  27. "te",
  28. "trailer",
  29. "transfer-encoding",
  30. "upgrade",
  31. }
  32.  
  33.  
  34. class ProxyHandler(BaseHTTPRequestHandler):
  35. protocol_version = "HTTP/1.1"
  36. server_version = "vllm-override-proxy/0.1"
  37.  
  38. def do_GET(self):
  39. self._proxy()
  40.  
  41. def do_POST(self):
  42. self._proxy()
  43.  
  44. def do_PUT(self):
  45. self._proxy()
  46.  
  47. def do_PATCH(self):
  48. self._proxy()
  49.  
  50. def do_DELETE(self):
  51. self._proxy()
  52.  
  53. def do_OPTIONS(self):
  54. self._proxy()
  55.  
  56. def _proxy(self):
  57. body = self._read_request_body()
  58. body = self._override_json_body(body)
  59. upstream_url = self._upstream_url()
  60. headers = self._upstream_headers(body)
  61.  
  62. req = urlrequest.Request(
  63. upstream_url,
  64. data=body,
  65. headers=headers,
  66. method=self.command,
  67. )
  68.  
  69. try:
  70. with urlrequest.urlopen(req, timeout=self.server.upstream_timeout) as resp:
  71. self._send_upstream_response(resp)
  72. except urlerror.HTTPError as exc:
  73. self._send_upstream_response(exc)
  74. except urlerror.URLError as exc:
  75. self.send_error(502, "bad gateway: %s" % exc.reason)
  76.  
  77. def _log_request(self, body):
  78. if body:
  79. try:
  80. payload = json.dumps(json.loads(body.decode("utf-8")), indent=2)
  81. except (UnicodeDecodeError, json.JSONDecodeError):
  82. payload = body.decode("utf-8", "replace")
  83. print(">>> %s %s\n%s" % (self.command, self.path, payload), flush=True)
  84. else:
  85. print(">>> %s %s" % (self.command, self.path), flush=True)
  86.  
  87. def _read_request_body(self):
  88. length = self.headers.get("Content-Length")
  89. if length is None:
  90. return None
  91. try:
  92. length_int = int(length)
  93. except ValueError:
  94. return None
  95. if length_int <= 0:
  96. return b""
  97. return self.rfile.read(length_int)
  98.  
  99. def _override_json_body(self, body):
  100. if not body:
  101. return body
  102.  
  103. content_type = self.headers.get("Content-Type", "").lower()
  104. looks_like_json = body.lstrip().startswith((b"{", b"["))
  105. if "json" not in content_type and not looks_like_json:
  106. return body
  107.  
  108. try:
  109. payload = json.loads(body.decode("utf-8"))
  110. except (UnicodeDecodeError, json.JSONDecodeError):
  111. return body
  112.  
  113. if not isinstance(payload, dict):
  114. return body
  115.  
  116. payload.pop("temp", None)
  117. payload.pop("top-k", None)
  118. payload.pop("top-p", None)
  119. payload.pop("min-p", None)
  120. payload["temperature"] = self.server.temperature
  121. payload["top_k"] = self.server.top_k
  122. payload["top_p"] = self.server.top_p
  123. payload["min_p"] = self.server.min_p
  124.  
  125. if self.server.reasoning_effort:
  126. payload.pop("reasoning_effort", None)
  127. payload["reasoning_effort"] = self.server.reasoning_effort
  128.  
  129. if self.server.chat_template_kwargs:
  130. payload.pop("chat_template_kwargs", None)
  131. value = self.server.chat_template_kwargs
  132. try:
  133. value = json.loads(value)
  134. except ValueError:
  135. pass
  136. payload["chat_template_kwargs"] = value
  137.  
  138. return json.dumps(payload, separators=(",", ":")).encode("utf-8")
  139.  
  140. def _upstream_url(self):
  141. path = self.path
  142. if path.startswith(("http://", "https://")):
  143. parts = urlsplit(path)
  144. path = urlunsplit(("", "", parts.path or "/", parts.query, ""))
  145. if not path.startswith("/"):
  146. path = "/" + path
  147. return self.server.target.rstrip("/") + path
  148.  
  149. def _upstream_headers(self, body):
  150. headers = {}
  151. for key, value in self.headers.items():
  152. lower = key.lower()
  153. if lower in HOP_BY_HOP_HEADERS or lower in {"host", "content-length"}:
  154. continue
  155. headers[key] = value
  156.  
  157. headers["Host"] = urlsplit(self.server.target).netloc
  158. headers["Accept-Encoding"] = "identity"
  159. if body is not None:
  160. headers["Content-Length"] = str(len(body))
  161. return headers
  162.  
  163. def _send_upstream_response(self, resp):
  164. status = getattr(resp, "status", getattr(resp, "code", 502))
  165. reason = getattr(resp, "reason", None)
  166. self.send_response(status, reason)
  167.  
  168. for key, value in resp.headers.items():
  169. lower = key.lower()
  170. if lower in HOP_BY_HOP_HEADERS or lower == "content-length":
  171. continue
  172. self.send_header(key, value)
  173. self.send_header("Connection", "close")
  174. self.end_headers()
  175.  
  176. reader = getattr(resp, "read1", resp.read)
  177. while True:
  178. chunk = reader(64 * 1024)
  179. if not chunk:
  180. break
  181. self.wfile.write(chunk)
  182. self.wfile.flush()
  183.  
  184. self.close_connection = True
  185.  
  186. def log_message(self, fmt, *args):
  187. sys.stderr.write("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), fmt % args))
  188.  
  189.  
  190. class OverrideProxyServer(ThreadingHTTPServer):
  191. daemon_threads = True
  192.  
  193. def __init__(self, server_address, handler_class):
  194. super().__init__(server_address, handler_class)
  195. self.target = TARGET
  196. self.temperature = TEMPERATURE
  197. self.top_k = TOP_K
  198. self.top_p = TOP_P
  199. self.min_p = MIN_P
  200. self.reasoning_effort = REASONING_EFFORT or ""
  201. self.chat_template_kwargs = CHAT_TEMPLATE_KWARGS or ""
  202. self.upstream_timeout = UPSTREAM_TIMEOUT
  203.  
  204.  
  205. def main():
  206. server = OverrideProxyServer((LISTEN_HOST, LISTEN_PORT), ProxyHandler)
  207. print(
  208. "proxy listening on http://%s:%d -> %s, temperature=%s, top_k=%s, top_p=%s, min_p=%s, reasoning_effort=%s, chat_template_kwargs=%s"
  209. % (LISTEN_HOST, LISTEN_PORT, TARGET, TEMPERATURE, TOP_K, TOP_P, MIN_P, REASONING_EFFORT or "-", CHAT_TEMPLATE_KWARGS or "-"),
  210. flush=True,
  211. )
  212. server.serve_forever()
  213.  
  214.  
  215. if __name__ == "__main__":
  216. main()
  217.  
Advertisement
Add Comment
Please, Sign In to add comment