Friday, March 2, 2012

P-roxy code


#include(proxy.java)
#include(compiler.java)
#include(jvm.c)


Admin.java*c


/****************************************************************** 
*** File Admin.java*c 
*** 
***/
import java.net.*; 
import java.io.*;
import c.net.*;
import c.io.*;




// 
// Class:     Admin 
// Abstract:  The admin thread listens on admin socket and handle all 
//            communications with the remote administrator. 
//


public class Admin extends Thread 

 // 
 // Member variables 
 //


 ServerSocket adminSocket = null; 
 Socket appletSocket = null; 
 String passwordCandidate = null; 
 DataInputStream in = null; 
 DataOutputStream out = null; 
 Config config = null; 
 Cache cache; 
  
  
 // 
 // Public methods 
 //


 // 
 // Constructor 
 // 
 Admin(Config configObject, Cache cacheManager) 
 { 
  try 
  { 
   config = configObject; 
   cache = cacheManager; 
   adminSocket = new ServerSocket(0); 
   config.setAdminPort(adminSocket.getLocalPort()); 
  } 
  catch (IOException e) 
  { 
   System.out.println("Error opening admin socket"); 
  } 
 }


 // 
 // Handle communications with remote administrator 
 // 
 public void run() 
 { 
  while(true) 
  { 
   try 
   { 
    appletSocket = adminSocket.accept(); 
    in = new DataInputStream(appletSocket.getInputStream()); 
    out = new DataOutputStream(appletSocket.getOutputStream());


    do 
    { 
     // Read password candidate sent by applet 
     String passwordCandidate = in.readLine();


     // Send applet ack/nack on password 
     if (config.getPassword().equals(passwordCandidate)) 
     { 
      out.writeBytes("ACCEPT\n"); 
      break; 
     } 
     else 
     { 
      out.writeBytes("REJECT\n"); 
     } 
     out.flush(); 
    } 
    while (true);

    // 
    // Password is OK, so let's send the administrator the 
    // parameters values and read his new values 
    // 
    while(true) 
    { 
     out.writeBytes(config.toString()); 
     out.flush();


     config.parse(in.readLine()); 
     System.out.println("Configuration changed by administrator.");


     // Administrator wants to clean the cache 
     if (config.getCleanCache()) 
     { 
      cache.clean(); 
      config.setCleanCache(false); //no need to clean again 
     } 
    } 
   } 
   catch (Exception e) 
   { 
    // 
    // This line was reached because the administrator closed 
    // the connection with the proxy. That's fine, we are now 
    // available for another administrator to log in. 
    // 
    System.out.println("Connection with administrator closed."); 
   } 
   finally 
   { 
    try 
    { 
     out.close(); 
     in.close(); 
    } 
    catch(Exception exc) 
    {} 
   } 
  }//while 
 } 
}


Cache.java


/****************************************************************** 
*** File Cache.java 
*** 
***/
import java.io.*; 
import java.util.*; 
import java.net.*;


// 
// Class:     Cache 
// Abstract:  manages all caching activities. 
//


public class Cache 

 // 
 // Members variables 
 //


 String basePath = null; 
 long MinFreeSpace;// in bytes 
 Hashtable htable; 
 Config config;


 // 
 // Public methods 
 //


 // 
 // Constructor 
 // 
 public Cache(Config configObject) 
 { 
  // 
  // Initialize variables 
  // 
  config = configObject; 
  MinFreeSpace = 15000; 
  htable = new Hashtable();


  // 
  // Create directory for caching 
  //


  File cacheDir = new File("Cache"); 
  cacheDir.mkdirs(); 
  basePath = cacheDir.getAbsolutePath(); 
  
  // 
  // Delete all files in cache directory 
  // 
  int i; 
  File file = new File(basePath);; 
  String filename;


  // Get list of files in cache direcotry 
  String files[] = file.list();


  // Delete each file found 
  for (i=0; i<files.length; i++) 
  { 
   file = new File(basePath + File.separatorChar + files[i]); 
   file.delete(); 
  } 
  config.setFilesCached(0); 
  config.setBytesCached(0); 
  config.setHits(0); 
  config.setMisses(0); 
 }


 // 
 // isCachable - check if URL reply should be cached 
 // 
 public boolean IsCachable(String rawUrl) 
 { 
  return (getFileName(rawUrl) != null); 
 } 



 // 
 // IsCached - Check if we have in cache what the client wants. 
 // 
 public boolean IsCached(String rawUrl) 
 { 
  // Generate filename from URL 
  String filename = getFileName(rawUrl); 
  if (filename == null) 
   return false;


  // Search in hash table 
  if (htable.get(filename) != null) 
   return true;


  return false; 
 }


 // 
 // getFileInputStream - When this method is called, it means a cache hit. 
 //   We update the date field in the hash table entry and return a 
 //   FileInputStream object corresponding to the file caching the info. 
 // 
    public FileInputStream getFileInputStream(String rawUrl) 
 { 
  FileInputStream in = null; 
  try 
  { 
      String filename = getFileName(rawUrl);

   // Update the hash table entry with current date as value 
   htable.put(filename,new Date());


   in = new FileInputStream(filename); 
  } 
  catch (FileNotFoundException fnf) 
  { 
   try


   { 
    System.out.println("File Not Found:"+getFileName(rawUrl)+" "+fnf); 
   } 
   catch (Exception e) 
   {} 
  } 
  finally 
  { 
   return in; 
  } 
 }


 // 
 // getFileoutputStream - When this method is called, it means we're about 
 //   to cache a new object. We generate a file name, and return 
 //   a corresponding FileOutputStream object. 
 // 
    public FileOutputStream getFileOutputStream(String rawUrl) 
 { 
  FileOutputStream out = null; 
  String filename; 
  try 
  { 
      filename = getFileName(rawUrl);


   out = new FileOutputStream(filename); 
  } 
  catch (IOException e) 
  {} 
  finally 
  { 
   return out; 
  } 
 }


 // 
 // Decrement Cache Free Space (In Bytes) 
 // 
 public synchronized void DecrementFreeSpace(int nbytes, String rawUrl) 
 { 
  config.setBytesCached(config.getBytesCached() + nbytes); 
  if (config.getBytesFree() <= MinFreeSpace) 
   MakeFreeSpace(rawUrl); 
 }


 // 
 // Add new entry to hash table 
 // 
 public synchronized void AddToTable(String rawUrl) 
 { 
  String filename = getFileName(rawUrl);


  // Add filename to hash table with the current date as its value 
  htable.put(filename,new Date()); 
  config.increaseFilesCached(); 
 }


 // 
 // clean - delete the cached files 
 // 
    public synchronized void clean() 
 { 
  System.out.println("Cleaning the cache...");


  // Enumerate the hash table 
  for (Enumeration keys = htable.keys(); keys.hasMoreElements() ;) 
  { 
   String filename = (String)keys.nextElement(); 
   File file = new File(filename); 
   long nbytes = file.length(); 
   boolean result = file.delete(); 
   if (result == true) 
   { 
    // Delete entry in hash table 
    htable.remove(filename); 
    config.decreaseFilesCached();


    // Increment free space 
    config.setBytesCached(config.getBytesCached() - nbytes); 
   } 
   else 
   { 
    // Another thread holds this file open for writing 
   } 
  } 
  config.setHits(0); 
  config.setMisses(0); 
  System.out.println("Cache is clean."); 
 }


 // 
 // Private methods 
 //


 // 
 // MakeFreeSpace - throw LRU file until free space is above min level 
 // 
 private synchronized void MakeFreeSpace(String rawUrl) 
 { 
  String filename, 
      LRUfilename; 
  Date   date, 
      minDate;


  minDate = new Date(); 
  while (config.getBytesFree() < MinFreeSpace) 
  { 
   filename = LRUfilename = null; 
   date = null;


   if (htable.isEmpty()) 
   { 
    System.out.println("Could not make free space: Hash table empty..."); 
    return; 
   }


   // 
   // Enumerate the hash table entries to find the LRU file 
   // 
   for (Enumeration keys = htable.keys(); keys.hasMoreElements() ;) 
   { 
    filename = (String)keys.nextElement(); 
    date = (Date)htable.get(filename); 
    if (date.before(minDate)) 
     LRUfilename = filename; 
   }


   // 
   // Delete the LRU file 
   // 
   File LRUfile = new File(LRUfilename); 
   long nbytes = LRUfile.length(); 
   boolean result = LRUfile.delete(); 
   if (result == true) 
   { 
    // Delete entry in hash table 
    htable.remove(LRUfilename); 
    config.decreaseFilesCached();


    // Increment free space 
    config.setBytesCached(config.getBytesCached() - nbytes); 
   } 
   else 
   { 
    // Another thread holds this file open for writing 
    System.out.println("File "+LRUfilename+" could not be deleted..."); 
    return; 
   } 
  } 
  }


 // 
 // Convert the URL to filename - this method parses the URL and 
 //   generate filename only if the URL is to be cached. 
 //   We do not cache URLs containing '?', "cgi-bin" and 
 //   a list of not-to-cached-URLs as instructed by the proxy administrator. 
 // 
 private String getFileName(String rawUrl) 
 { 
  String filename = basePath + File.separatorChar + rawUrl.substring(7).replace('/','@');


  if (filename.indexOf('?') != -1 || filename.indexOf("cgi-bin") != -1) 
  { 
   return null; 
  }


  return filename; 
 } 
}


Config.java


/****************************************************************** 
*** File Config.java 
*** 
***/
import java.util.*; 
import java.net.*; 
import java.io.*;


// 
// Class:     Config 
// Abstract:  Configurable parameters of the proxy. This class is 
//            used by both the applet and the proxy. 
//


class Config 

 // 
 // Member variables 
 // 
    private boolean  isFatherProxy; 
    private String   fatherProxyHost; 
    private int      fatherProxyPort; 
    private String[] deniedHosts; 
    private String   password; 
 private boolean  isCaching;  // enable/disable caching 
 private long   cacheSize;  // cache size in bytes 
    private boolean  cleanCache; 
    private String[] cacheMasks; 
  
    private long     filesCached; 
    private long     bytesCached; 
    private long     bytesFree; 
    private long     hits; 
    private long     misses;


    private final int defaultProxyPort = 8080; 
    private final String defaultPassword = "admin"; 
    private final long defaultCacheSize = 1000000; 
  
 private String adminPath; 
 private int    adminPort;


 private String localHost; 
 private String localIP;


 private boolean isAppletContext; 
 private String  separator = " "; 
 private String proxyMachineNameAndPort;


 // 
 // Member methods 
 //


 // 
 // Constructor 
 // 
 Config() 
 { 
  filesCached = 0; 
  bytesCached = 0; 
  bytesFree = cacheSize; 
  hits = 0; 
  misses = 0;


  reset(); 
 }


 // 
 // Re-initialize 
 // 
 public void reset() 
 { 
        isFatherProxy = true; 
        fatherProxyHost = "wwwproxy.ac.il"; 
        fatherProxyPort = defaultProxyPort; 
        password = defaultPassword; 
     isCaching = true; 
     cacheSize = defaultCacheSize; 
        cleanCache = false;


  deniedHosts = new String[0]; 
  cacheMasks = new String[0]; 
 }


 // 
 // Set/get methods 
 //


 // Set if we are in the applet or in the proxy 
 public void setIsAppletContext(boolean b) 
 { 
  isAppletContext = b; 
 }


 public void setProxyMachineNameAndPort(String s) 
 { 
  proxyMachineNameAndPort = s; 
 }


 public String getProxyMachineNameAndPort() 
 { 
  return proxyMachineNameAndPort; 
 }


 public int getAdminPort() 
 { 
  return adminPort; 
 }


 public void setAdminPort(int port) 
 { 
  adminPort = port; 
 } 
  
 public void setAdminPath(String path) 
 { 
  adminPath = path; 
 }


 public String getAdminPath() 
 { 
  return adminPath; 
 } 
  
 public void setLocalHost(String host) 
 { 
  localHost = host; 
 }


 public String getLocalHost() 
 
  return localHost; 
 } 
  
 public void setLocalIP(String ip) 
 { 
  localIP = ip; 
 } 
  
 public String getLocalIP() 
 { 
  return localIP; 
 } 
  
 boolean getIsCaching() 
 { 
  return isCaching; 
 } 
  
 public synchronized void setIsCaching(boolean caching) 
 { 
  isCaching = caching; 
 }


 public synchronized long getCacheSize() 
 { 
  return cacheSize; 
 } 
 public synchronized void setCacheSize(long size) 
 { 
  cacheSize = size; 
 }


    public boolean getIsFatherProxy() 
    { 
        return isFatherProxy; 
    } 
  
    public synchronized void setIsFatherProxy(boolean fatherProxy) 
    { 
        isFatherProxy  = fatherProxy; 
    } 
  
    public String getFatherProxyHost() 
    { 
        return fatherProxyHost; 
    } 
  
    public synchronized void setFatherProxyHost(String host) 
    { 
        fatherProxyHost = host; 
    } 
  
    public int getFatherProxyPort() 
    { 
        return fatherProxyPort; 
    } 
  
    public synchronized void setFatherProxyPort(int port) 
    { 
        fatherProxyPort = port; 
    } 
  
    public String[] getDeniedHosts() 
    { 
        return deniedHosts; 
    } 
  
    public synchronized void setDeniedHosts(String[] hosts) 
    { 
        deniedHosts = hosts; 
    } 
  
    public String getPassword() 
    { 
        return password; 
    } 
  
    public synchronized void setPassword(String newPassword) 
    { 
        password = newPassword; 
    } 
  
    public boolean getCleanCache() 
    { 
        return cleanCache; 
    } 
  
    public synchronized void setCleanCache(boolean clean) 
    { 
        cleanCache = clean; 
    } 
  
    public String[] getCacheMasks() 
    { 
        return cacheMasks; 
    } 
  
    public synchronized void setCacheMasks(String[] masks) 
    { 
        cacheMasks = masks; 
    } 
  
    public long getFilesCached() 
    { 
        return filesCached; 
    } 
  
    public synchronized void increaseFilesCached() 
    { 
        filesCached++; 
    }


    public synchronized void decreaseFilesCached() 
    { 
        filesCached--; 
    }


 public synchronized void setFilesCached(long number) 
 { 
  filesCached = number; 
 } 
  
    public long getBytesCached() 
    { 
        return bytesCached; 
    } 
  
    public synchronized void setBytesCached(long number) 
    { 
        bytesCached = number; 
    }


    public long getBytesFree() 
    { 
        return cacheSize - bytesCached; 
    } 
  
    public long getHits() 
    { 
        return hits; 
    } 
  
    public synchronized void increaseHits() 
    { 
        hits++; 
    }


 public synchronized void setHits(long number) 
 { 
  hits = number; 
 } 
  
    public long getMisses() 
    { 
        return misses; 
    } 
  
    public synchronized void increaseMisses() 
    { 
        misses++; 
    }


 public synchronized void setMisses(long number) 
 { 
  misses = number; 
 }


    public double getHitRatio() 
    { 
        if ((hits + misses)==0) 
            return 0; 
        else 
            return 100*hits / (hits + misses); 
    } 



 // 
 // Construct a string with all parameters 
 // 
 public synchronized String toString() 
 { 
  int i; 
  String s = ""; 
  s += isFatherProxy + separator; 
        s += fatherProxyHost.equals("") ? "NULL" : fatherProxyHost; 
        s +=                    separator + 
        fatherProxyPort       + separator;


        s += deniedHosts.length + separator; 
        for (i=0; i<deniedHosts.length; i++) 
            s += deniedHosts[i] + separator; 
  
        s += 
        password              + separator + 
     isCaching             + separator + 
     cacheSize             + separator + 
        cleanCache            + separator;


        s += cacheMasks.length + separator; 
        for (i=0; i<cacheMasks.length; i++) 
            s += cacheMasks[i] + separator; 
  
        s+= proxyMachineNameAndPort + separator; 
  
  s += 
        filesCached           + separator + 
        bytesCached           + separator + 
        bytesFree             + separator + 
        hits                  + separator + 
        misses                + separator + 
  "\n"; 
  return s; 
 }


 // 
 // Set parameters according to a string (that was sent by applet) 
 // 
 public synchronized void parse(String config) 
 { 
  System.out.println("Parsing administrator request..."); 
  int size,i; 
  StringTokenizer s = new StringTokenizer(config,separator);


        isFatherProxy       = s.nextToken().equals("true"); 
  System.out.println("Use father proxy = "+isFatherProxy); 
        fatherProxyHost     = s.nextToken(); 
        if(fatherProxyHost.equals("NULL")) 
           fatherProxyHost = ""; 
  System.out.println("Father proxy name = "+fatherProxyHost);


        fatherProxyPort     = Integer.parseInt(s.nextToken()); 
  System.out.println("Father proxy port = "+fatherProxyPort);


        size = Integer.parseInt(s.nextToken()); 
        deniedHosts = new String[size]; 
        for (i=0; i<size; i++) 
  { 
            deniedHosts[i] = s.nextToken(); 
   System.out.println("Deny access to "+deniedHosts[i]); 
  }


        password            = s.nextToken(); 
  System.out.println("password = "+password); 
     isCaching           = s.nextToken().equals("true"); 
  System.out.println("Caching = "+isCaching); 
     cacheSize           = Long.parseLong(s.nextToken()); 
  System.out.println("Cache size = "+cacheSize); 
        cleanCache          = s.nextToken().equals("true"); 
  System.out.println("Do cache clean up = "+cleanCache); 
  
        size = Integer.parseInt(s.nextToken()); 
        cacheMasks = new String[size]; 
        for (i=0; i<size; i++) 
  { 
            cacheMasks[i] = s.nextToken(); 
   System.out.println("Don't cache "+cacheMasks[i]); 
  }


        proxyMachineNameAndPort = s.nextToken(); 
  
  if (isAppletContext) 
  { 
   filesCached         = Long.parseLong(s.nextToken()); 
   bytesCached         = Long.parseLong(s.nextToken()); 
   bytesFree           = Long.parseLong(s.nextToken()); 
   hits                = Long.parseLong(s.nextToken()); 
   misses              = Long.parseLong(s.nextToken()); 
  }


  // 
  // Update bytesFree to reflect the change in cache size. 
  // Note that free bytes can be below min free level now. 
  // 
  bytesFree = cacheSize - bytesCached; 
 
}


Daemon.c*java


/****************************************************************** 
*** File Daemon.c*java 
*** 
***/
import java.net.*; 
import java.io.*;

import c.net.*; 
import c.io.*;


// 
// Class:     Daemon 
// Abstract:  Web daemon thread. creates main socket on port 8080 
//            and listens on it forever. For each client request, 
//            creates proxy thread to handle the request. 
// 
public class Daemon extends Thread 

 // 
 // Member variables 
 // 
 static ServerSocket MainSocket = null; 
    static Cache cache = null; 
 static Config config; 
 static String adminPath;


 final static int defaultDaemonPort = 8080; 
 final static int maxDaemonPort = 65536;


  
 // 
 // Member methods 
 //


 // Application starts here 
 public static void main(String args[]) 
 { 
  int daemonPort;


  // Parse command line 
  switch (args.length) 
  { 
   case 0: daemonPort = defaultDaemonPort; 
     break;


   case 1: try 
     { 
      daemonPort = Integer.parseInt(args[0]); 
     } 
     catch (NumberFormatException e) 
     { 
      System.out.println("Error: Invalid daemon port"); 
      return; 
     } 
     if (daemonPort > maxDaemonPort) 
     { 
      System.out.println("Error: Invalid daemon port"); 
      return; 
     } 
     break;


   default:System.out.println("Usage: Proxy [daemon port]"); 
     return; 
  }


  
  
  try 
  { 
   // Create the Cache Manager and Configuration objects 
   System.out.println("Initializing..."); 
   System.out.print("Creating Config Object..."); 
   config = new Config(); 
   config.setIsAppletContext(false); 
   config.setLocalHost(InetAddress.getLocalHost().getHostName()); 
   String tmp = InetAddress.getLocalHost().toString(); 
   config.setLocalIP(tmp.substring(tmp.indexOf('/')+1)); 
   config.setProxyMachineNameAndPort(InetAddress.getLocalHost().getHostName()+":"+daemonPort); 
   File adminDir = new File("Applet"); 
   config.setAdminPath(adminDir.getAbsolutePath()); 
   System.out.println("OK");


   System.out.print("Creating Cache Manager..."); 
   cache = new Cache(config); 
   System.out.println("OK");


   // Start the admin thread 
   System.out.print("Creating Admin Thread..."); 
   Admin adminThd = new Admin(config,cache); 
   adminThd.start(); 
   System.out.println(" port " + config.getAdminPort() + " OK"); 
  
   // Create main socket 
            System.out.print("Creating Daemon Socket..."); 
   MainSocket = new ServerSocket(daemonPort); 
   System.out.println(" port " + daemonPort + " OK");


   if (config.getIsFatherProxy()) 
   { 
    System.out.println("Using Father Proxy "+ 
     config.getFatherProxyHost()+ 
     ":"+config.getFatherProxyPort()+" ."); 
   } 
   else 
   { 
    System.out.println("Not Using Father Proxy ."); 
   } 
   System.out.println("Proxy up and running!");


   // Main loop 
   while (true) 
   { 
    // Listen on main socket 
    Socket ClientSocket = MainSocket.accept();


    // Pass request to new proxy thread 
    Proxy thd = new Proxy(ClientSocket,cache,config); 
    thd.start(); 
   } 
  
  } 
  
  catch (Exception e) 
  {}


  finally 
  { 
   try 
   { 
    MainSocket.close(); 
   } 
   catch (Exception exc) 
   { 
   } 
  } 
 } 




HttpReplyHdr.java


/****************************************************************** 
*** File HttpReplyHdr.java 
*** 
***/
import java.net.*; 
import java.io.*;


// 
// Class:     HttpReplyHdr 
// Abstract:  The headers of the server HTTP reply. 
//


/** 
 * Generates a http reply header. The header indicates the outcome 
 * of a http request. 
 * 
 */ 
public class HttpReplyHdr 
{


   static String CR="\r\n"; 
   static String HTTP_PROTOCOL="HTTP/1.0"; 
   static String HTTP_SERVER="Java Proxy Server";


   String lastModified =""; 
   long   contentLength=0; 
   String extraErrorString ="";


/** 
 * Sets the last modified date for a header; 
 
 * @param date  A string holding an interner date 
 * @return      true 
 */ 
public boolean setModifiedDate(String date) 
   { 
      lastModified = date; 
      return true; 
   }


/** 
 * Adds an extra explanation. This extra information is 
 * Added to the http headers failure explanation. 
 * 
 * @param str  Description to add. 
 * @return     true. 
 */ 
public boolean addErrorDescription(String str) 
   { 
      extraErrorString = str; 
      return true; 
   }


/** 
 * Forms a http ok reply header 
 * 
 * @param ContentType The mime-type of the content 
 * @return            A string with the header in it 
 */ 
public String formOk(String ContentType,long  ContentLength) 
   {


       contentLength = ContentLength; 
  
       String out =new String(); 
  
       out += HTTP_PROTOCOL + " 200 Ok" + CR; 
       out += "Server: " + HTTP_SERVER  + CR; 
       out += "MIME-version: 1.0"       + CR;


       if (0 < ContentType.length()) 
           out += "Content-type: " + ContentType + CR; 
       else 
           out += "Content-Type: text/html" + CR;

       if (0 != contentLength) 
           out += "Content-Length: " + Long.toString(contentLength) + CR;


       if (0 < lastModified.length()) 
           out +="Last-Modified: " + lastModified + CR;


       out +=CR;


       return out; 
   }


/** 
 * private! builds an http document describing a headers reason. 
 * 
 * @param Error        Error name. 
 * @param Description  Errors description. 
 * @return             A string with the HTML description body 
 */ 
private String formErrorBody(String Error,String Description) 
   { 
   String out; 
   //Generate Error Body 
   out  ="<HTML><HEAD><TITLE>"; 
   out += Error ; 
   out +="</TITLE></HEAD>"; 
   out +="<BODY><H2>" + Error +"</H2>\n"; 
   out +="</P></H3>"; 
   out += Description; 
   out +="</BODY></HTML>"; 
   return out; 
   }


  
/** 
 * builds an http document describing an error. 
 * 
 * @param Error        Error name. 
 * @param Description  Errors description. 
 * @return             A string with the HTML description body 
 */ 
private String formError(String Error, String Description) 
   { 
   /* A HTTP RESPONCE HEADER LOOKS ALOT LIKE: 
    * 
    * HTTP/1.0 200 OK 
    * Date: Wednesday, 02-Feb-94 23:04:12 GMT 
    * Server: NCSA/1.1 
    * MIME-version: 1.0 
    * Last-modified: Monday, 15-Nov-93 23:33:16 GMT 
    * Content-type: text/html 
    * Content-length: 2345 
    * \r\n 
    */ 
  
   String body=formErrorBody(Error,Description); 
   String header =new String();

   header +=HTTP_PROTOCOL +" " + Error + CR; 
   header +="Server: " + HTTP_SERVER   + CR; 
   header +="MIME-version: 1.0"        + CR; 
   header +="Content-type: text/html"  + CR; 
  
   if (0 < lastModified.length()) 
       header +="Last-Modified: " + lastModified +CR;


   header +="Content-Length: " + String.valueOf(body.length())+ CR;


   header += CR; 
   header += body; 
  
   return header; 
   }


/** 
 * Indicates a new file was created. 
 * 
 * @return    The header in a string; 
 */ 
public String formCreated() 
   { 
   return formError("201 Created","Object was created"); 
   }


/** 
 * Indicates the document was accepted. 
 * 
 * @return    The header in a string; 
 */ 
public String formAccepted() 
   { 
   return formError("202 Accepted","Object checked in"); 
   }


/** 
 * Indicates only a partial responce was sent. 
 * 
 * @return    The header in a string; 
 */ 
public String  formPartial() 
   { 
   return formError("203 Partial","Only partail document available"); 
   }


/** 
 * Indicates a requested URL has moved to a new address or name. 
 * 
 * @return    The header in a string; 
 */ 
public String formMoved() 
   { 
   //300 codes tell client to do actions 
   return formError("301 Moved","File has moved"); 
   }


/** 
 * Never seen this used. 
 * 
 * @return    The header in a string; 
 */ 
public String formFound() 
   { 
   return formError("302 Found","Object was found"); 
   }

/** 
 * The requested method is not implemented by the server. 
 * 
 * @return    The header in a string; 
 */ 
public String formMethod() 
   { 
   return formError("303 Method unseported","Method unseported"); 
   }


/** 
 * Indicates remote copy of the requested object is current. 
 * 
 * @return    The header in a string; 
 */ 
public String formNotModified() 
   { 
   return formError("304 Not modified","Use local copy"); 
   }


/** 
 * Client not otherized for the request. 
 * 
 * @return    The header in a string; 
 */ 
public String formUnautorized() 
   { 
   return formError("401 Unathorized","Unathorized use of this service"); 
   }


/** 
 * Payment is required for service. 
 * 
 * @return    The header in a string; 
 */ 
public String formPaymentNeeded() 
   { 
   return formError("402 Payment required","Payment is required"); 
   }


/** 
 * Client if forbidden to get the request service. 
 * 
 * @return    The header in a string; 
 */ 
public String formForbidden() 
   { 
   return formError("403 Forbidden","You need permission for this service"); 
   } 
  
/** 
 * The requested object was not found. 
 * 
 * @return    The header in a string; 
 */ 
public String formNotFound() 
   { 
   return formError("404 Not_found","Requested object was not found"); 
   }


/** 
 * The server had a problem and could not fulfill the request. 
 * 
 * @return    The header in a string; 
 */ 
public String formInternalError() 
   { 
   return formError("500 Internal server error","Server broke"); 
   }


/** 
 * Server does not do the requested feature. 
 * 
 * @return    The header in a string; 
 */ 
public String formNotImplemented() 
   { 
   return formError("501 Method not implemented","Service not implemented, programer was lazy"); 
   }


/** 
 * Server is overloaded, client should try again latter. 
 * 
 * @return    The header in a string; 
 */ 
public String formOverloaded() 
   { 
   return formError("502 Server overloaded","Try again latter"); 
   }


/** 
 * Indicates the request took to long. 
 * 
 * @return    The header in a string; 
 */ 
public String formTimeout() 
   { 
   return formError("503 Gateway timeout","The connection timed out"); 
   }


/** 
 * Indicates the client's proxies could not locate a server. 
 * 
 * @return    The header in a string; 
 */ 
public String formServerNotFound() 
   { 
   return formError("503 Gateway timeout","The requested server was not found"); 
   }

/** 
 * Indicates the client is not allowed to access the object. 
 * 
 * @return    The header in a string; 
 */ 
public String formNotAllowed() 
   { 
   return formError("403 Access Denied","Access is not allowed"); 
   } 
}


