*** empty log message ***
[IRC.git] / Robust / src / Benchmarks / Jhttpp2 / Java / Jhttpp2ClientInputStream.java
1 /* Written and copyright 2001-2003 Benjamin Kohl.\r
2  * Distributed under the GNU General Public License; see the README file.\r
3  * This code comes with NO WARRANTY.\r
4  */\r
5 \r
6 import java.io.IOException;\r
7 import java.io.InputStream;\r
8 import java.io.BufferedInputStream;\r
9 import java.net.InetAddress;\r
10 import java.net.UnknownHostException;\r
11 \r
12 \r
13 /**\r
14         File: Jhttpp2BufferedFilterStream.java\r
15         @author Benjamin Kohl\r
16 */\r
17 public class Jhttpp2ClientInputStream extends BufferedInputStream {\r
18         private boolean filter;\r
19         private String buf;\r
20         private int lread;\r
21         /**\r
22          * The length of the header (with body, if one)\r
23          */\r
24         private int header_length;\r
25         /**\r
26          * The length of the (optional) body of the actual request\r
27          */\r
28         private int content_len;\r
29         /**\r
30          * This is set to true with requests with bodies, like "POST"\r
31          */\r
32         private boolean body;\r
33         private static Jhttpp2Server server;\r
34         private Jhttpp2HTTPSession connection;\r
35         private InetAddress remote_host;\r
36         private String remote_host_name;\r
37         private String errordescription;\r
38         private int statuscode;\r
39 \r
40         public String url;\r
41         public String method;\r
42         public int remote_port;\r
43         public int post_data_len;\r
44     public boolean ssl;\r
45 \r
46         public int getHeaderLength() {\r
47           return header_length;\r
48         }\r
49 \r
50         public InetAddress getRemoteHost() { return remote_host; }\r
51         public String getRemoteHostName() { return remote_host_name; }\r
52 \r
53     private void init() {\r
54         lread = 0;\r
55         header_length = 0;\r
56         content_len = 0;\r
57         ssl = false;\r
58         body = false;\r
59         remote_port = 0;\r
60         post_data_len = 0;\r
61     }\r
62 \r
63     public Jhttpp2ClientInputStream(Jhttpp2Server server,Jhttpp2HTTPSession connection,InputStream a) {\r
64         super(a);\r
65         init();\r
66         this.server = server;\r
67         this.connection=connection;\r
68     }\r
69         /**\r
70          * Handler for the actual HTTP request\r
71      * @exception IOException\r
72          */\r
73     public int read(byte[] a) {\r
74         statuscode = connection.SC_OK;\r
75         if (ssl) return super.read(a);\r
76         boolean cookies_enabled=server.enableCookiesByDefault();\r
77         String rq="";\r
78         header_length=0;\r
79         post_data_len = 0;\r
80         content_len = 0;\r
81         boolean start_line=true;\r
82         buf = getLine(); // reads the first line\r
83         \r
84         boolean cnt=true;\r
85         while (lread>2&&cnt) {\r
86             if (start_line) {\r
87                 start_line = false;\r
88                 int methodID = server.getHttpMethod(buf);\r
89                 if (methodID==-1) {\r
90                     statuscode = connection.SC_NOT_SUPPORTED;\r
91                 } else {\r
92                     if (methodID==2) {\r
93                         ssl = true;\r
94                     }\r
95                     InetAddress host = parseRequest(buf,methodID);\r
96                     \r
97                     if (statuscode == connection.SC_OK) {\r
98                         if (!server.use_proxy && !ssl) {\r
99                             /* creates a new request without the hostname */\r
100                             buf = method + " " + url + " " + server.getHttpVersion() + "\r\n";\r
101                             lread = buf.length();\r
102                         }\r
103                         if ((server.use_proxy && connection.notConnected()) || !host.equals(remote_host)) {\r
104                             if (server.debug) server.writeLog("read_f: STATE_CONNECT_TO_NEW_HOST");\r
105                             statuscode = connection.SC_CONNECTING_TO_HOST;\r
106                             remote_host = host;\r
107                         }\r
108                         /* -------------------------\r
109                          * url blocking (only "GET" method)\r
110                          * -------------------------*/\r
111                         if (server.block_urls && methodID==0 && statuscode!=connection.SC_FILE_REQUEST) {\r
112                             if (server.debug) System.printString("Searching match...");\r
113                             Jhttpp2URLMatch match=server.findMatch(this.remote_host_name+url);\r
114                             if (match!=null){\r
115                                 if (server.debug) System.printString("Match found!");\r
116                                 cookies_enabled=match.getCookiesEnabled();\r
117                                 if (match.getActionIndex()==-1) cnt=false; else {\r
118                                     OnURLAction action=(OnURLAction)server.getURLActions().elementAt(match.getActionIndex());\r
119                                     if (action.onAccesssDeny()) {\r
120                                         statuscode=connection.SC_URL_BLOCKED;\r
121                                         if (action.onAccessDenyWithCustomText()) errordescription=action.getCustomErrorText();\r
122                                     } else if (action.onAccessRedirect()) {\r
123                                         statuscode=connection.SC_MOVED_PERMANENTLY;\r
124                                         errordescription=action.newLocation();\r
125                                     }\r
126                                 }\r
127                             }//end if match!=null)\r
128                         } //end if (server.block...\r
129                     }\r
130                 }\r
131             } else { // end if(startline)\r
132                 /*-----------------------------------------------\r
133                  * Content-Length parsing\r
134                  *-----------------------------------------------*/\r
135                 if(server.startsWith(buf.toUpperCase(),"CONTENT-LENGTH")) {\r
136                     String clen=buf.substring(16);\r
137                     if (clen.indexOf("\r")!=-1) clen=clen.substring(0,clen.indexOf("\r"));\r
138                     else if(clen.indexOf("\n")!=-1) clen=clen.substring(0,clen.indexOf("\n"));\r
139                     content_len=Integer.parseInt(clen);\r
140                     if (server.debug) server.writeLog("read_f: content_len: " + content_len);\r
141                     if (!ssl) body=true; // Note: in HTTP/1.1 any method can have a body, not only "POST"\r
142                 }\r
143                 else if (server.startsWith(buf,"Proxy-Connection:")) {\r
144                     if (!server.use_proxy) buf=null;\r
145                     else {\r
146                         buf="Proxy-Connection: Keep-Alive\r\n";\r
147                         lread=buf.length();\r
148                     }\r
149                 }\r
150                 /*-----------------------------------------------\r
151                  * cookie crunch section\r
152                  *-----------------------------------------------*/\r
153                 else if(server.startsWith(buf,"Cookie:")) {\r
154                     if (!cookies_enabled) buf=null;\r
155                 }\r
156                 /*------------------------------------------------\r
157                  * Http-Header filtering section\r
158                  *------------------------------------------------*/\r
159                 else if (server.filter_http) {\r
160                     if(server.startsWith(buf,"Referer:")) {// removes "Referer"\r
161                         buf=null;\r
162                     } else if(server.startsWith(buf,"User-Agent")) // changes User-Agent\r
163                         {\r
164                             buf="User-Agent: " + server.getUserAgent() + "\r\n";\r
165                             lread=buf.length();\r
166                         }\r
167                 }\r
168             }\r
169             if (buf!=null) {\r
170                 rq+=buf;\r
171                 if (server.debug) server.writeLog(buf);\r
172                 header_length+=lread;\r
173             }\r
174             buf=getLine();\r
175         }\r
176         rq+=buf; //adds last line (should be an empty line) to the header String\r
177         header_length+=lread;\r
178         \r
179         if (header_length==0) {\r
180             if (server.debug) server.writeLog("header_length=0, setting status to SC_CONNECTION_CLOSED (buggy request)");\r
181             statuscode=connection.SC_CONNECTION_CLOSED;\r
182         }\r
183         \r
184         for (int i=0;i<header_length;i++) a[i]=(byte)rq.charAt(i);\r
185         \r
186         if(body) {// read the body, if "Content-Length" given\r
187             post_data_len = 0;\r
188             while(post_data_len < content_len)  {\r
189                 a[header_length + post_data_len]=(byte)read(); // writes data into the array\r
190                 post_data_len ++;\r
191             }\r
192             header_length += content_len; // add the body-length to the header-length\r
193             body = false;\r
194         }\r
195         if (statuscode==connection.SC_OK) {\r
196             return header_length;\r
197         } else {\r
198             return -1;\r
199         }\r
200     }\r
201     /**\r
202      * reads a line\r
203      * @exception IOException\r
204      */\r
205     public String getLine()\r
206     {\r
207         int l=0; String line=""; lread=0;\r
208         boolean cnt=true;\r
209         while(l!='\n'&&cnt) {\r
210             l=read();\r
211             if (l!=-1) {\r
212                 line+=(char)l;\r
213                 lread++;\r
214             } else\r
215                 cnt=false;\r
216         }\r
217         return line;\r
218     }\r
219         /**\r
220         * Parser for the first (!) line from the HTTP request<BR>\r
221         * Sets up the URL, method and remote hostname.\r
222         * @return an InetAddress for the hostname, null on errors with a statuscode!=SC_OK\r
223         */\r
224         public InetAddress parseRequest(String a,int method_index)  {\r
225             if (server.debug) \r
226                 server.writeLog(a);\r
227             String f; \r
228             int pos; \r
229             url="";\r
230             if (ssl) {\r
231                 f = a.substring(8);\r
232             } else {\r
233                 method = a.substring(0,a.indexOf(" ")); //first word in the line\r
234                 pos = a.indexOf(":"); // locate first :\r
235                 if (pos == -1) { // occours with "GET / HTTP/1.1"\r
236                     url = a.substring(a.indexOf(" ")+1,a.lastIndexOf(" "));\r
237                     if (method_index == 0) { // method_index==0 --> GET\r
238                         if (url.indexOf(server.WEB_CONFIG_FILE) != -1) {\r
239                             statuscode = connection.SC_CONFIG_RQ;\r
240                         } else { \r
241                             statuscode = connection.SC_FILE_REQUEST;\r
242                         }\r
243                     } else {\r
244                         if (method_index == 1 && url.indexOf(server.WEB_CONFIG_FILE) != -1) { // allow "POST" for admin log in\r
245                             statuscode = connection.SC_CONFIG_RQ;\r
246                         } else {\r
247                             statuscode=connection.SC_INTERNAL_SERVER_ERROR;\r
248                             errordescription="This WWW proxy supports only the \"GET\" method while acting as webserver.";\r
249                         }\r
250                     }\r
251                     return null;\r
252                 }\r
253                 f = a.substring(pos+3); //removes "http://"\r
254             }\r
255             pos=f.indexOf(" "); // locate space, should be the space before "HTTP/1.1"\r
256             if (pos==-1) { // buggy request\r
257                 statuscode=connection.SC_CLIENT_ERROR;\r
258                 errordescription="Your browser sent an invalid request: \""+ a + "\"";\r
259                 return null;\r
260             }\r
261             f = f.substring(0,pos); //removes all after space\r
262             // if the url contains a space... it's not our mistake...(url's must never contain a space character)\r
263             pos=f.indexOf("/"); // locate the first slash\r
264             if (pos!=-1) {\r
265                 url=f.substring(pos); // saves path without hostname\r
266                 f=f.substring(0,pos); // reduce string to the hostname\r
267             }\r
268             else url="/"; // occurs with this request: "GET http://localhost HTTP/1.1"\r
269             pos = f.indexOf(":"); // check for the portnumber\r
270             if (pos!=-1) {\r
271                 String l_port =f.substring(pos+1);\r
272                 if (l_port.indexOf(" ")!=-1)\r
273                     l_port=l_port.substring(0,l_port.indexOf(" "));\r
274                 int i_port=80;\r
275                 //BCD\r
276                 i_port = Integer.parseInt(l_port);\r
277                 f = f.substring(0,pos);\r
278                 remote_port=i_port;\r
279             } else\r
280                 remote_port = 80;\r
281             remote_host_name = f;\r
282             InetAddress address = null;\r
283             if (server.log_access) \r
284                 server.logAccess(method + " " + getFullURL());\r
285 \r
286             address = InetAddress.getByName(f);\r
287 \r
288             if (remote_port == server.port && address.equals(InetAddress.getLocalHost())) {\r
289                 if (url.indexOf(server.WEB_CONFIG_FILE) != -1 && (method_index == 0 || method_index == 1))\r
290                     statuscode = connection.SC_CONFIG_RQ;\r
291                 else if (method_index > 0 ) {\r
292                     statuscode=connection.SC_INTERNAL_SERVER_ERROR;\r
293                     errordescription="This WWW proxy supports only the \"GET\" method while acting as webserver.";\r
294                 } else\r
295                     statuscode = connection.SC_FILE_REQUEST;\r
296             }\r
297             return address;\r
298         }\r
299         /**\r
300         * @return boolean whether the actual connection was established with the CONNECT method.\r
301         * @since 0.2.21\r
302         */\r
303         public boolean isTunnel() {\r
304           return ssl;\r
305         }\r
306     /**\r
307      * @return the full qualified URL of the actual request.\r
308      * @since 0.4.0\r
309      */\r
310     public String getFullURL() {\r
311         String sh="";\r
312         if (ssl)\r
313             sh="s";\r
314         if (remote_port!=80)\r
315                 return "http" + sh + "://" + getRemoteHostName()\r
316                 + ":" + remote_port + url;\r
317         else\r
318                 return "http" + sh + "://" + getRemoteHostName()\r
319                     + url;\r
320     }\r
321     /**\r
322      * @return status-code for the actual request\r
323      * @since 0.3.5\r
324      */\r
325         public int getStatusCode()\r
326         {\r
327                 return statuscode;\r
328         }\r
329         /**\r
330         * @return the (optional) error-description for this request\r
331         */\r
332         public String getErrorDescription()\r
333         {\r
334                 return errordescription;\r
335         }\r
336 }\r