-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
105 lines (79 loc) · 2.62 KB
/
app.js
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
const express = require('express');
const { GetObjectCommand, HeadObjectCommand, S3Client } = require("@aws-sdk/client-s3");
let bucket;
let s3Client;
module.exports = function createApp(hosts, bucketRegion, bucketName, {testHost, refreshUrl= "/refresh"}) {
s3Client = new S3Client({ region: bucketRegion });
bucket = bucketName;
const app = express();
app.get(refreshUrl, async (req, res) => {
process.exit();
})
app.get('*', async (req, res) => {
let host = req.hostname;
if (testHost) {
host = testHost
}
if (host.startsWith("www.")) {
host = host.slice(4)
}
if (!hosts.includes(host)) {
console.error(`Unrecognized Host: ${host}`)
return
}
const path = await resolveFinalPath(host, req.path)
const key = `${host}${path}`;
console.log(`${req.ip} == GET: ${key}`)
try {
const headResult = await s3Client.send( new HeadObjectCommand({Bucket: bucket, Key: key}))
const contentType = headResult.ContentType
const object = await s3Client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
let contents = await streamToBuffer(object.Body);
res.setHeader('Content-Type', contentType)
res.send(contents);
} catch (error) {
console.error(error);
res.status(404).send('File not found');
}
});
return app
}
async function resolveFinalPath(host, path) {
// Check if path ends in /
if (path.endsWith('/')) {
return path + 'index.html';
}
// Check if path has a file extension
const hasExtension = path.includes('.') && path.split('.').pop().length > 0;
// If no file extension, decide which file to serve
if (!hasExtension) {
const keyWithIndexHtml = `${host}${path}/index.html`;
const keyWithHtml = `${host}${path}.html`;
// Try the most likely option first (/index.html)
if (await fileExists(keyWithIndexHtml)) {
return path + '/index.html';
} else if (await fileExists(keyWithHtml)) {
// If /index.html doesn't exist, check for .html
return path + '.html';
}
}
// If the path has an extension or doesn't need modification, return it as is
return path;
}
async function fileExists(key) {
try {
await s3Client.send(new HeadObjectCommand({ Bucket: bucket, Key: key }));
return true;
} catch (error) {
return false;
}
}
// Helper function to convert a stream into a buffer
function streamToBuffer(stream) {
return new Promise((resolve, reject) => {
const chunks = [];
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', reject);
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
}