Skip to content

Instantly share code, notes, and snippets.

@leonard84
Created March 20, 2024 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leonard84/5319705454638c51a5686f465f997d42 to your computer and use it in GitHub Desktop.
Save leonard84/5319705454638c51a5686f465f997d42 to your computer and use it in GitHub Desktop.
This script starts a http server that serves the contents of a zip file.
#!/usr/bin/env groovy
/**
* Usage: groovy <scriptName> [port] path-to-zip-file
*
* This script starts a http server that serves the contents of a zip file.
* The zip file is specified as a command-line argument.
* The server listens on port 8080 by default, but you can adjust it as necessary.
* If you pass 0 as the port parameter, then a random port will be selected.
* The server serves the files in the zip file and provides directory listing for directories.
* The MIME types for different file extensions are defined in the `MIME_TYPES` map.
* The `ZipServlet` class handles the HTTP requests and serves the appropriate files.
* The script also opens the default web browser to the server's URL.
*/
@Grab(group='org.eclipse.jetty', module='jetty-server', version='9.4.35.v20201120')
@Grab(group='org.eclipse.jetty', module='jetty-servlet', version='9.4.35.v20201120')
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.awt.Desktop
import java.nio.file.Files
import java.nio.file.Paths
import java.util.zip.ZipFile
import java.util.zip.ZipEntry
class ZipServlet extends HttpServlet {
// Define common MIME types for file extensions
static final Map<String, String> MIME_TYPES = [
'.html': 'text/html',
'.htm' : 'text/html',
'.txt' : 'text/plain',
'.css' : 'text/css',
'.js' : 'application/javascript',
'.json': 'application/json',
'.xml' : 'application/xml',
'.jpg' : 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png' : 'image/png',
'.gif' : 'image/gif',
'.svg' : 'image/svg+xml',
'.pdf' : 'application/pdf',
// Add more MIME types based on your needs
]
ZipFile zipFile
Map<String, ZipEntry> index = [:]
ZipServlet(String zipFilePath) {
this.zipFile = new ZipFile(zipFilePath)
indexZipContents()
}
private void indexZipContents() {
Enumeration<? extends ZipEntry> entries = zipFile.entries()
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement()
index.put(entry.getName(), entry)
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String path = req.getPathInfo() ?: ""
if (path.startsWith("/")) {
path = path.substring(1)
}
ZipEntry entry = index.get(path)
if (entry == null) {
// Handle directory listing or 404 Not Found
Set<String> dirContents = new TreeSet<>()
index.each { key, value ->
if (key.startsWith(path) && !key.equals(path)) {
String relativePath = key.substring(path.length())
int slashIndex = relativePath.indexOf('/')
if (slashIndex != -1) {
dirContents.add(relativePath.substring(0, slashIndex + 1))
} else {
dirContents.add(relativePath)
}
}
}
if (dirContents.isEmpty()) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND)
resp.getWriter().println("404 Not Found")
} else {
resp.setContentType("text/html;charset=utf-8")
resp.setStatus(HttpServletResponse.SC_OK)
dirContents.each { item ->
resp.getWriter().println("<div><a href='/${path}${item}'>${item}</a></div>")
}
}
} else {
// Serve the file
resp.setContentType(getContentType(path))
resp.setStatus(HttpServletResponse.SC_OK)
zipFile.getInputStream(entry).transferTo(resp.getOutputStream())
}
}
private static String getContentType(String fileName) {
String extension = fileName.lastIndexOf('.') != -1 ? fileName.substring(fileName.lastIndexOf('.')) : ''
return MIME_TYPES.get(extension.toLowerCase(), 'application/octet-stream') // Default to binary type if unknown
}
}
if (args.length < 1) {
println("Usage: groovy <scriptName> [port] path-to-zip-file")
System.exit(1)
}
int port = args.length == 2 ? args[0] as int : 8080 // Adjust the server port as necessary
String zipFilePath = args.length == 2 ? args[1] : args[0] // Get the zip file path from command-line argument
if (!Files.exists(Paths.get(zipFilePath))) {
println("File not found: ${zipFilePath}")
System.exit(1)
}
Server server = new Server(port)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS)
context.setContextPath("/")
server.setHandler(context)
ZipServlet zipServlet = new ZipServlet(zipFilePath)
context.addServlet(new ServletHolder(zipServlet), "/*")
server.start()
int actualPort = server.getURI().port
println("Serving ${zipServlet.index.size()} files from ${zipFilePath}")
println("Start Browsing http://localhost:$actualPort/")
println("Press Ctrl+C to stop")
// Open the default web browser to the server's URL
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(new URI("http://localhost:$actualPort/"))
}
server.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment