MiniServer

このエントリーをはてなブックマークに追加

Sun Java SDK 1.6から,HttpServerを用いれば簡易的なWebサーバを簡単に構築できるようになった.
ここでは,以下の機能を持つWebサーバのサーバープログラムを作成してみる.

  • リクエストのパスが /html/xx/yy/zz.html なら,指定したドキュメントルート以下の/xx/yy/zz.html のファイルの内容を返す.
    • MIME typeには対応していない.
  • リクエストのパスが /command/xx?p1=a1&p2=a2 なら,JSONオブジェクトとして{p1:a1, p2,a2} を返す.ただし xx は quit 以外.
    • 文字列のデコードは行っていない.
  • リクエストのパスが /command/quit ならサーバーを終了する.

MiniServer.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import org.json.JSONException;
import org.json.JSONObject;

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

public class MiniServer {
    public int port = 8080;
    public String documentRoot = null;
    public String htmlPath = "/html";
    public String commandPath = "/command";
    public boolean quit = false;

    public MiniServer(int port, String documentRoot) throws IOException {
        this.port = port;
        this.documentRoot = documentRoot;
        if (documentRoot == null) {
            throw new IOException("Document documentRoot is not specified");
        }
    }

    public synchronized void quit() {
        quit = true;
        notifyAll();
    }

    public class HtmlHandler implements HttpHandler {
        int buffSize = 1024;
        File dir;

        public HtmlHandler(File dir) {
            this.dir = dir;
        }

        public void handle(HttpExchange exchange) throws IOException {
            String path0 = exchange.getHttpContext().getPath();
            String path1 = exchange.getRequestURI().getPath();
            String path = documentRoot + path1.substring(path0.length());
            int code = 0;
            OutputStream out = exchange.getResponseBody();
            File file = new File(path);
            try {
                if (file.isFile()) {
                    InputStream in = new FileInputStream(file);
                    code = 200;
                    exchange.sendResponseHeaders(code, 0);
                    byte[] buff = new byte[buffSize];
                    while (in.available() > 0) {
                        int length = in.read(buff);
                        out.write(buff, 0, length);
                    }
                    in.close();
                }
            } catch (IOException e) {
            }
            if (code == 0) {
                code = 404;
                String msg = "<h1>" + code + " Not Found</h1>";
                msg += exchange.getRequestURI();
                exchange.sendResponseHeaders(code, 0);
                out.write(msg.getBytes());
            }
            out.close();
        }
    }

    public class CommandHandler implements HttpHandler {
        public synchronized void handle(HttpExchange exchange) throws IOException {
            String path0 = exchange.getHttpContext().getPath();
            String path1 = exchange.getRequestURI().getPath();
            String path = path1.substring(path0.length());
            String query = exchange.getRequestURI().getRawQuery();
            OutputStream out = exchange.getResponseBody();
            String str = null;
            try {
                if (path.equals("/quit")) {
                    quit();
                    str = "";
                } else if (path.equals("/query")) {
                    JSONObject json = new JSONObject();
                    for (String q : query.split("&")) {
                        String[] s = q.split("=", 2);
                        json.put(s[0], s[1]);
                    }
                    str = json.toString();
                }
            } catch (JSONException e) {
            }
            int code = 200;
            if (str == null) {
                code = 404;
                str = code + " Not Found " + exchange.getRequestURI();
            }
            exchange.sendResponseHeaders(code, 0);
            out.write(str.getBytes());
            out.close();
        }
    }

    public synchronized void start() throws IOException {
        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
        File dir = new File(documentRoot);
        if (dir.isDirectory()) {
            server.createContext(htmlPath, new HtmlHandler(dir));
        }
        server.createContext(commandPath, new CommandHandler());
        server.start();
        System.out.println("MiniTrace server starting on port " + port);
        quit = false;
        while (! quit) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        server.stop(0);
        System.out.println("MiniTrace server stopped");
    }

    public static void main(String[] args) {
        int port = 8080;
        String documentRoot = null;
        try {
            int i = 0;
            while (i < args.length) {
                if (args[i].equals("-port") && i + 1 < args.length) {
                    i++;
                    port = Integer.parseInt(args[i]);
                } else if (args[i].equals("-html") && i + 1 < args.length) {
                    i++;
                    documentRoot = args[i];
                }
                i++;
            }
            MiniServer miniServer = new MiniServer(port, documentRoot);
            miniServer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}