/* * Copyright (C) 2013-2014 Sony Computer Science Laboratories, Inc. All Rights Reserved. * Copyright (C) 2014 Sony Corporation. All Rights Reserved. */ package com.sonycsl.Kadecot.server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern; // This class is base class of servers. public abstract class HTTPServer { // private static Server instance; private boolean isRunning = false; protected int runningPort = -1; private static ServerSocket socket; private String access_origin = ""; private ArrayList<HttpGet> httpGetList = new ArrayList<HttpGet>(); protected HTTPServer(String access_origin) { this.access_origin = access_origin; } // add httpget and so on. // abstract protected void initialize(); // abstract protected Server getInstance(); protected void addHttpGet(HttpGet hg) { httpGetList.add(hg); } private void service() throws IOException { for (Socket sock = accept(); sock != null; sock = accept()) { // why single thread? Executor executor = Executors.newSingleThreadExecutor(); executor.execute(new HttpServerService(sock)); } } private Socket accept() throws IOException { try { return socket.accept(); } catch (SocketException e) { } return null; } public void start(int port) throws IOException { if (isRunning()) return; socket = new ServerSocket(); socket.setReuseAddress(true); socket.bind(new InetSocketAddress(port)); Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { try { service(); } catch (IOException e) { e.printStackTrace(); } finally { stop(); } } }); runningPort = port; isRunning = true; } public void stop() { try { if (socket != null) { socket.close(); socket = null; } } catch (IOException e) { e.printStackTrace(); } finally { isRunning = false; runningPort = -1; } } public boolean isRunning() { return this.isRunning; } class Request { public String method; public String path = null; // public Map<String, String> params; public Map<String, String> query; public List<String> requests; Pattern REQUEST_LINE_PATTERN = Pattern.compile("^(\\w+)\\s+(.+?)\\s+HTTP/([\\d.]+)$"); public Request(InputStream in) { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); query = new HashMap<String, String>(); requests = new ArrayList<String>(); String line; try { line = reader.readLine(); while (line != null && line.length() != 0) { // System.out.println(line); requests.add(line); line = reader.readLine(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (requests.size() < 1) return; line = requests.get(0); Matcher m = REQUEST_LINE_PATTERN.matcher(line); if (m.matches()) { method = m.group(1); String p = m.group(2); String[] ss = p.split("\\?"); path = ss[0]; if (ss.length == 1) { return; } else { String q = p.substring(path.length() + 1); ss = q.split("&"); for (String s : ss) { String[] r = s.split("="); if (r.length != 2) continue; query.put(r[0], r[1]); } } } else { return; } } } class Response { private OutputStream out; private String access_origin = ""; public Response(OutputStream out, String access_origin) { this.out = out; this.access_origin = access_origin; } public Response(OutputStream out) { this(out, ""); } public void success(String type, String content) { // System.out.println("success"); PrintWriter writer = new PrintWriter(out); writer.print("HTTP/1.1 200 OK\r\n"); writer.print("Connection: close\r\n"); writer.print("ETag: \"" + UUID.randomUUID().toString().replaceAll("-", "") + "\"\r\n"); if (access_origin != "") { writer.print("Access-Control-Allow-Origin: " + access_origin + "\r\n"); } writer.print("Content-Length: "); writer.print(content.getBytes().length); writer.print("\r\n"); writer.print("Content-Type: "); writer.print(type); writer.print("\r\n\r\n"); writer.print(content); writer.flush(); } public void failure(String type, String content) { // System.out.println("failure"); PrintWriter writer = new PrintWriter(out); writer.print("HTTP/1.0 404 Not Found\r\n"); writer.print("Connection: close\r\n"); writer.print("ETag: \"" + UUID.randomUUID().toString().replaceAll("-", "") + "\"\r\n"); if (access_origin != "") { writer.print("Access-Control-Allow-Origin: " + access_origin + "\r\n"); } writer.print("Content-Length: "); writer.print(content.getBytes().length); writer.print("\r\n"); writer.print("Content-Type: "); writer.print(type); writer.print("\r\n\r\n"); writer.print(content); writer.flush(); } public void sendNotFound() { failure("text", "Not Found"); } } abstract class HttpGet { String path; public HttpGet(String path) { this.path = path; } public HttpGet(Pattern path) { // 未実装 } public boolean match(String path) { return this.path.equalsIgnoreCase(path); } public abstract void run(Request req, Response res) throws IOException; } private class HttpServerService implements Runnable { Socket socket; HttpServerService(Socket socket) { this.socket = socket; } @Override public void run() { OutputStream out = null; InputStream in = null; try { out = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); try { socket.close(); } catch (IOException e1) { e1.printStackTrace(); } return; } try { in = socket.getInputStream(); } catch (IOException e1) { e1.printStackTrace(); try { out.close(); } catch (IOException e) { e.printStackTrace(); } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } return; } try { Request req = new Request(in); Response res = new Response(out, access_origin); if (req.path == null) { res.sendNotFound(); return; } for (HttpGet httpGet : httpGetList) { if (httpGet.match(req.path)) { httpGet.run(req, res); return; } } res.sendNotFound(); } catch (IOException e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } try { in.close(); } catch (IOException e) { e.printStackTrace(); } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } static String urldecode(String s) { if (s == null) return null; try { return URLDecoder.decode(s, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return s; } } }