Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 55e9de3

Browse files
committed
feat: add PDF URL validation and content type check
Signed-off-by: Yukai Huang <yukaihuangtw@gmail.com>
1 parent 9448c91 commit 55e9de3

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

‎public/js/extra.js‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import './lib/renderer/lightbox'
2828
import { renderCSVPreview } from './lib/renderer/csvpreview'
2929

3030
import { escapeAttrValue } from './render'
31-
import { sanitizeUrl } from './utils'
31+
import { sanitizeUrl,isPdfUrl } from './utils'
3232

3333
import markdownit from 'markdown-it'
3434
import markdownitContainer from 'markdown-it-container'
@@ -634,11 +634,41 @@ export function finishView (view) {
634634
const cleanUrl = sanitizeUrl(url)
635635
const inner = $('<div></div>')
636636
$(this).append(inner)
637-
setTimeout(() => {
638-
PDFObject.embed(cleanUrl, inner, {
639-
height: '400px'
637+
638+
// First check URL format
639+
const isPDFByExtension = /\.pdf(\?.*)?$/i.test(cleanUrl) || cleanUrl.includes('pdf')
640+
641+
if (isPDFByExtension) {
642+
// Show loading message while we check content type
643+
const loadingMessage = $('<div class="alert alert-info">Verifying PDF file...</div>')
644+
inner.html(loadingMessage)
645+
646+
// Perform additional validation with HEAD request
647+
isPdfUrl(cleanUrl).then(isPDFByContentType => {
648+
if (isPDFByContentType) {
649+
// Valid PDF by content type, embed it
650+
PDFObject.embed(cleanUrl, inner, {
651+
height: '400px'
652+
})
653+
} else {
654+
// URL format looks like PDF but content type doesn't match
655+
inner.html('<div class="alert alert-warning">The URL looks like a PDF but the server didn\'t confirm it has a PDF content type.</div>')
656+
console.warn('URL has PDF extension but content type is not application/pdf:', cleanUrl)
657+
658+
// Try to embed anyway as a fallback
659+
setTimeout(() => {
660+
PDFObject.embed(cleanUrl, inner, {
661+
height: '400px',
662+
fallbackLink: 'This doesn\'t appear to be a valid PDF. <a href="[url]">Click here to try downloading it directly</a>.'
663+
})
664+
}, 1)
665+
}
640666
})
641-
}, 1)
667+
} else {
668+
// Not a valid PDF URL by extension
669+
inner.html('<div class="alert alert-danger">Invalid PDF URL. The URL must point to a PDF file.</div>')
670+
console.warn('Invalid PDF URL format:', cleanUrl)
671+
}
642672
})
643673
// syntax highlighting
644674
view.find('code.raw').removeClass('raw')

‎public/js/utils.js‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* global fetch */
12
import base64url from 'base64url'
23

34
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
@@ -46,3 +47,15 @@ export function sanitizeUrl (rawUrl) {
4647
return 'about:blank'
4748
}
4849
}
50+
51+
// Check if URL is a PDF based on Content-Type header
52+
export async function isPdfUrl (url) {
53+
try {
54+
const response = await fetch(url, { method: 'HEAD' })
55+
const contentType = response.headers.get('Content-Type')
56+
return contentType === 'application/pdf'
57+
} catch (error) {
58+
console.warn('Error checking PDF content type:', error)
59+
return false
60+
}
61+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /