java सूरज सरल httpserver का उपयोग करके स्थिर सामग्री की सेवा कैसे करें




jersey (2)

मैं जर्सी के एचटीटीपी सर्फरफैक्चर का प्रयोग कर रहा हूं जो एक सरल एम्बेडेड एचटीटीएससीआर बनाने के लिए उपयोग करता है जो कुछ आराम वाली सेवाओं की मेजबानी करता है हमें थोड़ी तेज़ और हल्के वजन की जरूरत थी मुझे एक ही सर्वर इंस्टेंस के अंदर छोटे स्थिर HTML पेज होस्ट करने की आवश्यकता है। क्या सर्वर पर एक स्थिर हैंडलर जोड़ने का एक आसान तरीका है? क्या एक पूर्व-परिभाषित हैंडलर का उपयोग किया जा सकता है? यह एक बहुत ही सामान्य कार्य की तरह लगता है, अगर मैं पहले से मौजूद है, तो इसके लिए मुझे फिर से कोड लिखने से नफरत है।

        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();

यह चाल कर देगा, हालांकि यह किसी को भी अनुरोध करके पेड़ पर चलने की इजाजत देता है .. /../../ आप किसी भी वैध जावा फ़ाइलपथ को बदल सकते हैं।

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();
            }  
        }
    }

यहां एक सुरक्षित संस्करण है आप दो प्रकार के माइम प्रकार जोड़ सकते हैं, जो कि सामान्य होते हैं (या यदि आपका प्लेटफ़ॉर्म है तो अन्य विधि का उपयोग करें )।

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");
    }
}




httpserver