remove another file
[IRC.git] / Robust / src / Benchmarks / Jhttpp2 / Java / Jhttpp2HTTPSession.java
1 /* Written and copyright 2001-2003 Benjamin Kohl.
2  * Distributed under the GNU General Public License; see the README file.
3  * This code comes with NO WARRANTY.
4  */
5
6 import java.net.Socket;
7 import java.net.InetAddress;
8 import java.net.UnknownHostException;
9
10 import java.io.BufferedOutputStream;
11 import java.io.BufferedInputStream;
12 import java.io.DataInputStream;
13 import java.io.IOException;
14 import java.io.File;
15 import java.io.FileInputStream;
16
17
18 /**
19         One HTTP connection
20         @file Jhttpp2HTTPSession.java
21         @author Benjamin Kohl
22 */
23 public class Jhttpp2HTTPSession extends Thread {
24
25     public final int SC_OK;
26     public final int SC_CONNECTING_TO_HOST;
27     public final int SC_HOST_NOT_FOUND;
28     public final int SC_URL_BLOCKED;
29     public final int SC_CLIENT_ERROR;
30     public final int SC_INTERNAL_SERVER_ERROR;
31     public final int SC_NOT_SUPPORTED;
32     public final int SC_REMOTE_DEBUG_MODE;
33     public final int SC_CONNECTION_CLOSED;
34     public final int SC_HTTP_OPTIONS_THIS;
35     public final int SC_FILE_REQUEST;
36     public final int SC_MOVED_PERMANENTLY;
37     public final int SC_CONFIG_RQ;
38     
39
40     void init() {
41          SC_OK=0;
42          SC_CONNECTING_TO_HOST=1;
43          SC_HOST_NOT_FOUND=2;
44          SC_URL_BLOCKED=3;
45          SC_CLIENT_ERROR=4;
46          SC_INTERNAL_SERVER_ERROR=5;
47          SC_NOT_SUPPORTED=6;
48          SC_REMOTE_DEBUG_MODE=7;
49          SC_CONNECTION_CLOSED=8;
50          SC_HTTP_OPTIONS_THIS=9;
51          SC_FILE_REQUEST=10;
52          SC_MOVED_PERMANENTLY=11;
53          SC_CONFIG_RQ = 12;
54     }
55
56     private Jhttpp2Server server;
57     
58     /** downstream connections */
59     private Socket client;
60     private BufferedOutputStream out;
61     private Jhttpp2ClientInputStream in;
62     
63     /** upstream connections */
64     private Socket HTTP_Socket;
65     private BufferedOutputStream HTTP_out;
66     private BufferedInputStream HTTP_in;
67     
68         public Jhttpp2HTTPSession(Jhttpp2Server server,Socket client) {
69             init();
70             in = new Jhttpp2ClientInputStream(server,this,client.getInputStream());//,true);
71             out = new BufferedOutputStream(client.getOutputStream());
72             this.server=server;
73             this.client=client;
74             start();
75         }
76         public Socket getLocalSocket() {
77                 return client;
78         }
79         public Socket getRemoteSocket() {
80                 return HTTP_Socket;
81         }
82         public boolean isTunnel() {
83                 return in.isTunnel();
84         }
85         public boolean notConnected() {
86                 return HTTP_Socket==null;
87         }
88     public void sendHeader(int a,boolean b) {
89                 sendHeader(a);
90                 endHeader();
91                 out.flush();
92         }
93         public void sendHeader(int status, String content_type, long content_length) {
94                 sendHeader(status);
95                 sendLine("Content-Length", String.valueOf(content_length));
96                 sendLine("Content-Type", content_type );
97         }
98         public void sendLine(String s) {
99                 write(out,s + "\r\n");
100         }
101         public void sendLine(String header, String s) {
102                 write(out,header + ": " + s + "\r\n");
103         }
104         public void endHeader() {
105                 write(out,"\r\n");
106         }
107         public void run() {
108                 if (server.debug)server.writeLog("begin http session");
109                 server.increaseNumConnections();
110                 handleRequest();
111                 in.close(); // since 0.4.10b
112                 out.close();
113                 client.close();
114                 // close upstream connections (webserver or other proxy)
115                 if (!notConnected()) {
116                     HTTP_Socket.close();
117                     HTTP_out.close();
118                     HTTP_in.close();
119                 }
120                 server.decreaseNumConnections();
121                 if (server.debug)server.writeLog("end http session");
122         }
123         /** sends a message to the user */
124         public void sendErrorMSG(int a,String info) {
125                 String statuscode = sendHeader(a);
126                 String localhost = "localhost"+":"+server.port;
127                 String msg = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"><html>\r"
128                     + "<!-- jHTTPp2 error message --><HEAD>\r"
129                     + "<TITLE>" + statuscode + "</TITLE>\r"
130                     + "<link rel=\"stylesheet\" type=\"text/css\" href=\"http://" + localhost + "/style.css\"></HEAD>\r"  // use css style sheet in htdocs
131                     + "<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#000080\" VLINK=\"#000080\" ALINK=\"#000080\">\r"
132                     + "<h2 class=\"headline\">HTTP " + statuscode + " </h2>\r"
133                     + "<HR size=\"4\">\r"
134                     + "<p class=\"i30\">Your request for the following URL failed:</p>"
135                     + "<p class=\"tiagtext\"><a href=\"" + in.getFullURL() + "\">" + in.getFullURL() + "</A> </p>\r"
136                     + "<P class=\"i25\">Reason: " + info + "</P>"
137                     + "<HR size=\"4\">\r"
138                     + "<p class=\"i25\"><A HREF=\"http://jhttp2.sourceforge.net/\">jHTTPp2</A> HTTP Proxy, Version " + server.getServerVersion() + " at " + localhost
139                     + "<br>Copyright &copy; 2001-2003 <A HREF=\"mailto:bkohl@users.sourceforge.net\">Benjamin Kohl</A></p>\r"
140                     + "<p class=\"i25\"><A HREF=\"http://" + localhost + "/\">jHTTPp2 local website</A> <A HREF=\"http://" + localhost + "/" + server.WEB_CONFIG_FILE + "\">Configuration</A></p>"
141                     + "</BODY></HTML>";
142                 sendLine("Content-Length",String.valueOf(msg.length()));
143                 sendLine("Content-Type","text/html; charset=iso-8859-1");
144                 endHeader();
145                 write(out,msg);
146                 out.flush();
147         }
148
149         public String sendHeader(int a) {
150             String stat;
151             if (a==200)
152                 stat="200 OK";
153             else if (a==202)
154                 stat="202 Accepted";
155             else if (a==300)
156                 stat="300 Ambiguous";
157             else if (a==301)
158                 stat="301 Moved Permanently";
159             else if (a==400)
160                 stat="400 Bad Request";
161             else if (a==401)
162                 stat="401 Denied";
163             else if (a==403)
164                 stat="403 Forbidden";
165             else if (a==404)
166                 stat="404 Not Found";
167             else if (a==405)
168                 stat="405 Bad Method";
169             else if (a==413)
170                 stat="413 Request Entity Too Large";
171             else if (a==415)
172                 stat="415 Unsupported Media";
173             else if (a==501)
174                 stat="501 Not Implemented";
175             else if (a==502)
176                 stat="502 Bad Gateway";
177             else if (a==504)
178                 stat="504 Gateway Timeout";
179             else if (a==505)
180                 stat="505 HTTP Version Not Supported";
181             else 
182                 stat="500 Internal Server Error";
183             sendLine(server.getHttpVersion() + " " + stat);
184             sendLine("Server",server.getServerIdentification());
185             if (a==501) 
186                 sendLine("Allow","GET, HEAD, POST, PUT, DELETE, CONNECT");
187             sendLine("Cache-Control", "no-cache, must-revalidate");
188             sendLine("Connection","close");
189             return stat;
190         }
191     
192     /** the main routine, where it all happens */
193     public int handleRequest() {
194         InetAddress remote_host;
195         Jhttpp2Read remote_in=null;
196         int remote_port;
197         byte[] b=new byte[65536];
198         int numread=in.read(b);
199         if (numread==-2)
200             return -1;
201         boolean cnt=true;
202         while(cnt) { // with this loop we support persistent connections
203             if (numread==-1) { // -1 signals an error
204                 if (in.getStatusCode()!=SC_CONNECTING_TO_HOST) {
205                     int code=in.getStatusCode();
206                     if (code==SC_CONNECTION_CLOSED) {
207                     } else if (code==SC_CLIENT_ERROR) {
208                         sendErrorMSG(400,"Your client sent a request that this proxy could not understand. (" + in.getErrorDescription() + ")");
209                     } else if (code==SC_HOST_NOT_FOUND)
210                         sendErrorMSG(504,"Host not found.<BR>jHTTPp2 was unable to resolve the hostname of this request. <BR>Perhaps the hostname was misspelled, the server is down or you have no connection to the internet.");
211                     else if (code==SC_INTERNAL_SERVER_ERROR) 
212                         sendErrorMSG(500,"Server Error! (" + in.getErrorDescription() + ")");
213                     else if (code==SC_NOT_SUPPORTED)
214                         sendErrorMSG(501,"Your client used a HTTP method that this proxy doesn't support: (" + in.getErrorDescription() + ")");
215                     else if (code==SC_URL_BLOCKED) {
216                         if (in.getErrorDescription()!=null && in.getErrorDescription().length()>0)
217                             sendErrorMSG(403,in.getErrorDescription());
218                         else
219                             sendErrorMSG(403,"The request for this URL was denied by the jHTTPp2 URL-Filter.");
220                     } else if (code==SC_HTTP_OPTIONS_THIS) {
221                         sendHeader(200); endHeader();
222                     } else if (code==SC_FILE_REQUEST)
223                         file_handler();
224                     else if (code==SC_CONFIG_RQ) 
225                         admin_handler(b);
226                     //case SC_HTTP_TRACE:
227                     else if (code==SC_MOVED_PERMANENTLY) {
228                         sendHeader(301);
229                         write(out,"Location: " + in.getErrorDescription() + "\r\n");
230                         endHeader();
231                         out.flush();
232                     }
233                     cnt=false;// return from main loop.
234                 } else { // also an error because we are not connected (or to the wrong host)
235                     // Creates a new connection to a remote host.
236                     if (!notConnected()) {
237                         HTTP_Socket.close();
238                     }
239                     numread=in.getHeaderLength(); // get the header length
240                     if (!server.use_proxy) {// sets up hostname and port
241                         remote_host=in.getRemoteHost();
242                         remote_port=in.remote_port;
243                     } else {
244                         remote_host=server.proxy;
245                         remote_port=server.proxy_port;
246                     }
247                     connect(remote_host,remote_port);
248                     if (!in.isTunnel()  || (in.isTunnel() && server.use_proxy))
249                         { // no SSL-Tunnel or SSL-Tunnel with another remote proxy: simply forward the request
250                             HTTP_out.write(b, 0, numread);
251                             HTTP_out.flush();
252                         }
253                     else
254                         { //  SSL-Tunnel with "CONNECT": creates a tunnel connection with the server
255                             sendLine(server.getHttpVersion() + " 200 Connection established");
256                             sendLine("Proxy-Agent",server.getServerIdentification());
257                             endHeader(); out.flush();
258                         }
259                     remote_in = new Jhttpp2Read(server,this, HTTP_in, out); // reads data from the remote server
260                     server.addBytesWritten(numread);
261                 }
262             }
263             if (cnt) {
264                 while(cnt) { // reads data from the client
265                     numread=in.read(b);
266                     if (numread==-2)
267                         return -1;
268                     if (numread!=-1) {
269                         HTTP_out.write(b, 0, numread);
270                         HTTP_out.flush();
271                         server.addBytesWritten(numread);
272                     } else cnt=false;
273                 } // end of inner loop
274                 cnt=true;
275             }
276         }// end of main loop
277         out.flush();
278         if (!notConnected() && remote_in != null)
279             remote_in.close(); // close Jhttpp2Read thread
280         return 0;
281     }
282     /** connects to the given host and port */
283     public void connect(InetAddress host,int port) {
284         HTTP_Socket = new Socket(host,port);
285         HTTP_in = new BufferedInputStream(HTTP_Socket.getInputStream());
286         HTTP_out = new BufferedOutputStream(HTTP_Socket.getOutputStream());
287     }
288   /** converts an String into a Byte-Array to write it with the OutputStream */
289   public void write(BufferedOutputStream o,String p) {
290     o.write(p.getBytes(),0,p.length());
291   }
292
293   /**
294    * Small webserver for local files in {app}/htdocs
295    * @since 0.4.04
296    */
297   public void file_handler() {
298         if (!server.www_server) {
299                 sendErrorMSG(500, "The jHTTPp2 built-in WWW server module is disabled.");
300                 return;
301         }
302     String filename=in.url;
303     if (filename.equals("/")) filename="index.html"; // convert / to index.html
304     else if (filename.startsWith("/")) filename=filename.substring(1);
305     if (filename.endsWith("/")) filename+="index.html"; // add index.html, if ending with /
306     File file = new File("htdocs/" + filename); // access only files in "htdocs"
307     if (true// !file.exists() || !file.canRead() // be sure that we can read the file
308                 || filename.indexOf("..")!=-1 // don't allow ".." !!!
309         //              || file.isDirectory() 
310 ) { // dont't read if it's a directory
311       sendErrorMSG(404,"The requested file /" + filename + " was not found or the path is invalid.");
312       return;
313     }
314     int pos = filename.lastIndexOf("."); // MIME type of the specified file
315     String content_type="text/plain"; // all unknown content types will be marked as text/plain
316     if (pos != -1) {
317         String extension = filename.substring(pos+1);
318         if (extension.equalsIgnoreCase("htm") || (extension.equalsIgnoreCase("html"))) content_type="text/html; charset=iso-8859-1";
319         else if (extension.equalsIgnoreCase("jpg") || (extension.equalsIgnoreCase("jpeg"))) content_type="image/jpeg";
320         else if (extension.equalsIgnoreCase("gif")) content_type = "image/gif";
321         else if (extension.equalsIgnoreCase("png")) content_type = "image/png";
322         else if (extension.equalsIgnoreCase("css")) content_type = "text/css";
323         else if (extension.equalsIgnoreCase("pdf")) content_type = "application/pdf";
324         else if (extension.equalsIgnoreCase("ps") || extension.equalsIgnoreCase("eps")) content_type = "application/postscript";
325         else if (extension.equalsIgnoreCase("xml")) content_type = "text/xml";
326         }
327     sendHeader(200,content_type, file.length() );
328     endHeader();
329     BufferedInputStream file_in = new BufferedInputStream(new FileInputStream(file));
330     byte[] buffer=new byte[4096];
331     int a=file_in.read(buffer);
332     while (a!=-1) { // read until EOF
333       out.write(buffer,0,a);
334       a = file_in.read(buffer);
335     }
336     out.flush();
337     file_in.close(); // finished!
338   }
339   /**
340    * @since 0.4.10b
341    */
342   public int getStatus()
343   {
344     return in.getStatusCode();
345   }
346   /**
347      * @since 0.4.20a
348      * admin webpage
349    */
350     public void admin_handler(byte[] b) {
351     }
352 }
353