/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;

public class HTTPServer {
 public static final String HTTP_ROOT     = "..\\docroot";
 public static final String DEFAULT_FILE  = "index.html";

 public static final String DOWNLOAD_FILE = "download.bin";

 static int download_req_id = 0;
 static int download_pos    = 0;

 public static String valid_files[]={
  "index.html",
  "sw_upgrades/apollo/download.txt",
  "sw_upgrades/apollo/download.bin",
  "upnpdev/dev.xml",
  "upnpdev/serv/00",
  "upnpdev/serv/01",
  "upnpdev/serv/02",
  "upnpdev/serv/03",
  "upnpdev/serv/04",
  "upnpdev/serv/05",
  "upnpdev/serv/06"
 };

 static class FileHandler implements HttpHandler {   
  public void not_found(HttpExchange t) throws IOException {
   String response="404 (Not Found)\n";

   t.sendResponseHeaders(404,response.length());
   OutputStream os=t.getResponseBody();
   os.write(response.getBytes());
   os.close();
  }

  public void write_download_image(OutputStream os,byte image[]) throws IOException {
   int pos=0;

   while(pos<image.length) {
    int tag=((int)image[pos])&0xff;

    int b1=((int)image[pos+1])&0xff;
    int b2=((int)image[pos+2])&0xff;
    int b3=((int)image[pos+3])&0xff;
    int tagsize=((b1<<16)|(b2<<8)|(b3))&0xffffff;

    int size=tagsize+4;

    os.write(image,pos,size);
    os.flush();

    pos+=size;
   }
  }

  public void send_file(HttpExchange t,String name) throws IOException {
   System.out.println("- sending: "+name);

   String fname=HTTP_ROOT+"\\"+name;

   File file=new File(fname);
   byte[] buf=new byte[(int)file.length()];

   FileInputStream fis=new FileInputStream(file);
   fis.read(buf,0,buf.length);
   fis.close();

   if (name.endsWith(DOWNLOAD_FILE)) {
    System.out.println("- sending download file");

    t.sendResponseHeaders(200,buf.length);
    OutputStream os=t.getResponseBody();
    write_download_image(os,buf);

    os.close();
   } else {
    t.sendResponseHeaders(200,buf.length);
 
    OutputStream os=t.getResponseBody();
    os.write(buf,0,buf.length);

    os.close();
   }

   System.out.println("- sent: "+buf.length+" bytes");
  }

  public boolean valid_file(String name) {
   for(int i=0;i<valid_files.length;i++) {
    if (valid_files[i].equals(name)) return true;
   }

   if (name.startsWith("nportal")&&name.endsWith(".class")) return true;

   return false;
  }

  public void handle(HttpExchange t) throws IOException {
   URI uri=t.getRequestURI();
   String path=uri.getPath();
   String method=t.getRequestMethod();

   InetAddress host=t.getRemoteAddress().getAddress();

   System.out.println("["+host+"] "+method+" request for: "+path);

   String name=path.substring(1);

   if (name.equals("")) name+=DEFAULT_FILE;

   if (method.equals("GET")) {
    if (valid_file(name)) send_file(t,path);
     else not_found(t);
   } else

   if (method.equals("POST")) {
    InputStream is=t.getRequestBody();
    ByteArrayOutputStream baos=new ByteArrayOutputStream();

    byte buf[]=new byte[1024];
    int len=0;

    while((len=is.read(buf))!=-1) {
     baos.write(buf,0,len);
    }
 
    byte req_data[]=baos.toByteArray();

    byte resp_data[]=Multiroom.process_request(host,req_data);

    t.sendResponseHeaders(200,resp_data.length);
    OutputStream os=t.getResponseBody();
    os.write(resp_data,0,resp_data.length);
    os.close();
   } else

   if (method.equals("SUBSCRIBE")) {
    Headers hdrs=t.getResponseHeaders();
    hdrs.add("SID","uuid:9f4ad2e0-f65a-11e7-bfaa-68635914452c");
    hdrs.add("TIMEOUT","Second-300");

    t.sendResponseHeaders(200,0);
    OutputStream os=t.getResponseBody();
    os.close();
   }
  }
 }

 public static void start(String host_addr,int port) {
  try {
   System.out.println("HTTP server listening on: "+port);

   HttpServer server=HttpServer.create(new InetSocketAddress(host_addr,port), 0);
   server.createContext("/",new FileHandler());
   server.setExecutor(null);
   server.start();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static void disable_mroom_files() {
  valid_files=new String[0];
 }
}