HttpRequestHdr.java


/****************************************************************** 
*** File HttpRequestHdr.java 
*** 
***/
import java.io.InputStream; 
import java.io.DataInputStream; 
import java.util.StringTokenizer;


// 
// Class:     HttpRequestHdr 
// Abstract:  The headers of the client HTTP request. 
//


/** 
 * Parses and stores a http server request. 
 * 
 */ 
public class HttpRequestHdr 

  
   /** 
    * Http Request method. Such as get or post. 
    */ 
   public  String method = new String();


   /** 
    * The requested url. The universal resource locator that 
    * hopefully uniquely describes the object or service the 
    * client is requesting. 
    */ 
   public String url   = new String();


   /** 
    * Version of http being used. Such as HTTP/1.0 
    */ 
   public String version           = new String();


   /** 
    * The client's browser's name. 
    */ 
   public String userAgent         = new String();


   /** 
    * The requesting documents that contained the url link. 
    */ 
   public String referer           = new String();


   /** 
    * A internet address date of the remote copy. 
    */ 
   public String ifModifiedSince   = new String();


   /** 
    * A list of mime types the client can accept. 
    */ 
   public String accept            = new String();


   /** 
    * The clients authorization. Don't belive it. 
    */


   public String authorization     = new String(); 
   /** 
    * The type of content following the request header. 
    * Normally there is no content and this is blank, however 
    * the post method usually does have a content and a content 
    * length. 
    */ 
   public String contentType       = new String(); 
   /** 
    * The length of the content following the header. Usually 
    * blank. 
    */ 
   public int    contentLength     = -1; 
   /** 
    * The content length of a remote copy of the requested object. 
    */ 
   public int    oldContentLength  = -1; 
   /** 
    * Anything in the header that was unrecognized by this class. 
    */ 
   public String unrecognized      = new String(); 
   /** 
    * Indicates that no cached versions of the requested object are 
    * to be sent. Usually used to tell proxy not to send a cached copy. 
    * This may also effect servers that are front end for data bases. 
    */ 
   public boolean pragmaNoCache    = false;


   static String CR ="\r\n";


/** 
 * Parses a http header from a stream. 
 * 
 * @param in  The stream to parse. 
 * @return    true if parsing sucsessfull. 
 */ 
