package com.timepath.vfs.http;

import com.timepath.vfs.MockFile;
import com.timepath.vfs.VFSStub;
import com.timepath.vfs.SimpleVFile;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author TimePath
 */
public class HTTPFS extends VFSStub implements Runnable {

    private static final Logger LOG = Logger.getLogger(HTTPFS.class.getName());

    public static void main(String... args) throws IOException {
        HTTPFS f = new HTTPFS(8000);
        f.add(new MockFile("test.txt", "It works!"));
        f.add(new MockFile("world.txt", "Hello world"));
        f.run();
    }

    private static String in(BufferedReader in) throws IOException {
        String s = in.readLine();
        LOG.log(Level.INFO, "<<< {0}", s);
        return s;
    }

    private static void out(PrintWriter out, String cmd) {
        out.print(cmd + "\r\n");
        out.flush();
        LOG.log(Level.INFO, ">>> {0}", cmd);
    }

    private final ServerSocket servsock;

    public HTTPFS() throws IOException {
        this(8000);
    }

    public HTTPFS(int port) throws IOException {
        servsock = new ServerSocket(port);//, 0, InetAddress.getByName(null)); // cannot use java7 InetAddress.getLoopbackAddress(). On windows, this prevents firewall warnings. It's also good for security in general
        LOG.log(Level.INFO, "Listening on {0}:{1}", new Object[] {
            InetAddress.getLocalHost().getHostAddress(), servsock.getLocalPort()});

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                LOG.info("HTTP server shutting down...");
            }
        });
    }

    public void run() {
        for(;;) {
//            LOG.info("Waiting for client...");
            try {
                new Thread(new HTTPConnection(servsock.accept())).start();
            } catch(IOException ex) {
                LOG.log(Level.SEVERE, null, ex);
            }
        }
    }

    private class HTTPConnection implements Runnable {

        private final Socket client;

        private HTTPConnection(Socket s) {
            LOG.log(Level.INFO, "{0} connected.", s);
            client = s;
        }

        public void run() {
            try {
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(client.getInputStream()));
                PrintWriter pw = new PrintWriter(client.getOutputStream(), true);
                while(!client.isClosed()) {
                    try {
                        String cmd = in(br);
                        if(cmd == null) {
                            client.close();
                            break;
                        } else if(cmd.startsWith("GET")) {
                            String[] args = cmd.substring(4).split(" ");
                            String ch = args[0];
                            String http = args[1];
                            if(ch.equals("/")) {
                                ch = "/index.html";
                            }
                            SimpleVFile f = get(ch);
                            LOG.log(Level.INFO, "*** GETing {0}", ch);
                            if(f != null) {
                                InputStream is = f.stream();
                                if(is != null) {
                                    out(pw, http + " 200 OK");
                                    out(pw, "");
                                    OutputStream os = client.getOutputStream();
                                    byte[] buf = new byte[1024 * 8];
                                    int read;
                                    while((read = is.read(buf)) > -1) {
                                        os.write(buf, 0, read);
                                        os.flush();
                                    }
                                    is.close();
                                }
                            } else {
                                out(pw, "404 File not found.");
                            }
                            client.close();
                            break;
                        }
                    } catch(Exception ex) {
                        LOG.log(Level.SEVERE, null, ex);
                        break;
                    }
                }
                LOG.log(Level.INFO, "{0} closed.", client);
            } catch(IOException ex) {
                LOG.log(Level.SEVERE, null, ex);
            }
        }

    }

}

@@ -83,23 +83,27 @@
 ath.vfs.
-VFSStub
+SimpleVFile
 ;%0Aimport
@@ -116,35 +116,31 @@
 imepath.vfs.
-SimpleVFile
+VFSStub
 ;%0Aimport jav
@@ -222,32 +222,159 @@
 ava.net.Socket;%0A
+import java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors;%0Aimport java.util.concurrent.ThreadFactory;%0A
 import java.util
@@ -590,24 +590,308 @@
 etName());%0A%0A
+    private ExecutorService pool = Executors.newFixedThreadPool(10, new ThreadFactory() %7B%0A%0A        public Thread newThread(Runnable r) %7B%0A            Thread t = Executors.defaultThreadFactory().newThread(r);%0A            t.setDaemon(false);%0A            return t;%0A        %7D%0A    %7D);%0A    %0A
     public s
@@ -1240,20 +1240,20 @@
 g(Level.
+F
 IN
-FO
+E
 , %22%3C%3C%3C %7B
@@ -1421,20 +1421,20 @@
 g(Level.
+F
 IN
-FO
+E
 , %22%3E%3E%3E %7B
@@ -2230,57 +2230,8 @@
 ) %7B%0A
-//            LOG.info(%22Waiting for client...%22);%0A
     
@@ -2260,26 +2260,27 @@
         
-new Thread
+pool.submit
 (new HTT
@@ -2314,16 +2314,8 @@
 ()))
-.start()
 ;%0A  
@@ -2730,39 +2730,168 @@
 ered
-Reader br = new BufferedReader(
+InputStream is = new BufferedInputStream(client.getInputStream());%0A                BufferedOutputStream os = new BufferedOutputStream(client.getOutputStream());
 %0A   
@@ -2903,24 +2903,31 @@
         
+%0A      
         
 new Inpu
@@ -2922,40 +2922,53 @@
     
-new InputStreamReader(client.get
+  BufferedReader br = new BufferedReader(new 
 Inpu
@@ -2974,18 +2974,25 @@
 utStream
-()
+Reader(is
 ));%0A    
@@ -3040,40 +3040,35 @@
 ter(
-client.getOutputStream(), true);
+os, true);%0A                
 %0A   
@@ -3875,18 +3875,22 @@
 tStream 
-i
 s
+tream
  = f.str
@@ -3931,18 +3931,22 @@
      if(
-i
 s
+tream
  != null
@@ -4065,88 +4065,8 @@
 %22);%0A
-                                    OutputStream os = client.getOutputStream();%0A
     
@@ -4226,18 +4226,22 @@
 (read = 
-i
 s
+tream
 .read(bu
@@ -4442,18 +4442,22 @@
         
-i
 s
+tream
 .close()
@@ -4573,28 +4573,75 @@
 pw, 
-%22404 File not found.
+http + %22 404 NOT FOUND%22);%0A                                out(pw, %22
 %22);%0A

Implement 404 handling and use thread pool