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
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
14 File: Jhttpp2BufferedFilterStream.java
\r
15 @author Benjamin Kohl
\r
17 public class Jhttpp2ClientInputStream extends BufferedInputStream {
\r
18 private boolean filter;
\r
22 * The length of the header (with body, if one)
\r
24 private int header_length;
\r
26 * The length of the (optional) body of the actual request
\r
28 private int content_len;
\r
30 * This is set to true with requests with bodies, like "POST"
\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
41 public String method;
\r
42 public int remote_port;
\r
43 public int post_data_len;
\r
46 public int getHeaderLength() {
\r
47 return header_length;
\r
50 public InetAddress getRemoteHost() { return remote_host; }
\r
51 public String getRemoteHostName() { return remote_host_name; }
\r
53 private void init() {
\r
63 public Jhttpp2ClientInputStream(Jhttpp2Server server,Jhttpp2HTTPSession connection,InputStream a) {
\r
66 this.server = server;
\r
67 this.connection=connection;
\r
70 * Handler for the actual HTTP request
\r
71 * @exception IOException
\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
81 boolean start_line=true;
\r
82 buf = getLine(); // reads the first line
\r
85 while (lread>2&&cnt) {
\r
88 int methodID = server.getHttpMethod(buf);
\r
90 statuscode = connection.SC_NOT_SUPPORTED;
\r
95 InetAddress host = parseRequest(buf,methodID);
\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
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
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
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
127 }//end if match!=null)
\r
128 } //end if (server.block...
\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
143 else if (server.startsWith(buf,"Proxy-Connection:")) {
\r
144 if (!server.use_proxy) buf=null;
\r
146 buf="Proxy-Connection: Keep-Alive\r\n";
\r
147 lread=buf.length();
\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
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
162 } else if(server.startsWith(buf,"User-Agent")) // changes User-Agent
\r
164 buf="User-Agent: " + server.getUserAgent() + "\r\n";
\r
165 lread=buf.length();
\r
171 if (server.debug) server.writeLog(buf);
\r
172 header_length+=lread;
\r
176 rq+=buf; //adds last line (should be an empty line) to the header String
\r
177 header_length+=lread;
\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
184 for (int i=0;i<header_length;i++) a[i]=(byte)rq.charAt(i);
\r
186 if(body) {// read the body, if "Content-Length" given
\r
188 while(post_data_len < content_len) {
\r
189 a[header_length + post_data_len]=(byte)read(); // writes data into the array
\r
192 header_length += content_len; // add the body-length to the header-length
\r
195 if (statuscode==connection.SC_OK) {
\r
196 return header_length;
\r
203 * @exception IOException
\r
205 public String getLine()
\r
207 int l=0; String line=""; lread=0;
\r
209 while(l!='\n'&&cnt) {
\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
224 public InetAddress parseRequest(String a,int method_index) {
\r
226 server.writeLog(a);
\r
231 f = a.substring(8);
\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
241 statuscode = connection.SC_FILE_REQUEST;
\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
247 statuscode=connection.SC_INTERNAL_SERVER_ERROR;
\r
248 errordescription="This WWW proxy supports only the \"GET\" method while acting as webserver.";
\r
253 f = a.substring(pos+3); //removes "http://"
\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
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
265 url=f.substring(pos); // saves path without hostname
\r
266 f=f.substring(0,pos); // reduce string to the hostname
\r
268 else url="/"; // occurs with this request: "GET http://localhost HTTP/1.1"
\r
269 pos = f.indexOf(":"); // check for the portnumber
\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
276 i_port = Integer.parseInt(l_port);
\r
277 f = f.substring(0,pos);
\r
278 remote_port=i_port;
\r
281 remote_host_name = f;
\r
282 InetAddress address = null;
\r
283 if (server.log_access)
\r
284 server.logAccess(method + " " + getFullURL());
\r
286 address = InetAddress.getByName(f);
\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
295 statuscode = connection.SC_FILE_REQUEST;
\r
300 * @return boolean whether the actual connection was established with the CONNECT method.
\r
303 public boolean isTunnel() {
\r
307 * @return the full qualified URL of the actual request.
\r
310 public String getFullURL() {
\r
314 if (remote_port!=80)
\r
315 return "http" + sh + "://" + getRemoteHostName()
\r
316 + ":" + remote_port + url;
\r
318 return "http" + sh + "://" + getRemoteHostName()
\r
322 * @return status-code for the actual request
\r
325 public int getStatusCode()
\r
330 * @return the (optional) error-description for this request
\r
332 public String getErrorDescription()
\r
334 return errordescription;
\r