import java.net.*;
import java.util.*;
import java.io.*;

public class HttpProxy 
{
public static void main(String args[]) 
{
Socket answeredSocket = null;
ServerSocket listenSocket = null;
try { listenSocket = new ServerSocket (8080,10); }
catch (Exception e )
{
        System.out.println ("Error in : creating listening socket");
        System.exit(0);
}

while (true ) 
{
        try { answeredSocket = listenSocket.accept ();  }
        catch (Exception e ) {
                System.out.println ("Error in : pass socket from accept() to answeredSocket");
                System.exit(0);
        }

ProxySession  session = null;                   
try { session = new ProxySession  (answeredSocket); }
catch (Exception e ) {
        System.out.println ("Error in: Creating ProxySession");
        System.exit(0);
}
session.start ();
}
}
}


// Class Header
// Looking for content length for data transmission
// In HTTP, Variable = Value is a pair value that between communications
class Header 
{
        String variableName;
        String variableValue;
        public Header (String line)
        { 
        System.out.println("DEBUG: HEADER: " + line);
                StringTokenizer myToken = new StringTokenizer(line,":");
                if (myToken.hasMoreTokens())
                        variableName = myToken.nextToken ().trim();
                if (myToken.hasMoreTokens())
                        variableValue = myToken.nextToken ().trim();
        }

        public String getName ()
        {
                return variableName;
        }
        
        public String getValue ()
        {
                return variableValue;
        }
        
        public int getValueInt ()
        {
                Integer iport = Integer.valueOf (variableValue);
                return iport.intValue();
        }
        public String toString ()
        {
                String ret = "Varialbe Name = "+ getName()+"\nVariable Value ="+getValue ()+"\n";
                return ret;
        }
}


// multi-thereaded proxysession
// so, we need to have run(). Invoking run() by calling start()

class ProxySession extends Thread
{
private Socket clientSocket = null;
public String isHTML ="";
public boolean isHTMLFlag = false;
public ProxySession (Socket cSocket)
        {
                super ();
                clientSocket = cSocket;
        }

        public void run ()
        {
                runEx();
                try  { clientSocket.close (); }
                catch (Exception e) {};
                        clientSocket = null;
        }

        private void runEx ()
        {
                
                String request="";
                DataInputStream  clientIn = null; 
                DataOutputStream clientOut= null;
                DataInputStream  serverIn = null;
                DataOutputStream serverOut = null;
                URL webServerUrl=null;   
                Socket serverSocket=null;
                String method   = "";
                String url              = "";
                String version  = "";
                Header contentLength = null;

                // setup the stream between browser and proxy server
                try 
                {
                        clientIn  = new DataInputStream (new BufferedInputStream (clientSocket.getInputStream ()));
                        clientOut = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream()));
                }
                catch (Exception e )
                {
                        System.out.println ("while attaching streams to client socket :" +e.toString ());
                        return;
                }

                // now read the request from the browser
                try 
                {
                        request = clientIn.readLine();
                } 
                catch (IOException e) 
                {
                        return;
                }
        
                // parse the key parts of the request 
                StringTokenizer tk = new StringTokenizer(request," ");
                if (tk.hasMoreTokens())
                        method = tk.nextToken ();  // Get or Post method
                if (tk.hasMoreTokens())
                        url     = tk.nextToken ();
                if (tk.hasMoreTokens())
                        version = tk.nextToken (); // HTTP protocol version number HTTP/1.0 or HTTP/1.1
                
         
                try { webServerUrl = new URL (url); }
                catch (Exception e) { System.exit(0); }
                

                try
                {
                        serverSocket =  new Socket (webServerUrl.getHost(),webServerUrl.getPort () != -1 ? webServerUrl.getPort () : 80);
                        System.out.println("DEBUG: Connect to: " + serverSocket);
                }
                catch (Exception e)
                {
                        
                        return;
                }

                try
                {
                        serverIn  = new DataInputStream (new BufferedInputStream (serverSocket.getInputStream ()));
                        serverOut = new DataOutputStream(new BufferedOutputStream(serverSocket.getOutputStream()));
                }
                catch (Exception e)
                {
                        System.out.println ("while getting stream from url :" +e.toString ());
                        return;
                }

                // send the server the request
                // The request must be transformed from a proxy request to a browser request
                try
                {
                        String req = method + " " + webServerUrl.getFile() +" "+ version + "\r\n"; 
            
            isHTML = webServerUrl.getFile(); 

                        System.out.println("isHTML string now is: " + isHTML);
            if (isHTML.endsWith("/") || isHTML.endsWith(".html") || isHTML.endsWith(".htm")
                                || isHTML.endsWith(".HTML") || isHTML.endsWith(".HTM"))
                        {
                                System.out.println("DEBUG: This file may be a HTML/TEXT file");
                                isHTMLFlag = true;
                        }
                        else
                        {
                                System.out.println("DEBUG: This file is not HTML file");
                                isHTMLFlag = false;
                        }


            System.out.println("DEBUG: ACTION: serverOut ->" + req);
                        serverOut.writeBytes (req);
                }
                catch (Exception e)
                {
                        
                        return;
                }


                // now send the headers
                
                Header hdr;
                do
                {
                        hdr = getAndCopyHeader (clientIn,serverOut);
                        if ( hdr!= null && hdr.getName().equalsIgnoreCase ("content-length"))
                                        contentLength = hdr;
                } while (hdr != null) ;

                

                // flush the server out stream 
                try 
                {
                        serverOut.flush();
                }
                catch (IOException e) {};

                // is there any extra data to copy from the client to the server ?
                if (contentLength != null ) 
                        streamCopyBytes (clientIn,serverOut,contentLength.getValueInt());

                // now copy the responce from the server to the client
                streamCopyBytes (serverIn,clientOut,-1);

                // do some cleanup
                clientIn  = null;
                clientOut = null;
                serverIn  = null;
                serverOut = null;
                try 
                {
                        serverSocket.close ();
                }
                catch (Exception e)
                {
                        System.out.println ("while closing the server socket :" +e.toString ());
                        return;
                }

                serverSocket = null;

        }
        


        Header getAndCopyHeader (DataInputStream in,DataOutputStream out)
        {
                String request="";
                Header ret = null;
                try 
                {
            request = in.readLine(); 
            // System.out.println("REQUEST= " + request);
                        out.writeBytes (request +"\r\n");
                } 
                catch (IOException e) 
                {
                        request = "";
                }
                
                if (!request.equals (""))
                        ret = new Header (request);
                return ret;     
                
        }
        //----------------------------------------------------------------------
        // Copy data from stream to stream until end of 
        // stream is reached or cBytes is reached
        //----------------------------------------------------------------------
        void streamCopyBytes (DataInputStream in,DataOutputStream out, int cBytes)
        {
                boolean ok = true;
                int cCount = 0;
                byte buffer[] = new byte[1024];
                while (ok)
                {
                        int inCount = 0;
                        try 
                        {
                                inCount = in.read(buffer);
                                if (inCount == -1 )
                                        ok = false;
                                cCount += inCount;
                                if (cBytes > -1 && cCount >= cBytes )
                                        ok = false;
                                if (inCount > 0) 
                                {

                                        if (isHTMLFlag == true)
                                        { System.out.write(buffer,0,inCount);   
                                          System.out.flush();
                                        }
                                        out.write (buffer,0,inCount);
                                        out.flush();
                                 
                                }
                        }
                        catch (IOException  e) 
                        {
                                ok = false;
                        }
                }
        }
}