summaryrefslogtreecommitdiff
path: root/app/api/tech-sales-rfq-download/route.ts
blob: b9dd14d11a9246582d44eb476fde0840c75152f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { NextRequest } from "next/server"
import { join } from "path"
import { readFile } from "fs/promises"

export async function GET(request: NextRequest) {
  try {
    const searchParams = request.nextUrl.searchParams
    const filePath = searchParams.get("path")

    if (!filePath) {
      return new Response("File path is required", { status: 400 })
    }

    // 보안: 경로 조작 방지
    if (filePath.includes("..") || !filePath.startsWith("/techsales-rfq/")) {
      return new Response("Invalid file path", { status: 400 })
    }

    // 파일 경로 구성 (public 폴더 기준)
    const fullPath = join(process.cwd(), "public", filePath)

    try {
      // 파일 읽기
      const fileBuffer = await readFile(fullPath)
      
      // 파일명 추출
      const fileName = filePath.split("/").pop() || "download"
      
      // MIME 타입 결정
      const ext = fileName.split(".").pop()?.toLowerCase()
      let contentType = "application/octet-stream"
      
      switch (ext) {
        case "pdf":
          contentType = "application/pdf"
          break
        case "doc":
          contentType = "application/msword"
          break
        case "docx":
          contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
          break
        case "xls":
          contentType = "application/vnd.ms-excel"
          break
        case "xlsx":
          contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
          break
        case "jpg":
        case "jpeg":
          contentType = "image/jpeg"
          break
        case "png":
          contentType = "image/png"
          break
        case "gif":
          contentType = "image/gif"
          break
        case "txt":
          contentType = "text/plain"
          break
        case "zip":
          contentType = "application/zip"
          break
        default:
          contentType = "application/octet-stream"
      }

      // 응답 헤더 설정
      const headers = new Headers({
        "Content-Type": contentType,
        "Content-Disposition": `attachment; filename="${encodeURIComponent(fileName)}"`,
        "Content-Length": fileBuffer.length.toString(),
      })

      return new Response(fileBuffer, { headers })
    } catch (fileError) {
      console.error("File read error:", fileError)
      return new Response("File not found", { status: 404 })
    }
  } catch (error) {
    console.error("Download error:", error)
    return new Response("Internal server error", { status: 500 })
  }
}