ifdef NoNanoHTTPD !include once #1028763 endifdef sclass HttpFromFileSystem { File baseDir; bool serveDirectoryListings; // default to false bool serveIndexHTML = true; S baseLink = ""; *() {} *(File *baseDir) {} *(File *baseDir, bool *serveDirectoryListings) {} O serve(S uri) { uri = urldecode(uri); LS parts = nempties(splitAtSlash(uri)); if (baseDir == null) ret serve404("No base directory set"); // process . and .. for i over parts: if (eq(parts.get(i), ".")) parts.remove(i); else if (eq(parts.get(i), "..")) if (i == 0) fail(".. leading nowhere: " + uri); else { parts.remove(i); parts.remove(--i); } if (!all validFileName(parts)) { print("Parts: " + quoteAll(parts)); fail("Bad path: " + uri); } File f = baseDir; if (!isDirectory(baseDir)) print("Base dir not found: " + f2s(f)); for (S part : parts) { f = newFile(f, part); if (!fileExists(f)) ret serve404("Path not found: " + uri); } print("Trying to serve: " + f2s(f)); if (isDirectory(f)) ret serveListing(f); else ret serveFile(f); } swappable O serveFile(File f) { ret main serveFile(f, contentTypeForFile(f)); } O serveListing(File dir) { if (serveIndexHTML) { File index = newFile(dir, "index.html"); if (fileExists(index)) ret serveFile(index); } if (!serveDirectoryListings) fail("Can't serve directory listings"); ret "Directory listing of " + f2s(dir) + ul(map(listFileNames(dir), name -> ahref(baseLink + name, htmlEncode2(name)))); } swappable S contentTypeForFile(File f) { ret or2(extensionToMimeType(fileExtension(f)), binaryMimeType()); } swappable bool validFileName(S name) { ret isValidFileName(name); } }