rafmacalaba commited on
Commit
e7f7858
·
1 Parent(s): fb404c5

fix: proxy PDFs through /api/pdf-proxy to bypass CORS

Browse files

World Bank PDF server blocks cross-origin requests, preventing
Mozilla's hosted PDF.js from loading them. Now PDFs are proxied
through our own API endpoint, and the browser's built-in PDF
viewer renders them via iframe.

app/api/pdf-proxy/route.js ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * GET /api/pdf-proxy?url=<encoded_pdf_url>
5
+ * Proxies a PDF from an external URL to bypass CORS restrictions.
6
+ * Returns the PDF with correct Content-Type so PDF.js can render it.
7
+ */
8
+ export async function GET(request) {
9
+ const { searchParams } = new URL(request.url);
10
+ const pdfUrl = searchParams.get('url');
11
+
12
+ if (!pdfUrl) {
13
+ return NextResponse.json({ error: 'Missing url parameter' }, { status: 400 });
14
+ }
15
+
16
+ try {
17
+ const res = await fetch(pdfUrl, {
18
+ headers: {
19
+ 'User-Agent': 'Mozilla/5.0 (compatible; AnnotationTool/1.0)',
20
+ },
21
+ signal: AbortSignal.timeout(30000), // 30s timeout
22
+ });
23
+
24
+ if (!res.ok) {
25
+ return NextResponse.json(
26
+ { error: `PDF fetch failed: HTTP ${res.status}` },
27
+ { status: res.status }
28
+ );
29
+ }
30
+
31
+ const pdfBuffer = await res.arrayBuffer();
32
+
33
+ return new Response(pdfBuffer, {
34
+ status: 200,
35
+ headers: {
36
+ 'Content-Type': 'application/pdf',
37
+ 'Content-Length': pdfBuffer.byteLength.toString(),
38
+ 'Cache-Control': 'public, max-age=86400', // cache 24h
39
+ 'Access-Control-Allow-Origin': '*',
40
+ },
41
+ });
42
+ } catch (error) {
43
+ console.error('PDF proxy error:', error);
44
+ return NextResponse.json(
45
+ { error: 'Failed to proxy PDF: ' + error.message },
46
+ { status: 500 }
47
+ );
48
+ }
49
+ }
app/components/PdfViewer.js CHANGED
@@ -23,9 +23,9 @@ export default function PdfViewer({ pdfUrl, pageNumber }) {
23
  // PDF pages in our data are 0-indexed; PDF.js viewer expects 1-indexed pages
24
  const viewerPage = (pageNumber ?? 0) + 1;
25
 
26
- // Use Mozilla's hosted PDF.js viewer supports #page=N for direct page navigation.
27
- // This avoids X-Frame-Options restrictions from the source server.
28
- const pdfJsViewerUrl = `https://mozilla.github.io/pdf.js/web/viewer.html?file=${encodeURIComponent(pdfUrl)}#page=${viewerPage}`;
29
 
30
  return (
31
  <div className="pdf-container">
@@ -47,7 +47,7 @@ export default function PdfViewer({ pdfUrl, pageNumber }) {
47
  )}
48
  <iframe
49
  key={`pdf-${pdfUrl}-page-${viewerPage}`}
50
- src={pdfJsViewerUrl}
51
  className="pdf-frame"
52
  title={`PDF Page ${viewerPage}`}
53
  allow="fullscreen"
 
23
  // PDF pages in our data are 0-indexed; PDF.js viewer expects 1-indexed pages
24
  const viewerPage = (pageNumber ?? 0) + 1;
25
 
26
+ // Proxy the PDF through our own API to bypass CORS restrictions.
27
+ // Then use the browser's built-in PDF viewer via <object> tag.
28
+ const proxyUrl = `/api/pdf-proxy?url=${encodeURIComponent(pdfUrl)}#page=${viewerPage}`;
29
 
30
  return (
31
  <div className="pdf-container">
 
47
  )}
48
  <iframe
49
  key={`pdf-${pdfUrl}-page-${viewerPage}`}
50
+ src={proxyUrl}
51
  className="pdf-frame"
52
  title={`PDF Page ${viewerPage}`}
53
  allow="fullscreen"