mirror of
https://github.com/Nezumi-2711/onedrive-vercel-index.git
synced 2026-09-22 13:38:45 +00:00
Enable raw file content proxy for files up to 4MB (#546)
Co-authored-by: spencerwooo <spencer.woo@outlook.com>
This commit is contained in:
@@ -82,13 +82,6 @@ const DownloadButtonGroup = () => {
|
|||||||
btnIcon="file-download"
|
btnIcon="file-download"
|
||||||
btnTitle={t('Download the file directly through OneDrive')}
|
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
|
<DownloadButton
|
||||||
onClickCallback={() => {
|
onClickCallback={() => {
|
||||||
clipboard.copy(`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`)
|
clipboard.copy(`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`)
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
|
|||||||
|
|
||||||
{readmeFile && (
|
{readmeFile && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<MarkdownPreview file={readmeFile} path={path} standalone={false} />
|
<MarkdownPreview file={readmeFile} path={path} standalone={false} proxy={true} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -20,11 +20,16 @@ const MarkdownPreview: FC<{
|
|||||||
file: any
|
file: any
|
||||||
path: string
|
path: string
|
||||||
standalone?: boolean
|
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
|
// The parent folder of the markdown file, which is also the relative image folder
|
||||||
const parentPath = standalone ? path.substring(0, path.lastIndexOf('/')) : path
|
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()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// Check if the image is relative path instead of a absolute url
|
// 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 { asPath } = useRouter()
|
||||||
const hashedToken = getStoredToken(asPath)
|
const hashedToken = getStoredToken(asPath)
|
||||||
|
|
||||||
// const url = `/api/proxy?url=${encodeURIComponent(...)}&inline=true`
|
|
||||||
const pdfPath = encodeURIComponent(
|
const pdfPath = encodeURIComponent(
|
||||||
`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`
|
`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -132,14 +132,6 @@ const VideoPreview: FC<{ file: OdFileObject }> = ({ file }) => {
|
|||||||
btnText={t('Download')}
|
btnText={t('Download')}
|
||||||
btnIcon="file-download"
|
btnIcon="file-download"
|
||||||
/>
|
/>
|
||||||
{/* <DownloadButton
|
|
||||||
onClickCallback={() =>
|
|
||||||
window.open(`/api/proxy?url=${encodeURIComponent(...)}`)
|
|
||||||
}
|
|
||||||
btnColor="teal"
|
|
||||||
btnText={t('Proxy download')}
|
|
||||||
btnIcon="download"
|
|
||||||
/> */}
|
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
onClickCallback={() => {
|
onClickCallback={() => {
|
||||||
clipboard.copy(`${getBaseUrl()}/api/raw/?path=${asPath}${hashedToken ? `&odpt=${hashedToken}` : ''}`)
|
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)
|
|
||||||
}
|
|
||||||
+15
-4
@@ -4,7 +4,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import Cors from 'cors'
|
import Cors from 'cors'
|
||||||
|
|
||||||
import { driveApi } from '../../config/api.config'
|
import { driveApi, cacheControlHeader } from '../../config/api.config'
|
||||||
import { encodePath, getAccessToken, checkAuthRoute } from '.'
|
import { encodePath, getAccessToken, checkAuthRoute } from '.'
|
||||||
|
|
||||||
// CORS middleware for raw links: https://nextjs.org/docs/api-routes/api-middlewares
|
// 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
|
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
|
// Sometimes the path parameter is defaulted to '[...path]' which we need to handle
|
||||||
if (path === '[...path]') {
|
if (path === '[...path]') {
|
||||||
@@ -65,12 +65,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
headers: { Authorization: `Bearer ${accessToken}` },
|
headers: { Authorization: `Bearer ${accessToken}` },
|
||||||
params: {
|
params: {
|
||||||
// OneDrive international version fails when only selecting the downloadUrl (what a stupid bug)
|
// 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) {
|
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 {
|
} else {
|
||||||
res.status(404).json({ error: 'No download url found.' })
|
res.status(404).json({ error: 'No download url found.' })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user