diff --git a/admin/database/seeders/service_seeder.ts b/admin/database/seeders/service_seeder.ts index 20b40166..4abd4fb7 100644 --- a/admin/database/seeders/service_seeder.ts +++ b/admin/database/seeders/service_seeder.ts @@ -550,7 +550,7 @@ export default class ServiceSeeder extends BaseSeeder { description: 'Read the Information Library in another language. Machine translation that works offline, on CPU', icon: 'IconWorld', - container_image: 'ghcr.io/crosstalk-solutions/project-nomad-translate:0.1.0', + container_image: 'ghcr.io/crosstalk-solutions/project-nomad-translate:0.1.1', source_repo: 'https://github.com/browsermt/bergamot-translator', container_command: null, container_config: JSON.stringify({ diff --git a/install/nomad-translate/proxy.py b/install/nomad-translate/proxy.py index 78ba1aea..553f164b 100644 --- a/install/nomad-translate/proxy.py +++ b/install/nomad-translate/proxy.py @@ -40,6 +40,24 @@ MAX_TRANSLATE_BYTES = int(os.environ.get("MAX_TRANSLATE_BYTES", str(4 * 1024 * 1 COOKIE = "nomadlang" + +class _NoRedirect(urllib.request.HTTPRedirectHandler): + """Hand upstream redirects back to the browser instead of following them. + + Kiwix answers a book root such as /content/ with a 302 to the ZIM's + main page. Following it here would serve that page's HTML at the ORIGINAL + URL, so every relative link and stylesheet in it resolves one directory + too high: styling is lost and every article link 404s. + """ + + def redirect_request(self, *args, **kwargs): + return None + + +# urlopen() follows redirects by default; this opener raises them as HTTPError +# so they are forwarded below like any other non-200 response. +_opener = urllib.request.build_opener(_NoRedirect) + # Display names for the languages Bergamot's tiny model set covers. A language # only appears in the control if its model is actually on disk. LANG_NAMES = { @@ -226,12 +244,18 @@ class Handler(BaseHTTPRequestHandler): # HTML can be rewritten without decompressing first. try: - response = urllib.request.urlopen(request, timeout=120) + response = _opener.open(request, timeout=120) status, headers, data = response.status, response.headers, response.read() except urllib.error.HTTPError as exc: # Forwarded as-is, which is how Kiwix's own 404 and 400 pages keep # coming back byte for byte. status, headers, data = exc.code, exc.headers, exc.read() + # An absolute Location would point the browser at the upstream + # container name, which it cannot reach. Keep it on this origin. + location = headers.get("Location", "") + if location.startswith(UPSTREAM): + del headers["Location"] + headers["Location"] = location[len(UPSTREAM):] or "/" except Exception as exc: message = f"Translation proxy could not reach the library: {exc}".encode() self.send_response(502)