mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-17 21:24:37 +03:00
fix: Enhance Apps Script language handling and improve response parsing logic
This commit is contained in:
@@ -110,6 +110,7 @@ class DomainFronter:
|
||||
"sec-fetch-site",
|
||||
)
|
||||
_SAFE_RETRY_METHODS = {"GET", "HEAD", "OPTIONS"}
|
||||
_APPS_SCRIPT_DEFAULT_LANG = "en"
|
||||
|
||||
def __init__(self, config: dict):
|
||||
self.connect_host = config.get("google_ip", "216.239.38.120")
|
||||
@@ -128,6 +129,9 @@ class DomainFronter:
|
||||
self._script_idx = 0
|
||||
self.script_id = self._script_ids[0] # backward compat / logging
|
||||
self._dev_available = False # True if /dev endpoint works (no redirect, ~400ms faster)
|
||||
self._apps_script_lang = str(
|
||||
config.get("apps_script_lang", self._APPS_SCRIPT_DEFAULT_LANG)
|
||||
).strip().lower() or self._APPS_SCRIPT_DEFAULT_LANG
|
||||
|
||||
# Simple execution monitor: log total consumed Apps Script executions.
|
||||
self._execution_report_interval = 5.0
|
||||
@@ -597,10 +601,13 @@ class DomainFronter:
|
||||
payload = json.dumps(
|
||||
{"m": "GET", "u": "http://example.com/", "k": self.auth_key}
|
||||
).encode()
|
||||
path = f"/macros/s/{sid}/exec?hl={self._apps_script_lang}"
|
||||
request = (
|
||||
f"POST /macros/s/{sid}/exec HTTP/1.1\r\n"
|
||||
f"POST {path} HTTP/1.1\r\n"
|
||||
f"Host: {self.http_host}\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Accept: application/json,text/plain,*/*\r\n"
|
||||
"Accept-Language: en-US,en;q=0.9\r\n"
|
||||
f"Content-Length: {len(payload)}\r\n"
|
||||
"Connection: close\r\n\r\n"
|
||||
).encode() + payload
|
||||
@@ -952,7 +959,17 @@ class DomainFronter:
|
||||
|
||||
def _exec_path_for_sid(self, sid: str) -> str:
|
||||
"""Build the /macros/s/<sid>/(dev|exec) path for a specific script ID."""
|
||||
return f"/macros/s/{sid}/{'dev' if self._dev_available else 'exec'}"
|
||||
endpoint = "dev" if self._dev_available else "exec"
|
||||
# Force Google Apps Script UI/errors to English for stable diagnostics.
|
||||
return f"/macros/s/{sid}/{endpoint}?hl={self._apps_script_lang}"
|
||||
|
||||
def _apps_script_headers(self) -> dict[str, str]:
|
||||
"""Headers for Apps Script relay calls (control-plane, not target origin)."""
|
||||
return {
|
||||
"content-type": "application/json",
|
||||
"accept": "application/json,text/plain,*/*",
|
||||
"accept-language": "en-US,en;q=0.9",
|
||||
}
|
||||
async def _flush_pool(self):
|
||||
"""Close all pooled connections (they may be stale after errors)."""
|
||||
async with self._pool_lock:
|
||||
@@ -1140,13 +1157,13 @@ class DomainFronter:
|
||||
payload = json.dumps(
|
||||
{"m": "GET", "u": "http://example.com/", "k": self.auth_key}
|
||||
).encode()
|
||||
hdrs = {"content-type": "application/json"}
|
||||
hdrs = self._apps_script_headers()
|
||||
sid = self._script_ids[0]
|
||||
|
||||
# Test /dev endpoint — returns data inline (no 302 redirect).
|
||||
# If it works, saves ~400ms per request by eliminating one round trip.
|
||||
try:
|
||||
dev_path = f"/macros/s/{sid}/dev"
|
||||
dev_path = f"/macros/s/{sid}/dev?hl={self._apps_script_lang}"
|
||||
t0 = time.perf_counter()
|
||||
self._record_execution(sid)
|
||||
status, _, body = await asyncio.wait_for(
|
||||
@@ -1167,7 +1184,7 @@ class DomainFronter:
|
||||
|
||||
# Fallback: warm up with /exec
|
||||
try:
|
||||
exec_path = f"/macros/s/{sid}/exec"
|
||||
exec_path = f"/macros/s/{sid}/exec?hl={self._apps_script_lang}"
|
||||
t0 = time.perf_counter()
|
||||
self._record_execution(sid)
|
||||
await asyncio.wait_for(
|
||||
@@ -1233,7 +1250,7 @@ class DomainFronter:
|
||||
await asyncio.wait_for(
|
||||
self._h2.request(
|
||||
method="POST", path=path, host=self.http_host,
|
||||
headers={"content-type": "application/json"},
|
||||
headers=self._apps_script_headers(),
|
||||
body=json.dumps(payload).encode(),
|
||||
),
|
||||
timeout=20,
|
||||
@@ -2595,7 +2612,7 @@ class DomainFronter:
|
||||
t0 = time.perf_counter()
|
||||
status, headers, body = await (self._pick_h2() or self._h2).request(
|
||||
method="POST", path=path, host=self.http_host,
|
||||
headers={"content-type": "application/json"},
|
||||
headers=self._apps_script_headers(),
|
||||
body=json_body,
|
||||
timeout=self._relay_timeout,
|
||||
)
|
||||
@@ -2626,7 +2643,7 @@ class DomainFronter:
|
||||
|
||||
status, headers, body = await (self._pick_h2() or self._h2).request(
|
||||
method="POST", path=path, host=self.http_host,
|
||||
headers={"content-type": "application/json"},
|
||||
headers=self._apps_script_headers(),
|
||||
body=json_body,
|
||||
timeout=self._relay_timeout,
|
||||
)
|
||||
@@ -2664,6 +2681,8 @@ class DomainFronter:
|
||||
request_lines = [
|
||||
f"{redirect_method} {rpath} HTTP/1.1",
|
||||
f"Host: {parsed.netloc}",
|
||||
"Accept: application/json,text/plain,*/*",
|
||||
"Accept-Language: en-US,en;q=0.9",
|
||||
"Accept-Encoding: gzip",
|
||||
"Connection: keep-alive",
|
||||
]
|
||||
@@ -2693,6 +2712,8 @@ class DomainFronter:
|
||||
f"POST {path} HTTP/1.1\r\n"
|
||||
f"Host: {self.http_host}\r\n"
|
||||
f"Content-Type: application/json\r\n"
|
||||
f"Accept: application/json,text/plain,*/*\r\n"
|
||||
f"Accept-Language: en-US,en;q=0.9\r\n"
|
||||
f"Content-Length: {len(json_body)}\r\n"
|
||||
f"Accept-Encoding: gzip\r\n"
|
||||
f"Connection: keep-alive\r\n"
|
||||
@@ -2745,7 +2766,7 @@ class DomainFronter:
|
||||
status, headers, body = await asyncio.wait_for(
|
||||
(self._pick_h2() or self._h2).request(
|
||||
method="POST", path=path, host=self.http_host,
|
||||
headers={"content-type": "application/json"},
|
||||
headers=self._apps_script_headers(),
|
||||
body=json_body,
|
||||
timeout=batch_timeout,
|
||||
),
|
||||
|
||||
@@ -787,11 +787,13 @@ def parse_relay_response(body: bytes, max_body_bytes: int) -> bytes:
|
||||
elif preview_lower.startswith("<"):
|
||||
# HTML response from script.google.com usually indicates that
|
||||
# Deployment ID is wrong/archived or the deployment was not updated.
|
||||
# This signature commonly appears as a generic Google Docs wrapper.
|
||||
# Match only Apps Script-specific wrappers to avoid false positives
|
||||
# when the destination site itself is RTL or hosted on docs.google.com.
|
||||
if any(sig in preview_lower for sig in (
|
||||
"web word processing, presentations and spreadsheets",
|
||||
"docs.google.com",
|
||||
"google docs",
|
||||
"goog.script.init",
|
||||
"script.google.com/macros",
|
||||
"/macros/s/",
|
||||
)):
|
||||
error_msg = (
|
||||
"Wrong Apps Script deployment (script_id). "
|
||||
|
||||
Reference in New Issue
Block a user