Enable raw file content proxy for files up to 4MB (#546)
Co-authored-by: spencerwooo <spencer.woo@outlook.com>
This commit is contained in:
parent
520792d86f
commit
7df0453269
7 changed files with 23 additions and 65 deletions
|
@ -82,13 +82,6 @@ const DownloadButtonGroup = () => {
|
|||
btnIcon="file-download"
|
||||
btnTitle={t('Download the file directly through OneDrive')}
|
||||
/>
|
||||
{/* <DownloadButton
|
||||
onClickCallback={() => window.open(`/api/proxy?url=${encodeURIComponent(downloadUrl)}`)}
|
||||
btnColor="teal"
|
||||
btnText={t('Proxy download')}
|
||||
btnIcon="download"
|
||||
btnTitle={t('Download the file with the stream proxied through Vercel Serverless')}
|
||||
/> */}
|
||||
<DownloadButton
|
||||
onClickCallback={() => {
|
||||
clipboard.copy(`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`)
|
||||
|
|
|
@ -370,7 +370,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
|
|||
|
||||
{readmeFile && (
|
||||
<div className="mt-4">
|
||||
<MarkdownPreview file={readmeFile} path={path} standalone={false} />
|
||||
<MarkdownPreview file={readmeFile} path={path} standalone={false} proxy={true} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -20,11 +20,16 @@ const MarkdownPreview: FC<{
|
|||
file: any
|
||||
path: string
|
||||
standalone?: boolean
|
||||
}> = ({ file, path, standalone = true }) => {
|
||||
proxy?: boolean
|
||||
}> = ({ file, path, standalone = true, proxy = false }) => {
|
||||
// The parent folder of the markdown file, which is also the relative image folder
|
||||
const parentPath = standalone ? path.substring(0, path.lastIndexOf('/')) : path
|
||||
|
||||
const { response: content, error, validating } = useFileContent(`/api/raw/?path=${parentPath}/${file.name}`, path)
|
||||
const {
|
||||
response: content,
|
||||
error,
|
||||
validating,
|
||||
} = useFileContent(`/api/raw/?path=${parentPath}/${file.name}${proxy ? `&proxy=true` : ''}`, path)
|
||||
const { t } = useTranslation()
|
||||
|
||||
// Check if the image is relative path instead of a absolute url
|
||||
|
|
|
@ -8,7 +8,6 @@ const PDFEmbedPreview: React.FC<{ file: any }> = ({ file }) => {
|
|||
const { asPath } = useRouter()
|
||||
const hashedToken = getStoredToken(asPath)
|
||||
|
||||
// const url = `/api/proxy?url=${encodeURIComponent(...)}&inline=true`
|
||||
const pdfPath = encodeURIComponent(
|
||||
`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`
|
||||
)
|
||||
|
|
|
@ -132,14 +132,6 @@ const VideoPreview: FC<{ file: OdFileObject }> = ({ file }) => {
|
|||
btnText={t('Download')}
|
||||
btnIcon="file-download"
|
||||
/>
|
||||
{/* <DownloadButton
|
||||
onClickCallback={() =>
|
||||
window.open(`/api/proxy?url=${encodeURIComponent(...)}`)
|
||||
}
|
||||
btnColor="teal"
|
||||
btnText={t('Proxy download')}
|
||||
btnIcon="download"
|
||||
/> */}
|
||||
<DownloadButton
|
||||
onClickCallback={() => {
|
||||
clipboard.copy(`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`)
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
import axios from 'axios'
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import apiConfig from '../../config/api.config'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// 'inline' is used for previewing PDF files inside the browser directly
|
||||
const { url, inline = false } = req.query
|
||||
|
||||
if (!url || typeof url !== 'string') {
|
||||
res.status(400).json({ error: 'Bad request, URL is not valid.' })
|
||||
return
|
||||
}
|
||||
|
||||
// Only handle urls that start with OneDrive's own direct link (or SharePoint's):
|
||||
// https://public.*.files.1drv.com/y4m0G_0GPeS8AXGrux-lVV79eU1F38VbWxtCSi-8-aUkBLeZH1H6...
|
||||
const hostname = new URL(url).hostname
|
||||
if (hostname.match(new RegExp(apiConfig.directLinkRegex)) === null) {
|
||||
res
|
||||
.status(400)
|
||||
.json({ error: `URL forbidden, only OneDrive direct links that match ${apiConfig.directLinkRegex} are allowed.` })
|
||||
return
|
||||
}
|
||||
|
||||
const { headers, data: stream } = await axios.get(url as string, {
|
||||
responseType: 'stream',
|
||||
})
|
||||
|
||||
// Check if requested file is PDF based on content-type
|
||||
if (headers['content-type'] === 'application/pdf' && inline) {
|
||||
// Get filename from content-disposition header
|
||||
const filename = headers['content-disposition'].split(/filename[*]?=/)[1]
|
||||
// Remove original content-disposition header
|
||||
delete headers['content-disposition']
|
||||
// Add new inline content-disposition header along with filename
|
||||
headers['content-disposition'] = `inline; filename*=UTF-8''${filename}`
|
||||
}
|
||||
|
||||
// Send data stream as response
|
||||
res.writeHead(200, headers)
|
||||
stream.pipe(res)
|
||||
}
|
|
@ -4,7 +4,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'
|
|||
import axios from 'axios'
|
||||
import Cors from 'cors'
|
||||
|
||||
import { driveApi } from '../../config/api.config'
|
||||
import { driveApi, cacheControlHeader } from '../../config/api.config'
|
||||
import { encodePath, getAccessToken, checkAuthRoute } from '.'
|
||||
|
||||
// CORS middleware for raw links: https://nextjs.org/docs/api-routes/api-middlewares
|
||||
|
@ -28,7 +28,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
return
|
||||
}
|
||||
|
||||
const { path = '/', odpt = '' } = req.query
|
||||
const { path = '/', odpt = '', proxy = false } = req.query
|
||||
|
||||
// Sometimes the path parameter is defaulted to '[...path]' which we need to handle
|
||||
if (path === '[...path]') {
|
||||
|
@ -65,12 +65,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
params: {
|
||||
// OneDrive international version fails when only selecting the downloadUrl (what a stupid bug)
|
||||
select: 'id,@microsoft.graph.downloadUrl',
|
||||
select: 'id,size,@microsoft.graph.downloadUrl',
|
||||
},
|
||||
})
|
||||
|
||||
if ('@microsoft.graph.downloadUrl' in data) {
|
||||
res.redirect(data['@microsoft.graph.downloadUrl'])
|
||||
// Only proxy raw file content response for files up to 4MB
|
||||
if (proxy && 'size' in data && data['size'] < 4194304) {
|
||||
const { headers, data: stream } = await axios.get(data['@microsoft.graph.downloadUrl'] as string, {
|
||||
responseType: 'stream',
|
||||
})
|
||||
headers['Cache-Control'] = cacheControlHeader
|
||||
// Send data stream as response
|
||||
res.writeHead(200, headers)
|
||||
stream.pipe(res)
|
||||
} else {
|
||||
res.redirect(data['@microsoft.graph.downloadUrl'])
|
||||
}
|
||||
} else {
|
||||
res.status(404).json({ error: 'No download url found.' })
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue