Add reviews and support tutorial management
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { NextRequest } from 'next/server'
|
||||
|
||||
import { eversoloPasteURLAllowList } from '@/payload/upload-paste-url-allow-list'
|
||||
|
||||
export const runtime = 'nodejs'
|
||||
|
||||
const retryDelays = [0, 300, 800, 1500]
|
||||
const fetchTimeoutMs = 10000
|
||||
|
||||
function isAllowedPasteURL(value: string) {
|
||||
try {
|
||||
const url = new URL(value)
|
||||
|
||||
return eversoloPasteURLAllowList.some((allowItem) => {
|
||||
return url.protocol === `${allowItem.protocol}:` && url.hostname === allowItem.hostname
|
||||
})
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function wait(delay: number) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, delay)
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchWithRetry(src: string) {
|
||||
let lastError: unknown
|
||||
|
||||
for (const [index, delay] of retryDelays.entries()) {
|
||||
if (delay > 0) {
|
||||
await wait(delay)
|
||||
}
|
||||
|
||||
const controller = new AbortController()
|
||||
const timeout = setTimeout(() => {
|
||||
controller.abort()
|
||||
}, fetchTimeoutMs)
|
||||
|
||||
try {
|
||||
const response = await fetch(src, {
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
'user-agent':
|
||||
'Mozilla/5.0 (compatible; EversoloWebPasteImporter/1.0; +https://www.eversolo.com)',
|
||||
},
|
||||
redirect: 'follow',
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
if (response.ok || response.status < 500 || index === retryDelays.length - 1) {
|
||||
return response
|
||||
}
|
||||
} catch (error) {
|
||||
lastError = error
|
||||
} finally {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const src = request.nextUrl.searchParams.get('src')
|
||||
|
||||
if (!src || !isAllowedPasteURL(src)) {
|
||||
return new Response('URL is not allowed.', { status: 400 })
|
||||
}
|
||||
|
||||
let upstream: Response
|
||||
|
||||
try {
|
||||
upstream = await fetchWithRetry(src)
|
||||
} catch {
|
||||
return new Response('Failed to fetch the file.', { status: 502 })
|
||||
}
|
||||
|
||||
if (!upstream.ok) {
|
||||
return new Response('Failed to fetch the file.', { status: upstream.status })
|
||||
}
|
||||
|
||||
const headers = new Headers()
|
||||
const contentType = upstream.headers.get('content-type')
|
||||
const contentLength = upstream.headers.get('content-length')
|
||||
|
||||
if (contentType) headers.set('content-type', contentType)
|
||||
if (contentLength) headers.set('content-length', contentLength)
|
||||
|
||||
return new Response(await upstream.arrayBuffer(), {
|
||||
headers,
|
||||
status: 200,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user