"""tools/fetch_page.py is the browser-header retry from 09-web-research.md. Why this test exists: the retry used to be a documented `curl` invocation plus an inline `python3 -c` tag-stripper, which meant the workflow needed a `Bash(curl:*)` grant - and `curl` with a free tail is an upload channel. The script replaces both with one GET-only command whose argv is fixed, that enforces the robots.txt gate itself, and that refuses to write inside the repo. These tests pin each of those properties against a real local server. """ import contextlib import http.server import io import shutil import sys import tempfile import threading import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(REPO_ROOT / "tools")) import fetch_page # noqa: E402 PAGE = ( "Posting" "" "" "" "

Visible title

Visible text & more.

" "svg text" "" ) KOREAN_PAGE = ( '' "채용공고

백엔드 개발자 채용

" ) CONTENT_TYPES = {"/euc-kr.html": "text/html; charset=euc-kr"} class _Handler(http.server.BaseHTTPRequestHandler): def do_GET(self): # noqa: N802 (http.server naming) self.server.paths.append(self.path) if self.path in ("/ok.html", "/ok.html?q=a%20b", "/ok.html?t=%C3%A6%C3%B8%C3%A5") or ( self.path.startswith("/unicode/") and self.path.endswith("?page=2") ): body = PAGE.encode("utf-8") self.send_response(200) elif self.path.startswith("/unicode/"): self.send_response(302) self.send_header("Location", "?page=2") self.send_header("Content-Length", "0") self.end_headers() return elif self.path == "/redirect-utf8": # http.server writes header values as latin-1; preserve raw UTF-8 bytes. self.send_response(302) self.send_header("Location", "/ok.html?t=" + "æøå".encode("utf-8").decode("latin-1")) self.send_header("Content-Length", "0") self.end_headers() return elif self.path == "/euc-kr.html": body = KOREAN_PAGE.encode("cp949") self.send_response(200) elif self.path == "/robots.txt": body = b"User-agent: *\nAllow: /redirect\nDisallow: /blocked\n" self.send_response(200) elif self.path in ("/redirect", "/redirect-allowed"): self.send_response(302) self.send_header("Location", "/blocked" if self.path == "/redirect" else "/ok.html") self.send_header("Content-Length", "0") self.end_headers() return elif self.path == "/redirect-space": self.send_response(302) self.send_header("Location", "/ok.html?q=a b") self.send_header("Content-Length", "0") self.end_headers() return elif self.path == "/redirect-other": self.send_response(302) self.send_header("Location", self.server.redirect_to) self.send_header("Content-Length", "0") self.end_headers() return elif self.path == "/blocked": body = b"blocked posting" self.send_response(200) elif self.path == "/forbidden": body = b"denied" self.send_response(403) elif self.path == "/open-script.html": body = ( b"

Visible role