2002/07/19 05:45:00
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:49:21 +0000 (06:49 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:49:21 +0000 (06:49 +0000)
darcs-hash:20040130064921-2ba56-58682e67504818d6209982ff0afcd83cba7e7360.gz

CHANGES
src/org/xwt/HTTP.java

diff --git a/CHANGES b/CHANGES
index b42300f..a35d35f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
 18-Jul megacz Platform.java: don't try to getEnv() on Win w/ jdk<1.4
 
+18-Jul megacz HTTP.java: Basic Proxy-Authorization support
+
index a596af4..526f0fc 100644 (file)
@@ -56,27 +56,39 @@ public class HTTP {
 
     public HTTP(String url) throws MalformedURLException, IOException { this(url, false); }
     public HTTP(String url, boolean skipResolveCheck) throws MalformedURLException, IOException {
-        if (url.startsWith("https:")) { url = "http" + url.substring(5); ssl = true; }
-        if (!url.startsWith("http:")) throw new HTTPException("HTTP only supports http/https urls");
-        this.url = new URL(url);
+        if (url.startsWith("https:")) {
+            this.url = new URL("http" + url.substring(5));
+            ssl = true;
+        } else if (!url.startsWith("http:")) {
+            throw new HTTPException("HTTP only supports http/https urls");
+        } else {
+            this.url = new URL(url);
+        }
+        if (!skipResolveCheck) resolveAndCheckIfFirewalled(this.url.getHost());
         port = this.url.getPort();
         path = this.url.getFile();
         if (port == -1) port = ssl ? 443 : 80;
         host = this.url.getHost();
         if (Log.on) Log.log(this, "creating HTTP object for connection to " + host + ":" + port);
-        addHeader("Host", host);                                           // host header is always sent verbatim
-        if (!skipResolveCheck) resolveAndCheckIfFirewalled(host);   // might have to use the strict IP if behind a proxy
+        init();
+    }
 
+    /** this method initializes the HTTP object, resetting if needed (in case of a reconnect) */
+    public void init() throws IOException {
+        headers = "";
+        sock = null;
+        in = null;
+        out = null;
+        addHeader("Host", host);
         ProxyInfo pi = Platform.detectProxy();
         if (sock == null && pi != null && pi.proxyAutoConfigFunction != null) sock = attemptPAC(pi.proxyAutoConfigFunction);
         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);
         if (sock == null) sock = attemptDirect();
-        if (sock == null) throw new HTTPException("all socket creation attempts have failed");
+        if (sock == null) throw new HTTPException("unable to contact host " + host);
     }
 
-
     // Safeguarded DNS Resolver ///////////////////////////////////////////////////////////////////////////
 
     /**
@@ -276,13 +288,19 @@ public class HTTP {
         pw.print("User-Agent: XWT\r\n");
         pw.print("Content-length: " + contentLength + "\r\n");
         pw.print(headers);
+        if (ProxyAuthorization.authorization != null) pw.print("Proxy-Authorization: " + ProxyAuthorization.authorization + "\r\n");
         if (contentType != null) pw.print("Content-Type: " + contentType + "\r\n");
         pw.print("\r\n");
+
+        // FIXME: check for HTTP "ok, go ahead" here, in case we need proxy authorization this can happen if the xwar is
+        //        on the local disk and the first HTTP request is through an auth-requiring proxy
+
         pw.flush();
         return out;
     }
 
     public InputStream getInputStream() throws IOException {
+
         if (in != null) return in;
         if (out != null) {
             out.flush();
@@ -291,6 +309,8 @@ public class HTTP {
             pw.print("GET " + path + " HTTP/1.0\r\n");
             pw.print("User-Agent: XWT\r\n");
             pw.print(headers);
+            System.out.print(headers);
+            if (ProxyAuthorization.authorization != null) pw.print("Proxy-Authorization: " + ProxyAuthorization.authorization + "\r\n");
             pw.print("\r\n");
             pw.flush();
         }
@@ -317,7 +337,34 @@ public class HTTP {
         String s = headerReader.readLine();
         if (!s.startsWith("HTTP/")) throw new HTTPException("Expected reply to start with \"HTTP/\"");
         String reply = s.substring(s.indexOf(' ') + 1);
-        if (!reply.startsWith("2")) throw new HTTPException("HTTP Error: " + reply);
+
+        if (reply.startsWith("407")) {
+            if (Log.on) Log.log(this, "Proxy Auth Required: HTTP " + reply);
+            String realm = "";
+            String style = "Basic";
+
+            while((s = headerReader.readLine()) != null)
+                if (s.startsWith("Proxy-Authenticate:")) {
+                    s = s.substring(19);
+                    while(s.charAt(0) == ' ') s = s.substring(1);
+                    style = s.substring(0, s.indexOf(' '));
+                    s = s.substring(s.indexOf(' '));
+                    s = s.substring(s.indexOf("realm"));
+                    s = s.substring(s.indexOf('\"') + 1);
+                    s = s.substring(0, s.indexOf('\"'));
+                    realm = s;
+                }
+
+            ProxyAuthorization.getPassword(realm, style, sock.getInetAddress().getHostAddress(), ProxyAuthorization.authorization);
+
+            // reset and re-try
+            init();
+            return getInputStream();
+
+        } else if (!reply.startsWith("2")) {
+            throw new HTTPException("HTTP Error: " + reply);
+        }
+
         while((s = headerReader.readLine()) != null)
             if (s.length() > 15 && s.substring(0, 16).equalsIgnoreCase("content-length: "))
                 contentLength = Integer.parseInt(s.substring(16));
@@ -484,6 +531,7 @@ public class HTTP {
                 else if (name.equals("dnsDomainIs")) return dnsDomainIs;
                 else if (name.equals("localHostOrDomainIs")) return localHostOrDomainIs;
                 else if (name.equals("isResolvable")) return isResolvable;
+                else if (name.equals("isInNet")) return isInNet;
                 else if (name.equals("dnsResolve")) return dnsResolve;
                 else if (name.equals("myIpAddress")) return myIpAddress;
                 else if (name.equals("dnsDomainLevels")) return dnsDomainLevels;
@@ -586,7 +634,6 @@ public class HTTP {
                     }
                 };
         
-            // FIXME: test this!
             private static boolean match(String[] arr, String s, int index) {
                 if (index == arr.length) return true;
                 for(int i=0; i<s.length(); i++) {
@@ -650,4 +697,34 @@ public class HTTP {
 
     }
 
+    // ProxyAuthorization ///////////////////////////////////////////////////////////////////////////////////
+
+    public static class ProxyAuthorization {
+
+        static public String authorization = null;
+        static public Semaphore waitingForUser = new Semaphore();
+
+        // FIXME: Digest and NTLM
+        public static synchronized void getPassword(final String realm, final String style, final String proxyIP, String oldAuth) {
+
+            // this handles cases where multiple threads hit the proxy auth at the same time -- all but one will block on the
+            // synchronized keyword. If 'authorization' changed while the thread was blocked, it means that the user entered
+            // a password, so we should reattempt authorization.
+
+            if (authorization != oldAuth) return;
+            if (Log.on) Log.log(ProxyAuthorization.class, "displaying proxy authorization dialog");
+            MessageQueue.add(new Message() {
+                    public void perform() {
+                        Box b = new Box("org.xwt.builtin.proxy_authorization", null);
+                        b.put("realm", realm);
+                        b.put("proxyIP", proxyIP);
+                    }
+                });
+
+            waitingForUser.block();
+            if (Log.on) Log.log(ProxyAuthorization.class, "got proxy authorization info; re-attempting connection");
+            
+        }
+    }
+
 }