package org.bucksch.httpserver;
import java.io.File;
import org.bucksch.zeipis.all.Misconfiguration;
import org.bucksch.zeipis.core.CoreServer;

/**
 * This implements a normal HTTP server which just delivers files on the
 * harddisk / filesystem, corresponding to the http: url path.
 *
 * E.g. you tell it to handle URL /foo/bar/ and to use directory
 * /usr/share/zeipis/static/, then <http://servername:1234/foo/bar/hello/bla.html>
 * will be answered with /usr/share/zeipis/static/hello/bar.html .
 *
 * If there's no filename, index.html is used.
 *
 * Copyright 2009 Ben Bucksch
 * BSD
 */
public class HTTPDirectoryHandler implements HTTPHandler
{
  public HTTPDirectoryHandler(String urlPrefix, File directory)
    throws Misconfiguration
  {
    if ( ! directory.exists())
      throw new Misconfiguration("HTTP file server dir " + directory.getAbsolutePath() + " is missing on the harddisk");
    if ( ! directory.canRead())
      throw new Misconfiguration("HTTP file server dir " + directory.getAbsolutePath() + " is not readable on the harddisk, please check the permissions");
    if ( ! directory.isDirectory())
      throw new Misconfiguration("HTTP file server dir " + directory.getAbsolutePath() + " must be a directory, but is not");
    for (File root : File.listRoots())
      if (directory.getAbsoluteFile().equals(root.getAbsoluteFile()))
        throw new Misconfiguration("HTTP file server dir " + directory.getAbsolutePath() + " must not be a root directory, for your own security");
    if (directory.getAbsolutePath().length() < 4)
      throw new Misconfiguration("HTTP file server dir " + directory.getAbsolutePath() + " is too short. Everything underneath this path would be accessible from outside.");

    myDirectory = directory;
    CoreServer.me.dispatchingServer().registerHandler(this, urlPrefix);
  }
  public void handle(HTTPRequest request)
    throws HTTPException
  {
    File file = new File(myDirectory, request.getURLRest());
    if (file.isDirectory())
      file = new File(file, defaultFilename);

    // Double-check that the to-be-served file really is in the configured directory, to avoid exploits.
    // TODO necessary?
    File parent = file.getParentFile();
    while (parent != null && ! parent.equals(myDirectory))
      parent = parent.getParentFile();
    if (parent == null)
      throw new HTTPException(400, "File to be served is outside the http file directory - should not happen");
    
    String mimetype = FileTypeGuesser.guessMimetype(file);

    new HTTPFileResponse().respond(request, file, mimetype, file.getAbsolutePath());
  }
  
  protected File myDirectory;
  protected String defaultFilename = "index.html";
}

class FileTypeGuesser
{
  static String guessMimetype(File file)
  {
    String filename = file.getName();
    if (filename.endsWith(".html") || filename.endsWith(".htm"))
      return "text/html";
    else if (filename.endsWith(".js"))
      return "text/javascript";
    else if (filename.endsWith(".xml"))
      return "text/xml";
    else if (filename.endsWith(".xul"))
      return "application/vnd.mozilla.xul+xml";
    else if (filename.endsWith(".properties"))
      return "text/plain";
    else if (filename.endsWith(".jpeg") || filename.endsWith(".jpg"))
      return "image/jpeg";
    else if (filename.endsWith(".png"))
      return "image/png";
    else if (filename.endsWith(".gif"))
      return "image/gif";
    else if (filename.endsWith(".svg"))
      return "image/svg+xml";
    else if (filename.endsWith(".txt"))
      return "text/plain";
    else if (filename.endsWith(".zip"))
      return "application/zip";
    else if (filename.endsWith(".tar.gz") || filename.endsWith(".tar.bz2"))
      return "application/x-tar";
    else
      return defaultMimetype;
  }
  static String defaultMimetype = null;
}
