2013-04-09 4 views
7

Sto utilizzando HttpServerFactory di jersey per creare un semplice Httpserver incorporato che ospita un paio di servizi di resto. Avevamo solo bisogno di qualcosa di piccolo, veloce e leggero. Ho bisogno di ospitare una piccola pagina html statica all'interno della stessa istanza del server. C'è un modo semplice per aggiungere un gestore statico al server? C'è un gestore predefinito che posso usare? Sembra un compito abbastanza comune, odio dover riscrivere il codice per esso se esiste già.Come servire il contenuto statico usando il semplice httpserver di suns

 server = HttpServerFactory.create(url); 
     server.setExecutor(Executors.newCachedThreadPool()); 
     server.createContext("/staticcontent", new HttpHandler() { 

      @Override 
      public void handle(HttpExchange arg0) throws IOException { 
       //What goes here? 

      } 
     }); 
     server.start(); 

risposta

6

questo farà il trucco, anche se non permettere a nessuno di camminare l'albero richiedendo ../../../ È possibile modificare ./wwwroot a qualsiasi percorso file java valido.

static class MyHandler implements HttpHandler { 
     public void handle(HttpExchange t) throws IOException { 
      String root = "./wwwroot"; 
      URI uri = t.getRequestURI(); 
      System.out.println("looking for: "+ root + uri.getPath()); 
      String path = uri.getPath(); 
      File file = new File(root + path).getCanonicalFile(); 

      if (!file.isFile()) { 
       // Object does not exist or is not a file: reject with 404 error. 
       String response = "404 (Not Found)\n"; 
       t.sendResponseHeaders(404, response.length()); 
       OutputStream os = t.getResponseBody(); 
       os.write(response.getBytes()); 
       os.close(); 
      } else { 
       // Object exists and is a file: accept with response code 200. 
       String mime = "text/html"; 
       if(path.substring(path.length()-3).equals(".js")) mime = "application/javascript"; 
       if(path.substring(path.length()-3).equals("css")) mime = "text/css";    

       Headers h = t.getResponseHeaders(); 
       h.set("Content-Type", mime); 
       t.sendResponseHeaders(200, 0);    

       OutputStream os = t.getResponseBody(); 
       FileInputStream fs = new FileInputStream(file); 
       final byte[] buffer = new byte[0x10000]; 
       int count = 0; 
       while ((count = fs.read(buffer)) >= 0) { 
       os.write(buffer,0,count); 
       } 
       fs.close(); 
       os.close(); 
      } 
     } 
    } 
+0

Non volevo farlo ma ci sono tornato dopo aver eseguito i file jar in conflitto in altre soluzioni. Citerò che "httpServer.createContext ("/", new MyHandler());" è la linea per aggiungere il gestore al server. Il '/' è necessario per iniziare il percorso. – Speck

+0

sto usando Windows. E voglio il mio D: drive da usare come cartella principale. Qualche suggerimento. –

+0

Avvio di Java 7, utilizzare String mime = Files.probeContentType (file.toPath()); – krishnakumarp

2

Ecco una versione sicura. Si consiglia di aggiungere un paio di tipi MIME, a seconda di quelli che sono comuni (o utilizzare un altro metodo se your platform has that).

package de.phihag.miniticker; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.HashMap; 
import java.util.Map; 

import com.sun.net.httpserver.HttpExchange; 
import com.sun.net.httpserver.HttpHandler; 
import com.sun.net.httpserver.HttpServer; 

