X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2FHTTP.java;h=8f2652830ee2a7204e8a21b2caa921870bef69c1;hb=0373b49c4640afde70d852f2531e46b19260554f;hp=d4d2249eed02b36d783b08d8f20c2a1b7b4211eb;hpb=f3b7bcb8cecf6f0aa3b7283eb987466d72e48af5;p=org.ibex.core.git diff --git a/src/org/xwt/HTTP.java b/src/org/xwt/HTTP.java index d4d2249..8f26528 100644 --- a/src/org/xwt/HTTP.java +++ b/src/org/xwt/HTTP.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.net.*; @@ -60,6 +60,9 @@ public class HTTP { /** true iff we are allowed to skip the resolve check (only allowed when we're downloading the PAC script) */ boolean skipResolveCheck = false; + /** true iff we're using a proxy */ + boolean proxied = false; + // Public Methods //////////////////////////////////////////////////////////////////////////////////////// @@ -70,16 +73,16 @@ public class HTTP { } /** Performs an HTTP GET request */ - public HTTPInputStream GET() throws IOException { return makeRequest(null, null); } + public InputStream GET() throws IOException { return makeRequest(null, null); } /** Performs an HTTP POST request; content is appended to the headers (so it should include a blank line to delimit the beginning of the body) */ - public HTTPInputStream POST(String contentType, String content) throws IOException { return makeRequest(contentType, content); } + public InputStream POST(String contentType, String content) throws IOException { return makeRequest(contentType, content); } /** * This method isn't synchronized; however, only one thread can be in the inner synchronized block at a time, and the rest of * the method is protected by in-order one-at-a-time semaphore lock-steps */ - private HTTPInputStream makeRequest(String contentType, String content) throws IOException { + private InputStream makeRequest(String contentType, String content) throws IOException { // Step 1: send the request and establish a semaphore to stop any requests that pipeline after us Semaphore blockOn = null; @@ -132,7 +135,8 @@ public class HTTP { if (h.get("HTTP").equals("1.0") && h.get("content-length") == null) throw new HTTPException("XWT does not support HTTP/1.0 servers which fail to return the Content-Length header"); int cl = h.get("content-length") == null ? -1 : Integer.parseInt(h.get("content-length").toString()); - HTTPInputStream ret = new HTTPInputStream(in, cl, releaseMe); + InputStream ret = new HTTPInputStream(in, cl, releaseMe); + if ("gzip".equals(h.get("content-encoding"))) ret = new java.util.zip.GZIPInputStream(ret); doRelease = false; return ret; @@ -150,14 +154,11 @@ public class HTTP { // Safeguarded DNS Resolver /////////////////////////////////////////////////////////////////////////// /** - * resolves the hostname and returns it as a string in the form "x.y.z.w", except for the special case "xmlrpc.xwt.org". + * resolves the hostname and returns it as a string in the form "x.y.z.w" * @throws HTTPException if the host falls within a firewalled netblock */ private void resolveAndCheckIfFirewalled(String host) throws HTTPException { - // special case - if (host.equals("xmlrpc.xwt.org")) return; - // cached if (resolvedHosts.get(host) != null) return; @@ -175,12 +176,11 @@ public class HTTP { return; } catch (UnknownHostException uhe) { } - // resolve using xmlrpc.xwt.org if (Platform.detectProxy() == null) throw new HTTPException("could not resolve hostname \"" + host + "\" and no proxy configured"); if (Log.on) Log.log(this, " could not resolve host " + host + "; using xmlrpc.xwt.org to ensure security"); try { - Array args = new Array(); - args.addElement(host); + JS.Array args = new JS.Array(); + args.addElement(host); Object ret = new XMLRPC("http://xmlrpc.xwt.org/RPC2/", "dns.resolve").call(args); if (ret == null || !(ret instanceof String)) throw new Exception(" xmlrpc.xwt.org returned non-String: " + ret); resolvedHosts.put(host, ret); @@ -285,9 +285,9 @@ public class HTTP { if (Log.verbose) Log.log(this, "evaluating PAC script"); String pac = null; try { - org.xwt.js.Array args = new org.xwt.js.Array(); - args.addElement(url.toString()); - args.addElement(url.getHost()); + org.xwt.js.JS.Array args = new org.xwt.js.JS.Array(); + args.addElement(url.toString()); + args.addElement(url.getHost()); Object obj = pacFunc.call(args); if (Log.verbose) Log.log(this, " PAC script returned \"" + obj + "\""); pac = obj.toString(); @@ -323,6 +323,10 @@ public class HTTP { // Everything Else //////////////////////////////////////////////////////////////////////////// private synchronized void connect() throws IOException { + if (originalUrl.equals("stdio:")) { + in = new BufferedInputStream(System.in); + return; + } if (sock != null) { if (in == null) in = new BufferedInputStream(sock.getInputStream()); return; @@ -358,6 +362,7 @@ public class HTTP { if (sock == null && pi != null && ssl && pi.httpsProxyHost != null) sock = attemptHttpProxy(pi.httpsProxyHost, pi.httpsProxyPort); if (sock == null && pi != null && pi.httpProxyHost != null) sock = attemptHttpProxy(pi.httpProxyHost, pi.httpProxyPort); if (sock == null && pi != null && pi.socksProxyHost != null) sock = attemptSocksProxy(pi.socksProxyHost, pi.socksProxyPort); + proxied = sock != null; if (sock == null) sock = attemptDirect(); if (sock == null) throw new HTTPException("unable to contact host " + host); if (in == null) in = new BufferedInputStream(sock.getInputStream()); @@ -365,12 +370,12 @@ public class HTTP { public void sendRequest(String contentType, String content) throws IOException { - PrintWriter pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream())); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(originalUrl.equals("stdio:") ? System.out : sock.getOutputStream())); if (content != null) { pw.print("POST " + path + " HTTP/1.1\r\n"); - int contentLength = content.substring(0, 2).equals("\r\n") ? - content.length() - 2 : - (content.length() - content.indexOf("\r\n\r\n") - 4); + int contentLength = content.substring(0, 2).equals("\r\n") ? + content.length() - 2 : + (content.length() - content.indexOf("\r\n\r\n") - 4); pw.print("Content-Length: " + contentLength + "\r\n"); if (contentType != null) pw.print("Content-Type: " + contentType + "\r\n"); } else { @@ -378,7 +383,9 @@ public class HTTP { } pw.print("User-Agent: XWT\r\n"); + pw.print("Accept-encoding: gzip\r\n"); pw.print("Host: " + (host + (port == 80 ? "" : (":" + port))) + "\r\n"); + if (proxied) pw.print("X-RequestOrigin: " + Main.originHost + "\r\n"); if (Proxy.Authorization.authorization != null) pw.print("Proxy-Authorization: " + Proxy.Authorization.authorization2 + "\r\n"); if (authCache.get(originalUrl) != null) pw.print("Authorization: " + authCache.get(originalUrl) + "\r\n"); @@ -477,26 +484,26 @@ public class HTTP { private int contentLength = 0; public int getContentLength() { return contentLength; } - HTTPInputStream(InputStream in, int length, Semaphore releaseMe) { + HTTPInputStream(InputStream in, int length, Semaphore releaseMe) throws IOException { super(in); this.releaseMe = releaseMe; this.contentLength = length; this.length = length == -1 ? 0 : length; } - public boolean markSupported() { return false; } - public int read(byte[] b) throws IOException { return read(b, 0, b.length); } - public long skip(long n) throws IOException { return read(null, -1, (int)n); } - public int available() throws IOException { - if (contentLength == -1) return java.lang.Math.min(super.available(), length); - return super.available(); - } + public boolean markSupported() { return false; } + public int read(byte[] b) throws IOException { return read(b, 0, b.length); } + public long skip(long n) throws IOException { return read(null, -1, (int)n); } + public int available() throws IOException { + if (contentLength == -1) return java.lang.Math.min(super.available(), length); + return super.available(); + } - public int read() throws IOException { - byte[] b = new byte[1]; - int ret = read(b, 0, 1); - return ret == -1 ? -1 : b[0] & 0xff; - } + public int read() throws IOException { + byte[] b = new byte[1]; + int ret = read(b, 0, 1); + return ret == -1 ? -1 : b[0] & 0xff; + } private void readChunk() throws IOException { if (chunkedDone) return; @@ -507,7 +514,7 @@ public class HTTP { int i = super.read(); if (i == -1) throw new HTTPException("encountered end of stream while reading chunk length"); - // FIXME: handle chunking extensions + // FEATURE: handle chunking extensions if (i == '\r') { super.read(); // LF break; @@ -515,7 +522,7 @@ public class HTTP { chunkLen += (char)i; } } - length = Integer.parseInt(chunkLen, 16); + length = Integer.parseInt(chunkLen.trim(), 16); if (length == 0) chunkedDone = true; } @@ -523,17 +530,17 @@ public class HTTP { boolean good = false; try { if (length == 0 && contentLength == -1) { - readChunk(); - if (chunkedDone) { good = true; return -1; } - } else { - if (length == 0) { good = true; return -1; } - } + readChunk(); + if (chunkedDone) { good = true; return -1; } + } else { + if (length == 0) { good = true; return -1; } + } if (len > length) len = length; int ret = b == null ? (int)super.skip(len) : super.read(b, off, len); - if (ret >= 0) { - length -= ret; - good = true; - } + if (ret >= 0) { + length -= ret; + good = true; + } return ret; } finally { if (!good) invalid = true; @@ -633,4 +640,339 @@ public class HTTP { return ret; } + + // Proxy /////////////////////////////////////////////////////////// + + /** encapsulates most of the proxy logic; some is shared in HTTP.java */ + public static class Proxy { + + public Proxy() { } + + /** the HTTP Proxy host to use */ + public String httpProxyHost = null; + + /** the HTTP Proxy port to use */ + public int httpProxyPort = -1; + + /** if a seperate proxy should be used for HTTPS, this is the hostname; otherwise, httpProxyHost is used */ + public String httpsProxyHost = null; + + /** if a seperate proxy should be used for HTTPS, this is the port */ + public int httpsProxyPort = -1; + + /** the SOCKS Proxy Host to use */ + public String socksProxyHost = null; + + /** the SOCKS Proxy Port to use */ + public int socksProxyPort = -1; + + /** hosts to be excluded from proxy use; wildcards permitted */ + public String[] excluded = null; + + /** the PAC script */ + public JS.Callable proxyAutoConfigFunction = null; + + public static Proxy detectProxyViaManual() { + Proxy ret = new Proxy(); + + ret.httpProxyHost = Platform.getEnv("http_proxy"); + if (ret.httpProxyHost != null) { + if (ret.httpProxyHost.startsWith("http://")) ret.httpProxyHost = ret.httpProxyHost.substring(7); + if (ret.httpProxyHost.endsWith("/")) ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.length() - 1); + if (ret.httpProxyHost.indexOf(':') != -1) { + ret.httpProxyPort = Integer.parseInt(ret.httpProxyHost.substring(ret.httpProxyHost.indexOf(':') + 1)); + ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.indexOf(':')); + } else { + ret.httpProxyPort = 80; + } + } + + ret.httpsProxyHost = Platform.getEnv("https_proxy"); + if (ret.httpsProxyHost != null) { + if (ret.httpsProxyHost.startsWith("https://")) ret.httpsProxyHost = ret.httpsProxyHost.substring(7); + if (ret.httpsProxyHost.endsWith("/")) ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.length() - 1); + if (ret.httpsProxyHost.indexOf(':') != -1) { + ret.httpsProxyPort = Integer.parseInt(ret.httpsProxyHost.substring(ret.httpsProxyHost.indexOf(':') + 1)); + ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.indexOf(':')); + } else { + ret.httpsProxyPort = 80; + } + } + + ret.socksProxyHost = Platform.getEnv("socks_proxy"); + if (ret.socksProxyHost != null) { + if (ret.socksProxyHost.startsWith("socks://")) ret.socksProxyHost = ret.socksProxyHost.substring(7); + if (ret.socksProxyHost.endsWith("/")) ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.length() - 1); + if (ret.socksProxyHost.indexOf(':') != -1) { + ret.socksProxyPort = Integer.parseInt(ret.socksProxyHost.substring(ret.socksProxyHost.indexOf(':') + 1)); + ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.indexOf(':')); + } else { + ret.socksProxyPort = 80; + } + } + + String noproxy = Platform.getEnv("no_proxy"); + if (noproxy != null) { + StringTokenizer st = new StringTokenizer(noproxy, ","); + ret.excluded = new String[st.countTokens()]; + for(int i=0; st.hasMoreTokens(); i++) ret.excluded[i] = st.nextToken(); + } + + if (ret.httpProxyHost == null && ret.socksProxyHost == null) return null; + return ret; + } + + public static JS.Scope proxyAutoConfigRootScope = new ProxyAutoConfigRootScope(); + public static JS.Callable getProxyAutoConfigFunction(String url) { + try { + BufferedReader br = new BufferedReader(new InputStreamReader(new HTTP(url, true).GET())); + String s = null; + String script = ""; + while((s = br.readLine()) != null) script += s + "\n"; + if (Log.on) Log.log(Proxy.class, "successfully retrieved WPAD PAC:"); + if (Log.on) Log.log(Proxy.class, script); + + // MS CARP hack + Vector carpHosts = new Vector(); + for(int i=0; i= arr.length) return true; + for(int i=0; i= d1 && day <= d2) || + (d1 > d2 && (day >= d1 || day <= d2))) ? + Boolean.TRUE : Boolean.FALSE; + } + }; + + private static final JS.Callable dateRange = new JS.Callable() { + public Object call(org.xwt.js.JS.Array args) throws JS.Exn { + throw new JS.Exn("XWT does not support dateRange() in PAC scripts"); + } + }; + + private static final JS.Callable timeRange = new JS.Callable() { + public Object call(org.xwt.js.JS.Array args) throws JS.Exn { + throw new JS.Exn("XWT does not support timeRange() in PAC scripts"); + } + }; + + } + + } + }