public boolean parse(InputStream In) 
   { 
       String CR ="\r\n";


       /* 
        * Read by lines 
        */ 
       DataInputStream lines; 
       StringTokenizer tz; 
       try 
    { 
           lines = new DataInputStream(In); 
           tz = new StringTokenizer(lines.readLine()); 
       } 
    catch (Exception e) 
    { 
           return false; 
       }


       /* 
        * HTTP COMMAND LINE < <METHOD==get> <URL> <HTTP_VERSION> > 
        */ 
       method = getToken(tz).toUpperCase(); 
       url    = getToken(tz); 
       version= getToken(tz); 
  
       while (true) 
    { 
           try 
     { 
               tz = new StringTokenizer(lines.readLine()); 
           } 
     catch (Exception e) 
     { 
               return false; 
           } 
           String Token = getToken(tz); 
  
           // look for termination of HTTP command 
           if (0 == Token.length()) 
               break; 
  
           if (Token.equalsIgnoreCase("USER-AGENT:")) { 
               // line =<User-Agent: <Agent Description>> 
               userAgent = getRemainder(tz); 
           } else if (Token.equalsIgnoreCase("ACCEPT:")) { 
               // line=<Accept: <Type>/<Form> 
               // examp: Accept image/jpeg 
               accept += " " + getRemainder(tz);


           } else if (Token.equalsIgnoreCase("REFERER:")) { 
               // line =<Referer: <URL>> 
               referer = getRemainder(tz);


           } else if (Token.equalsIgnoreCase("PRAGMA:")) { 
               // Pragma: <no-cache> 
               Token = getToken(tz);


               if (Token.equalsIgnoreCase("NO-CACHE")) 
                   pragmaNoCache = true; 
               else 
                   unrecognized += "Pragma:" + Token + " " 
                       +getRemainder(tz) +"\n"; 
           } else if (Token.equalsIgnoreCase("AUTHORIZATION:")) { 
               // Authenticate: Basic UUENCODED 
               authorization=  getRemainder(tz);


           } else if (Token.equalsIgnoreCase("IF-MODIFIED-SINCE:")) { 
               // line =<If-Modified-Since: <http date> 
               // *** Conditional GET replaces HEAD method *** 
               String str = getRemainder(tz); 
              int index = str.indexOf(";"); 
              if (index == -1) { 
                   ifModifiedSince  =str; 
               } else { 
                   ifModifiedSince  =str.substring(0,index); 
  
                  index = str.indexOf("="); 
                  if (index != -1) { 
                      str = str.substring(index+1); 
                      oldContentLength =Integer.parseInt(str); 
                  } 
              } 
           } else if (Token.equalsIgnoreCase("CONTENT-LENGTH:")) { 
               Token = getToken(tz); 
               contentLength =Integer.parseInt(Token); 
           } else if (Token.equalsIgnoreCase("CONTENT-TYPE:")) { 
               contentType = getRemainder(tz); 
           } else { 
               unrecognized += Token + " " + getRemainder(tz) + CR; 
           } 
       } 
       return true; 
   } 
  
   /* 
    * Rebuilds the header in a string 
    * @returns      The header in a string. 
    */ 
   public String toString(boolean sendUnknowen) { 
       String Request;


       if (0 == method.length()) 
            method = "GET";


       Request = method +" "+ url + " HTTP/1.0" + CR;

       if (0 < userAgent.length()) 
           Request +="User-Agent:" + userAgent + CR;


       if (0 < referer.length()) 
           Request+= "Referer:"+ referer  + CR;


       if (pragmaNoCache) 
           Request+= "Pragma: no-cache" + CR;


       if (0 < ifModifiedSince.length()) 
           Request+= "If-Modified-Since: " + ifModifiedSince + CR; 
  
       // ACCEPT TYPES // 
       if (0 < accept.length()) 
           Request += "Accept: " + accept + CR; 
       else 
           Request += "Accept: */"+"* \r\n"; 
  
       if (0 < contentType.length()) 
           Request += "Content-Type: " + contentType   + CR;


       if (0 < contentLength) 
           Request += "Content-Length: " + contentLength + CR; 
  
  
       if (0 != authorization.length()) 
           Request += "Authorization: " + authorization + CR;


       if (sendUnknowen) { 
           if (0 != unrecognized.length()) 
               Request += unrecognized; 
       }


       Request += CR; 
  
       return Request; 
   }


   /** 
    * (Re)builds the header in a string. 
    * 
    * @returns      The header in a string. 
    */ 
   public String toString() { 
       return toString(true); 
   }


   /** 
    *  Returns the next token in a string 
    * 
    * @param   tk String that is partially tokenized. 
    * @returns The remainder 
    */ 
   String  getToken(StringTokenizer tk){ 
       String str =""; 
       if  (tk.hasMoreTokens()) 
           str =tk.nextToken(); 
       return str; 
   } 
  
   /** 
    *  Returns the remainder of a tokenized string 
    * 
    * @param   tk String that is partially tokenized. 
    * @returns The remainder 
    */ 
   String  getRemainder(StringTokenizer tk){ 
       String str =""; 
       if  (tk.hasMoreTokens()) 
           str =tk.nextToken(); 
       while (tk.hasMoreTokens()){ 
           str +=" " + tk.nextToken(); 
       } 
       return str; 
   }


}


Proxy.java


/****************************************************************** 
*** File Proxy.java 
*** 
***/
import java.net.*; 
import java.io.*; 
import java.util.*;


// 
// Class:     Proxy 
// Abstract:  Thread to handle one client request. get the requested 
//            object from the web server or from the cache, and delivers 
//            the bits to client. 
// 
public class Proxy extends Thread 

 // 
 // Member variables 
 // 
 Socket ClientSocket = null;              // Socket to client 
 Socket SrvrSocket = null;                // Socket to web server 
    Cache  cache = null;                     // Static cache manager object 
 String localHostName = null;             // Local machine name 
 String localHostIP = null;               // Local machine IP address 
 String adminPath = null;                 // Path of admin applet 
 Config config = null;                    // Config object


  
 // 
 // Public member methods 
 //


 // 
 // Constructor 
 // 
 Proxy(Socket clientSocket, Cache CacheManager, Config configObject) 
 { 
  // 
  // Initialize member variables 
  // 
  config = configObject; 
  ClientSocket = clientSocket; 
  cache = CacheManager; 
  localHostName = config.getLocalHost(); 
  localHostIP = config.getLocalIP(); 
  adminPath = config.getAdminPath(); 
    }


 // 
 // run - Main work is done here: 
 // 
    public void run() 
 { 
        String serverName =""; 
  URL url;


  byte line[]; 
        HttpRequestHdr request = new HttpRequestHdr(); 
        HttpReplyHdr   reply   = new HttpReplyHdr(); 
  FileInputStream fileInputStream = null; 
  FileOutputStream fileOutputStream = null; 
  boolean TakenFromCache = false; 
  boolean isCachable = false;


  try 
  { 
   // 
   // Read HTTP Request from client 
   // 
            request.parse(ClientSocket.getInputStream()); 
            url = new URL(request.url); 
            System.out.println("Request = " + url); 
  
   // 
   // Send Web page with applet to administrator 
   // 
   if (url.getFile().equalsIgnoreCase("/admin") && 
    (url.getHost().equalsIgnoreCase(localHostName) || 
     url.getHost().equalsIgnoreCase(localHostIP) )) 
   { 
    sendAppletWebPage(); 
    return; 
   }


   // 
   // Send Applet Files to administrator 
   // 
   if ((url.getHost().equalsIgnoreCase(localHostName) || 
     url.getHost().equalsIgnoreCase(localHostIP) )) 
   { 
    sendAppletClass(url.getFile()); 
    return; 
   }


   // 
   // Check if accessing the URL is allowed by administrator 
   // 
   String[] denied = config.getDeniedHosts(); 
   for (int i=0; i<denied.length; i++) 
   { 
    if (url.toString().indexOf(denied[i]) != -1) 
    { 
     System.out.println("Access not allowed..."); 
     DataOutputStream out = 
        new DataOutputStream(ClientSocket.getOutputStream()); 
     out.writeBytes(reply.formNotAllowed()); 
     out.flush(); 
        ClientSocket.close(); 
     return; 
    } 
   } 
  
  
   // 
   // Client wants a web page - let's see if we have it in cache 
   // 
   if (cache.IsCached(url.toString())) 
   { 
    // 
    // Client request is allready cached - get it from file 
    // 
    System.out.println("Hit! Getting from cache!!!"); 
    config.increaseHits(); 
    TakenFromCache = true;


    // Get FileInputStream from Cache Manager 
    fileInputStream  = cache.getFileInputStream(url.toString()); 
    OutputStream out = ClientSocket.getOutputStream();


    // Send the bits to client 
    byte data[] = new byte[2000]; 
    int count; 
    while (-1 < ( count  = fileInputStream.read(data))) 
    { 
     out.write(data,0,count); 
    } 
    out.flush(); 
    fileInputStream.close(); 
   }


            // 
   // We do not have the page in cache 
   // 
   else 
   { 
    // 
    // Open socket to web server (or father proxy) 
    // 
    if (config.getIsFatherProxy()) 
    { 
        System.out.println("Miss! Forwarding to father proxy " + 
      config.getFatherProxyHost() + ":" + 
      config.getFatherProxyPort() + "..."); 
     config.increaseMisses(); 
     SrvrSocket = new Socket(config.getFatherProxyHost(), 
                          config.getFatherProxyPort()); 
    } 
    else 
    { 
        serverName  = url.getHost(); 
     System.out.println("Miss! Forwarding to server "+ 
      serverName + "..."); 
     config.increaseMisses(); 
     SrvrSocket = new Socket(serverName(request.url), 
              serverPort(request.url)); 
     request.url = serverUrl(request.url); 
    } 
  
    DataOutputStream srvOut = 
       new DataOutputStream(SrvrSocket.getOutputStream());


    // 
    // Send the url to web server (or father proxy) 
    // 
    srvOut.writeBytes(request.toString(false)); 
    srvOut.flush();


    // 
    // Send data to server (needed for post method) 
    // 
    for (int i =0; i < request.contentLength; i++) 
    { 
       SrvrSocket.getOutputStream().write(ClientSocket.getInputStream().read()); 
    } 
    SrvrSocket.getOutputStream().flush();


    // 
    // Find if reply should be cached - 
    //   First, check if caching is on. 
    // 
    isCachable = config.getIsCaching(); 
    String reasonForNotCaching = "Caching is OFF.";


    // Second, parse the URL for special characters. 
    if (isCachable) 
    { 
     isCachable = cache.IsCachable(url.toString()); 
     reasonForNotCaching = "URL not cacheable"; 
    }


    // Third, check reply headers (we must read first 
    //         line of headers for that). 
    DataInputStream  Din  = 
       new DataInputStream(SrvrSocket.getInputStream()); 
    DataOutputStream Dout = 
       new DataOutputStream(ClientSocket.getOutputStream()); 
    String str = Din.readLine(); 
    StringTokenizer s = new StringTokenizer(str); 
    String retCode = s.nextToken(); // first token is HTTP protocol 
    retCode = s.nextToken(); // second is return code 
    // Return codes 200,302,304 are OK to cache 
    if (isCachable) 
    { 
     if (!retCode.equals("200") && !retCode.equals("302") 
      && !retCode.equals("304")) 
     { 
      isCachable = false; 
                        reasonForNotCaching = "Return Code is "+retCode; 
     } 
    }


    // Fourth, check if URL is cache-allowed by administrator 
    if (isCachable) 
    { 
     String[] denyCache = config.getCacheMasks(); 
     for (int i=0; i<denyCache.length; i++) 
     { 
      if (url.toString().indexOf(denyCache[i]) != -1) 
      { 
       isCachable = false; 
       reasonForNotCaching = "Caching this URL is not allowed"; 
       break; 
      } 
     } 
    }


                if (isCachable) 
    { 
     System.out.println("Caching the reply..."); 
     fileOutputStream = cache.getFileOutputStream(url.toString()); 
    } 
    else 
    { 
     System.out.println("NOT Caching the reply. Reason:" 
      +reasonForNotCaching); 
    } 
  
    // 
    // First line was read - send it to client and cache it 
    // 
    String tempStr = new String(str+"\r\n"); 
    Dout.writeBytes(tempStr); 
    if (isCachable) 
    { 
     // Translate reply string to bytes 
     line = new byte[tempStr.length()]; 
     tempStr.getBytes(0,tempStr.length(),line,0); 
  
     // Write bits to file 
     fileOutputStream.write(line); 
     cache.DecrementFreeSpace(line.length,url.toString()); 
    }


    // 
    // Read next lines in reply header, send them to 
    // client and cache them 
    // 
    if (str.length() > 0) 
     while (true) 
     { 
      str = Din.readLine(); 
      tempStr = new String(str+"\r\n");


      // Send bits to client 
      Dout.writeBytes(tempStr); 
  
      if (isCachable) 
      { 
       // Translate reply string to bytes 
       line = new byte[tempStr.length()]; 
       tempStr.getBytes(0,tempStr.length(),line,0); 
  
       // Write bits to file 
       fileOutputStream.write(line); 
       cache.DecrementFreeSpace(line.length,url.toString()); 
      }


      if (str.length() <= 0) 
       break; 
     } 
    Dout.flush(); 



    // 
    // With the HTTP reply body do: 
    //   (1) Send it to client. 
    //   (2) Cache it. 
    // 
    InputStream  in  = SrvrSocket.getInputStream(); 
    OutputStream out = ClientSocket.getOutputStream();


    byte data[] = new byte[2000]; 
    int count; 
    while (( count  = in.read(data)) > 0) 
    { 
     // Send bits to client 
     out.write(data,0,count);


     if (isCachable) 
     { 
      // Write bits to file 
      line  = new byte[count]; 
      System.arraycopy(data,0,line,0,count); 
      fileOutputStream.write(line); 
      cache.DecrementFreeSpace(count,url.toString()); 
     } 
    } 
    out.flush(); 
    if (isCachable) 
    { 
     fileOutputStream.close();


     // Add new entry to hash table 
     cache.AddToTable(url.toString()); 
    }


   } 
  } 
  
        catch (UnknownHostException uhe) 
  { 
   // 
            // Requested Server could not be located 
            // 
            System.out.println("Server Not Found."); 
  
            try 
   { 
    // Notify client that server not found 
    DataOutputStream out = 
                   new DataOutputStream(ClientSocket.getOutputStream()); 
                out.writeBytes(reply.formServerNotFound()); 
                out.flush(); 
            } 
   catch (Exception uhe2) 
   {} 
  } 
  
  catch (Exception e) 
  { 
            try 
   { 
    if (TakenFromCache) 
     fileInputStream.close(); 
    else if (isCachable) 
     fileOutputStream.close(); 
  
    // Notify client that internal error accured in proxy 
    DataOutputStream out = 
                   new DataOutputStream(ClientSocket.getOutputStream()); 
                out.writeBytes(reply.formTimeout()); 
                out.flush(); 
  
            } 
   catch (Exception uhe2) 
   {} 
        } 
  
  finally 
  { 
   try 
   { 
    ClientSocket.getOutputStream().flush(); 
    ClientSocket.close(); 
   } 
   catch (Exception e) 
   {} 
  } 
    }


  
 // 
 // Private methods 
 //


 // 
 // Send to administrator web page containing reference to applet 
 // 
 private void sendAppletWebPage() 
 { 
  System.out.println("Sending the applet..."); 
  String page = ""; 
  try 
  { 
   File appletHtmlPage = new File(config.getAdminPath() + 
             File.separator + "Admin.html"); 
   DataInputStream in = new DataInputStream(new FileInputStream(appletHtmlPage));


   String s = null;


   while((s = in.readLine()) != null) 
    page += s; 
  
   page = page.substring(0,page.indexOf("PORT")) + 
     config.getAdminPort() + 
     page.substring(page.indexOf("PORT")+4); 
  
   in.close(); 
   DataOutputStream out = new DataOutputStream(ClientSocket.getOutputStream()); 
   out.writeBytes(page); 
   out.flush(); 
   out.close(); 
  } 
  catch (Exception e) 
  { 
   System.out.println("Error: can't open applet html page"); 
  }


 }


 // 
 // Send the applet to administrator 
 // 
 private void sendAppletClass(String className) 
 { 
  try 
  { 
   byte data[] = new byte[2000]; 
   int count; 
   HttpReplyHdr   reply   = new HttpReplyHdr(); 
   File appletFile = new File(adminPath + File.separatorChar + className); 
   long length = appletFile.length();


   FileInputStream in = new FileInputStream(appletFile); 
   DataOutputStream out = new DataOutputStream(ClientSocket.getOutputStream());


   out.writeBytes(reply.formOk("application/octet-stream",length)); 
  
   while (-1 < ( count  = in.read(data))) 
   { 
    out.write(data,0,count); 
   } 
   out.flush(); 
   in.close(); 
   out.close(); 
  } 
  catch (Exception e) 
  {} 
 }


 // 
 // Parsing Methods 
 //


    /** 
     * Find the //server.name from an url. 
     * 
     * @return Servers internet name 
     */ 
    private String serverName(String str) 
 { 
        // chop to "server.name:x/thing" 
        int i = str.indexOf("//"); 
        if (i< 0) return ""; 
        str = str.substring(i+2); 
  
        // chop to  server.name:xx 
        i = str.indexOf("/"); 
        if (0 < i) str = str.substring(0,i); 
  
        // chop to server.name 
        i = str.indexOf(":"); 
        if (0 < i) str = str.substring(0,i); 
  
        return str; 
    } 
  
    /** 
     * Find the :PORT form http://server.ect:PORT/some/file.xxx 
     * 
     * @return Servers internet name 
     */ 
    private int serverPort(String str) 
 { 
        // chop to "server.name:x/thing" 
        int i = str.indexOf("//"); 
        if (i< 0) return 80; 
        str = str.substring(i+2); 
  
        // chop to  server.name:xx 
        i = str.indexOf("/"); 
        if (0 < i) str = str.substring(0,i); 
  
        // chop XX 
        i = str.indexOf(":"); 
        if (0 < i) 
  { 
            return Integer.parseInt(str.substring(i).trim()); 
        } 
  
        return 80; 
    }


    /** 
     * Find the /some/file.xxxx form http://server.ect:PORT/some/file.xxx 
     * 
     * @return the deproxied url 
     */ 
    private String serverUrl(String str) 
 { 
        int i = str.indexOf("//"); 
        if (i< 0) return str;


        str = str.substring(i+2); 
        i = str.indexOf("/"); 
        if (i< 0) return str;


        return str.substring(i); 
    } 
}

No comments:

Post a Comment