public class StaticFileHandler implements HttpHandler { 
    private static final Map<String,String> MIME_MAP = new HashMap<>(); 
    static { 
     MIME_MAP.put("appcache", "text/cache-manifest"); 
     MIME_MAP.put("css", "text/css"); 
     MIME_MAP.put("gif", "image/gif"); 
     MIME_MAP.put("html", "text/html"); 
     MIME_MAP.put("js", "application/javascript"); 
     MIME_MAP.put("json", "application/json"); 
     MIME_MAP.put("jpg", "image/jpeg"); 
     MIME_MAP.put("jpeg", "image/jpeg"); 
     MIME_MAP.put("mp4", "video/mp4"); 
     MIME_MAP.put("pdf", "application/pdf"); 
     MIME_MAP.put("png", "image/png"); 
     MIME_MAP.put("svg", "image/svg+xml"); 
     MIME_MAP.put("xlsm", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 
     MIME_MAP.put("xml", "application/xml"); 
     MIME_MAP.put("zip", "application/zip"); 
     MIME_MAP.put("md", "text/plain"); 
     MIME_MAP.put("txt", "text/plain"); 
     MIME_MAP.put("php", "text/plain"); 
    }; 

    private String filesystemRoot; 
    private String urlPrefix; 
    private String directoryIndex; 

    /** 
    * @param urlPrefix The prefix of all URLs. 
    *     This is the first argument to createContext. Must start and end in a slash. 
    * @param filesystemRoot The root directory in the filesystem. 
    *      Only files under this directory will be served to the client. 
    *      For instance "./staticfiles". 
    * @param directoryIndex File to show when a directory is requested, e.g. "index.html". 
    */ 
    public StaticFileHandler(String urlPrefix, String filesystemRoot, String directoryIndex) { 
     if (!urlPrefix.startsWith("/")) { 
      throw new RuntimeException("pathPrefix does not start with a slash"); 
     } 
     if (!urlPrefix.endsWith("/")) { 
      throw new RuntimeException("pathPrefix does not end with a slash"); 
     } 
     this.urlPrefix = urlPrefix; 

     assert filesystemRoot.endsWith("/"); 
     try { 
      this.filesystemRoot = new File(filesystemRoot).getCanonicalPath(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 

     this.directoryIndex = directoryIndex; 
    } 

    /** 
    * Create and register a new static file handler. 
    * @param hs The HTTP server where the file handler will be registered. 
    * @param path The path in the URL prefixed to all requests, such as "/static/" 
    * @param filesystemRoot The filesystem location. 
    *      For instance "/var/www/mystaticfiles/". 
    *      A request to "/static/x/y.html" will be served from the filesystem file "/var/www/mystaticfiles/x/y.html" 
    * @param directoryIndex File to show when a directory is requested, e.g. "index.html". 
    */ 
    public static void create(HttpServer hs, String path, String filesystemRoot, String directoryIndex) { 
     StaticFileHandler sfh = new StaticFileHandler(path, filesystemRoot, directoryIndex); 
     hs.createContext(path, sfh); 
    } 

    public void handle(HttpExchange he) throws IOException { 
     String method = he.getRequestMethod(); 
     if (! ("HEAD".equals(method) || "GET".equals(method))) { 
      sendError(he, 501, "Unsupported HTTP method"); 
      return; 
     } 

     String wholeUrlPath = he.getRequestURI().getPath(); 
     if (wholeUrlPath.endsWith("/")) { 
      wholeUrlPath += directoryIndex; 
     } 
     if (! wholeUrlPath.startsWith(urlPrefix)) { 
      throw new RuntimeException("Path is not in prefix - incorrect routing?"); 
     } 
     String urlPath = wholeUrlPath.substring(urlPrefix.length()); 

     File f = new File(filesystemRoot, urlPath); 
     File canonicalFile; 
     try { 
      canonicalFile = f.getCanonicalFile(); 
     } catch (IOException e) { 
      // This may be more benign (i.e. not an attack, just a 403), 
      // but we don't want the attacker to be able to discern the difference. 
      reportPathTraversal(he); 
      return; 
     } 

     String canonicalPath = canonicalFile.getPath(); 
     if (! canonicalPath.startsWith(filesystemRoot)) { 
      reportPathTraversal(he); 
      return; 
     } 

     FileInputStream fis; 
     try { 
      fis = new FileInputStream(canonicalFile); 
     } catch (FileNotFoundException e) { 
      // The file may also be forbidden to us instead of missing, but we're leaking less information this way 
      sendError(he, 404, "File not found"); 
      return; 
     } 

     String mimeType = lookupMime(urlPath); 
     he.getResponseHeaders().set("Content-Type", mimeType); 
     if ("GET".equals(method)) { 
      he.sendResponseHeaders(200, canonicalFile.length());    
      OutputStream os = he.getResponseBody(); 
      copyStream(fis, os); 
      os.close(); 
     } else { 
      assert("HEAD".equals(method)); 
      he.sendResponseHeaders(200, -1); 
     } 
     fis.close(); 
    } 

    private void copyStream(InputStream is, OutputStream os) throws IOException { 
     byte[] buf = new byte[4096]; 
     int n; 
     while ((n = is.read(buf)) >= 0) { 
      os.write(buf, 0, n); 
     } 
    } 

    private void sendError(HttpExchange he, int rCode, String description) throws IOException { 
     String message = "HTTP error " + rCode + ": " + description; 
     byte[] messageBytes = message.getBytes("UTF-8"); 

     he.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); 
     he.sendResponseHeaders(rCode, messageBytes.length); 
     OutputStream os = he.getResponseBody(); 
     os.write(messageBytes); 
     os.close(); 
    } 

    // This is one function to avoid giving away where we failed 
    private void reportPathTraversal(HttpExchange he) throws IOException { 
     sendError(he, 400, "Path traversal attempt detected"); 
    } 

    private static String getExt(String path) { 
     int slashIndex = path.lastIndexOf('/'); 
     String basename = (slashIndex < 0) ? path : path.substring(slashIndex + 1); 

     int dotIndex = basename.lastIndexOf('.'); 
     if (dotIndex >= 0) { 
      return basename.substring(dotIndex + 1); 
     } else { 
      return ""; 
     } 
    } 

    private static String lookupMime(String path) { 
     String ext = getExt(path).toLowerCase(); 
     return MIME_MAP.getOrDefault(ext, "application/octet-stream"); 
    } 
}