v1.8.3
• cache spreadsheet اختیاری در Code.gs برای کاهش مصرف quota (#400، PR #443 از @euvel): GET requests عمومی که Cache-Control header دارن میتونن از Google Sheet بهجای Apps Script's UrlFetchApp serve بشن. هزینهی هر cache hit ~۵-۲۰ms (Sheet read) بهجای ۲۵۰-۵۰۰ms (UrlFetchApp roundtrip). features کامل: TTL-aware (max-age, no-cache, no-store, private respect)، header rewriting (Date/Age/X-Cache)، circular buffer برای O(1) writes، Vary-aware با Accept-Encoding/Accept-Language. opt-in via یک constant CACHE_SPREADSHEET_ID در Code.gs — default غیرفعال، بدون overhead برای کاربران که نمیخوان. setup: ساخت یک Google Sheet جدید + قرار دادن ID آن در CACHE_SPREADSHEET_ID + redeploy as new version
• bypass DoH endpoints from Apps Script tunnel (#377، PR #439 از @dazzling-no-more): قبلاً در Full mode هر DNS-over-HTTPS lookup browser از طریق Apps Script tunnel میرفت — chrome.cloudflare-dns.com:443، dns.google:443 و سایر هزینه ~۲ ثانیه UrlFetchApp roundtrip به ازای هر name داشتن. ولی DoH از قبل encrypted هست + tunnel privacy اضافهای نمیده — فقط fact-of-DoH رو از local network مخفی میکنه که ناچیزه. حالا bypass_doh_hosts config (default true) routes DoH lookups مستقیم via TCP/443. لیست کامل bypass شامل: Cloudflare (incl. chrome./mozilla./1dot1dot1dot1.)، Google، Quad9، AdGuard، NextDNS، OpenDNS، CleanBrowsing، dns.sb، dns0.eu، AliDNS، doh.pub، Mullvad. کاربران میتوانند با tunnel_doh: true در config opt-out کنن یا با bypass_doh_hosts: ["custom1.com", "custom2.com"] لیست رو extend کنن
• H1 container keepalive (~۲۴۰s) برای جلوگیری از Apps Script V8 cold-start stalls (PR #438 از @dazzling-no-more): Apps Script containerها بعد از ~۵ دقیقه idle cold میشن + ۱-۳ ثانیه به wake-up زمان میبرن. این بهخصوص در YouTube playback بعد از pause طولانی stall بهوضوح دیده میشد. با ping HEAD به example.com هر ۲۴۰ ثانیه از طریق relay، container warm نگه داشته میشه. cache + inflight coalescer bypass شده تا ping واقعاً به Apps Script برسه. در google_only mode غیرفعال
• 431 Request Header Fields Too Large بهجای drop سکوتی (PR #438 از @dazzling-no-more): قبلاً اگر header block > ۱ MB میشد، socket drop میشد + browser silently retry میکرد + loop ابدی. حالا cap به ۶۴ KB کاهش یافته (match upstream Python) + explicit HTTP/1.1 431 Request Header Fields Too Large response برمیگرده + close میشه. browser ارور رو ببینه + loop رو نمیسازه
• پیام error config port-collision واضحتر شد (PR #438): قبلاً پیام cryptic بود. حالا: "both set to 8080 on 127.0.0.1. Change one of them in config.json." — کاربر مستقیم میفهمه چی fix بکنه
• Optional spreadsheet-backed response cache in Code.gs to reduce UrlFetchApp quota consumption (#400, PR #443 by @euvel): public GET requests with Cache-Control headers can now be served from a Google Sheet instead of round-tripping through UrlFetchApp. Cache hit costs ~5-20ms (Sheet read) vs ~250-500ms (UrlFetchApp). Features: TTL-aware caching (respects max-age, no-cache, no-store, private), 35 KB body-size gate (under the Sheets cell limit), header rewriting (Date/Age/Cache-Control/X-Cache/X-Cached-At), circular buffer for O(1) writes, Vary-aware compound keys (Accept-Encoding + Accept-Language). Opt-in via a single CACHE_SPREADSHEET_ID constant — default off, zero overhead for users who don't want it. Setup: create a new Google Sheet, paste its ID into CACHE_SPREADSHEET_ID, redeploy as new version. Run getCacheStats() from the Apps Script editor to see hit/miss/eviction counts.
• Bypass Apps Script tunnel for DoH endpoints on TCP/443 (#377, PR #439 by @dazzling-no-more): previously every browser DNS-over-HTTPS lookup in Full mode rode through the Apps Script tunnel — chrome.cloudflare-dns.com:443, dns.google:443, etc. each paid the ~2-second UrlFetchApp round-trip per name. But DoH is already encrypted at the transport layer; tunneling it adds no real privacy (only hiding fact-of-DoH from the local network, which is marginal). Now bypass_doh_hosts config (default true) routes known DoH hosts around the tunnel via plain TCP. Built-in list: Cloudflare (incl. chrome./mozilla./1dot1dot1dot1. browser-pinned variants), Google, Quad9, AdGuard, NextDNS, OpenDNS, CleanBrowsing, dns.sb, dns0.eu, AliDNS, doh.pub, Mullvad. Users can opt out with tunnel_doh: true or extend the list with bypass_doh_hosts: ["custom1.com", "custom2.com"]. Gated to TCP/443 only — private DoH endpoints on :8443 should use passthrough_hosts instead. ProxyServer warns at startup if tunnel_doh: true is paired with non-empty bypass_doh_hosts (the otherwise-silent inert combo). 6 unit tests for matches_doh_host covering exact match, case insensitivity, trailing dots, suffix tenant subdomains, user extras extending the default list, and the asymmetric-matching footgun guard.
• H1 container keepalive (~240s) to prevent Apps Script V8 cold-start stalls (PR #438 by @dazzling-no-more): Apps Script V8 containers go cold after ~5 minutes idle and cost 1-3s to wake. Most visible as YouTube player stalls after a quiet pause. Now sends a HEAD http://example.com/ ping every 240s through the relay to keep the container warm. Bypasses the response cache and inflight coalescer (otherwise the second iteration would just hit the cache and never reach Apps Script). Skipped in google_only mode. The JoinHandle is captured so shutdown's select! arm can abort it cleanly — without that, hitting Stop in the UI would leave the keepalive holding an Arc<DomainFronter> on stale config (same class of bug as #99 hit for accept loops).
• 431 Request Header Fields Too Large instead of silent drop (PR #438 by @dazzling-no-more): previously header blocks larger than 1 MB were silently dropped at the socket level, causing browsers to retry on connection-reset and loop indefinitely on the same oversized request. Now the cap is tightened to 64 KB (matching upstream Python's MAX_HEADER_BYTES) and oversized requests get an explicit HTTP/1.1 431 Request Header Fields Too Large reply followed by close. Both the plaintext HTTP frontend and the MITM HTTPS relay path now do this. Browsers see the error and don't loop.
• Clearer port-collision error message (PR #438): the same-port validation already existed; only the message was vague. Now reads: "both set to 8080 on 127.0.0.1. Change one of them in config.json." matching upstream Python's clarity.
What's Changed
- feat: H1 container keepalive + 431 oversized-headers by @dazzling-no-more in #438
- feat: bypass Apps Script tunnel for DoH endpoints on TCP/443 by @dazzling-no-more in #439
- feat(code.gs): optional spreadsheet-backed response cache with TTL by @euvel in #443
New Contributors
Full Changelog: v1.8.2...v1.8.3