@@ -110,6 +110,7 @@ class DomainFronter:
110110 "sec-fetch-site" ,
111111 )
112112 _SAFE_RETRY_METHODS = {"GET" , "HEAD" , "OPTIONS" }
113+ _APPS_SCRIPT_DEFAULT_LANG = "en"
113114
114115 def __init__ (self , config : dict ):
115116 self .connect_host = config .get ("google_ip" , "216.239.38.120" )
@@ -128,6 +129,9 @@ def __init__(self, config: dict):
128129 self ._script_idx = 0
129130 self .script_id = self ._script_ids [0 ] # backward compat / logging
130131 self ._dev_available = False # True if /dev endpoint works (no redirect, ~400ms faster)
132+ self ._apps_script_lang = str (
133+ config .get ("apps_script_lang" , self ._APPS_SCRIPT_DEFAULT_LANG )
134+ ).strip ().lower () or self ._APPS_SCRIPT_DEFAULT_LANG
131135
132136 # Simple execution monitor: log total consumed Apps Script executions.
133137 self ._execution_report_interval = 5.0
@@ -597,10 +601,13 @@ async def _probe_sni_latency_once(self, sni: str, sid: str) -> float | None:
597601 payload = json .dumps (
598602 {"m" : "GET" , "u" : "http://example.com/" , "k" : self .auth_key }
599603 ).encode ()
604+ path = f"/macros/s/{ sid } /exec?hl={ self ._apps_script_lang } "
600605 request = (
601- f"POST /macros/s/ { sid } /exec HTTP/1.1\r \n "
606+ f"POST { path } HTTP/1.1\r \n "
602607 f"Host: { self .http_host } \r \n "
603608 "Content-Type: application/json\r \n "
609+ "Accept: application/json,text/plain,*/*\r \n "
610+ "Accept-Language: en-US,en;q=0.9\r \n "
604611 f"Content-Length: { len (payload )} \r \n "
605612 "Connection: close\r \n \r \n "
606613 ).encode () + payload
@@ -952,7 +959,17 @@ def _exec_path(self, url_or_host: str | None = None) -> str:
952959
953960 def _exec_path_for_sid (self , sid : str ) -> str :
954961 """Build the /macros/s/<sid>/(dev|exec) path for a specific script ID."""
955- return f"/macros/s/{ sid } /{ 'dev' if self ._dev_available else 'exec' } "
962+ endpoint = "dev" if self ._dev_available else "exec"
963+ # Force Google Apps Script UI/errors to English for stable diagnostics.
964+ return f"/macros/s/{ sid } /{ endpoint } ?hl={ self ._apps_script_lang } "
965+
966+ def _apps_script_headers (self ) -> dict [str , str ]:
967+ """Headers for Apps Script relay calls (control-plane, not target origin)."""
968+ return {
969+ "content-type" : "application/json" ,
970+ "accept" : "application/json,text/plain,*/*" ,
971+ "accept-language" : "en-US,en;q=0.9" ,
972+ }
956973 async def _flush_pool (self ):
957974 """Close all pooled connections (they may be stale after errors)."""
958975 async with self ._pool_lock :
@@ -1140,13 +1157,13 @@ async def _prewarm_script(self):
11401157 payload = json .dumps (
11411158 {"m" : "GET" , "u" : "http://example.com/" , "k" : self .auth_key }
11421159 ).encode ()
1143- hdrs = { "content-type" : "application/json" }
1160+ hdrs = self . _apps_script_headers ()
11441161 sid = self ._script_ids [0 ]
11451162
11461163 # Test /dev endpoint — returns data inline (no 302 redirect).
11471164 # If it works, saves ~400ms per request by eliminating one round trip.
11481165 try :
1149- dev_path = f"/macros/s/{ sid } /dev"
1166+ dev_path = f"/macros/s/{ sid } /dev?hl= { self . _apps_script_lang } "
11501167 t0 = time .perf_counter ()
11511168 self ._record_execution (sid )
11521169 status , _ , body = await asyncio .wait_for (
@@ -1167,7 +1184,7 @@ async def _prewarm_script(self):
11671184
11681185 # Fallback: warm up with /exec
11691186 try :
1170- exec_path = f"/macros/s/{ sid } /exec"
1187+ exec_path = f"/macros/s/{ sid } /exec?hl= { self . _apps_script_lang } "
11711188 t0 = time .perf_counter ()
11721189 self ._record_execution (sid )
11731190 await asyncio .wait_for (
@@ -1233,7 +1250,7 @@ async def _keepalive_loop(self):
12331250 await asyncio .wait_for (
12341251 self ._h2 .request (
12351252 method = "POST" , path = path , host = self .http_host ,
1236- headers = { "content-type" : "application/json" } ,
1253+ headers = self . _apps_script_headers () ,
12371254 body = json .dumps (payload ).encode (),
12381255 ),
12391256 timeout = 20 ,
@@ -2595,7 +2612,7 @@ async def _relay_single_h2(self, payload: dict) -> bytes:
25952612 t0 = time .perf_counter ()
25962613 status , headers , body = await (self ._pick_h2 () or self ._h2 ).request (
25972614 method = "POST" , path = path , host = self .http_host ,
2598- headers = { "content-type" : "application/json" } ,
2615+ headers = self . _apps_script_headers () ,
25992616 body = json_body ,
26002617 timeout = self ._relay_timeout ,
26012618 )
@@ -2626,7 +2643,7 @@ async def _relay_single_h2_with_sid(self, payload: dict,
26262643
26272644 status , headers , body = await (self ._pick_h2 () or self ._h2 ).request (
26282645 method = "POST" , path = path , host = self .http_host ,
2629- headers = { "content-type" : "application/json" } ,
2646+ headers = self . _apps_script_headers () ,
26302647 body = json_body ,
26312648 timeout = self ._relay_timeout ,
26322649 )
@@ -2664,6 +2681,8 @@ async def _follow_redirects(
26642681 request_lines = [
26652682 f"{ redirect_method } { rpath } HTTP/1.1" ,
26662683 f"Host: { parsed .netloc } " ,
2684+ "Accept: application/json,text/plain,*/*" ,
2685+ "Accept-Language: en-US,en;q=0.9" ,
26672686 "Accept-Encoding: gzip" ,
26682687 "Connection: keep-alive" ,
26692688 ]
@@ -2693,6 +2712,8 @@ async def _relay_single(self, payload: dict) -> bytes:
26932712 f"POST { path } HTTP/1.1\r \n "
26942713 f"Host: { self .http_host } \r \n "
26952714 f"Content-Type: application/json\r \n "
2715+ f"Accept: application/json,text/plain,*/*\r \n "
2716+ f"Accept-Language: en-US,en;q=0.9\r \n "
26962717 f"Content-Length: { len (json_body )} \r \n "
26972718 f"Accept-Encoding: gzip\r \n "
26982719 f"Connection: keep-alive\r \n "
@@ -2745,7 +2766,7 @@ async def _relay_batch(self, payloads: list[dict]) -> list[bytes]:
27452766 status , headers , body = await asyncio .wait_for (
27462767 (self ._pick_h2 () or self ._h2 ).request (
27472768 method = "POST" , path = path , host = self .http_host ,
2748- headers = { "content-type" : "application/json" } ,
2769+ headers = self . _apps_script_headers () ,
27492770 body = json_body ,
27502771 timeout = batch_timeout ,
27512772 ),
0 commit comments