serve-static.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const http = require('http');
  2. const fs = require('fs').promises;
  3. const path = require('path');
  4. // This file is used for testing wasm build from emscripten
  5. // Example build command:
  6. // emcmake cmake -B build-wasm -DGGML_WEBGPU=ON -DLLAMA_CURL=OFF
  7. // cmake --build build-wasm --target test-backend-ops -j
  8. const PORT = 8080;
  9. const STATIC_DIR = path.join(__dirname, '../build-wasm/bin');
  10. console.log(`Serving static files from: ${STATIC_DIR}`);
  11. const mimeTypes = {
  12. '.html': 'text/html',
  13. '.js': 'text/javascript',
  14. '.css': 'text/css',
  15. '.png': 'image/png',
  16. '.jpg': 'image/jpeg',
  17. '.gif': 'image/gif',
  18. '.svg': 'image/svg+xml',
  19. '.json': 'application/json',
  20. '.woff': 'font/woff',
  21. '.woff2': 'font/woff2',
  22. };
  23. async function generateDirListing(dirPath, reqUrl) {
  24. const files = await fs.readdir(dirPath);
  25. let html = `
  26. <!DOCTYPE html>
  27. <html>
  28. <head>
  29. <title>Directory Listing</title>
  30. <style>
  31. body { font-family: Arial, sans-serif; padding: 20px; }
  32. ul { list-style: none; padding: 0; }
  33. li { margin: 5px 0; }
  34. a { text-decoration: none; color: #0066cc; }
  35. a:hover { text-decoration: underline; }
  36. </style>
  37. </head>
  38. <body>
  39. <h1>Directory: ${reqUrl}</h1>
  40. <ul>
  41. `;
  42. if (reqUrl !== '/') {
  43. html += `<li><a href="../">../ (Parent Directory)</a></li>`;
  44. }
  45. for (const file of files) {
  46. const filePath = path.join(dirPath, file);
  47. const stats = await fs.stat(filePath);
  48. const link = encodeURIComponent(file) + (stats.isDirectory() ? '/' : '');
  49. html += `<li><a href="${link}">${file}${stats.isDirectory() ? '/' : ''}</a></li>`;
  50. }
  51. html += `
  52. </ul>
  53. </body>
  54. </html>
  55. `;
  56. return html;
  57. }
  58. const server = http.createServer(async (req, res) => {
  59. try {
  60. // Set COOP and COEP headers
  61. res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  62. res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
  63. res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
  64. res.setHeader('Pragma', 'no-cache');
  65. res.setHeader('Expires', '0');
  66. const filePath = path.join(STATIC_DIR, decodeURIComponent(req.url));
  67. const stats = await fs.stat(filePath);
  68. if (stats.isDirectory()) {
  69. const indexPath = path.join(filePath, 'index.html');
  70. try {
  71. const indexData = await fs.readFile(indexPath);
  72. res.writeHeader(200, { 'Content-Type': 'text/html' });
  73. res.end(indexData);
  74. } catch {
  75. // No index.html, generate directory listing
  76. const dirListing = await generateDirListing(filePath, req.url);
  77. res.writeHeader(200, { 'Content-Type': 'text/html' });
  78. res.end(dirListing);
  79. }
  80. } else {
  81. const ext = path.extname(filePath).toLowerCase();
  82. const contentType = mimeTypes[ext] || 'application/octet-stream';
  83. const data = await fs.readFile(filePath);
  84. res.writeHeader(200, { 'Content-Type': contentType });
  85. res.end(data);
  86. }
  87. } catch (err) {
  88. if (err.code === 'ENOENT') {
  89. res.writeHeader(404, { 'Content-Type': 'text/plain' });
  90. res.end('404 Not Found');
  91. } else {
  92. res.writeHeader(500, { 'Content-Type': 'text/plain' });
  93. res.end('500 Internal Server Error');
  94. }
  95. }
  96. });
  97. server.listen(PORT, () => {
  98. console.log(`Server running at http://localhost:${PORT}/`);
  99. });