8017779: java/net/Authenticator/B4769350.java fails
authorchegar
Tue, 22 Oct 2013 14:00:16 +0100
changeset 21320 0a56bf0c2390
parent 21319 9bfb258734ce
child 21323 d9433f0957ae
8017779: java/net/Authenticator/B4769350.java fails Reviewed-by: chegar Contributed-by: Tristan Yan <tristan.yan@oracle.com>, Kurchi Subhra Hazra <kurchisubhra@gmail.com>
jdk/test/java/net/Authenticator/B4769350.java
--- a/jdk/test/java/net/Authenticator/B4769350.java	Tue Oct 15 18:41:23 2013 +0400
+++ b/jdk/test/java/net/Authenticator/B4769350.java	Tue Oct 22 14:00:16 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,7 @@
 
 /**
  * @test
- * @bug 4769350
- * @library ../../../sun/net/www/httptest/
- * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction AbstractCallback
+ * @bug 4769350 8017779
  * @run main/othervm B4769350 server
  * @run main/othervm B4769350 proxy
  * @summary proxy authentication username and password caching only works in serial case
@@ -34,8 +32,17 @@
  * tests may already have invoked the HTTP handler.
  */
 
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
 import java.io.*;
 import java.net.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 public class B4769350 {
 
@@ -43,13 +50,12 @@
     static boolean error = false;
 
     static void read (InputStream is) throws IOException {
-        int c;
-        while ((c=is.read()) != -1) {
+        while (is.read() != -1) {
             //System.out.write (c);
         }
     }
 
-    static class Client extends Thread {
+     static class Client extends Thread {
         String authority, path;
         boolean allowerror;
 
@@ -64,8 +70,8 @@
             try {
                 URI u = new URI ("http", authority, path, null, null);
                 URL url = u.toURL();
-                URLConnection urlc = url.openConnection ();
-                InputStream is = urlc.getInputStream ();
+                URLConnection urlc = url.openConnection();
+                InputStream is = urlc.getInputStream();
                 read (is);
                 is.close();
             } catch (URISyntaxException  e) {
@@ -73,7 +79,8 @@
                 error = true;
             } catch (IOException e) {
                 if (!allowerror) {
-                    System.out.println (Thread.currentThread().getName() + " " + e);
+                    System.out.println (Thread.currentThread().getName()
+                            + " " + e);
                     e.printStackTrace();
                     error = true;
                 }
@@ -81,55 +88,58 @@
         }
     }
 
-    static class CallBack extends AbstractCallback {
-
-        void errorReply (HttpTransaction req, String reply) throws IOException {
-            req.addResponseHeader ("Connection", "close");
-            req.addResponseHeader ("WWW-Authenticate", reply);
-            req.sendResponse (401, "Unauthorized");
-            req.orderlyClose();
-        }
+    class Server implements AutoCloseable {
+        HttpServer server;
+        Executor executor;
+        CyclicBarrier t1Cond1;
+        CyclicBarrier t1Cond2;
 
-        void proxyReply (HttpTransaction req, String reply) throws IOException {
-            req.addResponseHeader ("Proxy-Authenticate", reply);
-            req.sendResponse (407, "Proxy Authentication Required");
-        }
-
-        void okReply (HttpTransaction req) throws IOException {
-            req.addResponseHeader ("Connection", "close");
-            req.setResponseEntityBody ("Hello .");
-            req.sendResponse (200, "Ok");
-            req.orderlyClose();
+        public String getAddress() {
+            return server.getAddress().getHostName();
         }
 
-        public void request (HttpTransaction req, int count) {
+        public void startServer() {
+            InetSocketAddress addr = new InetSocketAddress(0);
+
             try {
-                URI uri = req.getRequestURI();
-                String path = uri.getPath();
-                if (path.endsWith ("/t1a")) {
-                    doT1a (req, count);
-                } else if (path.endsWith ("/t1b")) {
-                    doT1b (req, count);
-                } else if (path.endsWith ("/t1c")) {
-                    doT1c (req, count);
-                } else if (path.endsWith ("/t1d")) {
-                    doT1d (req, count);
-                } else if (path.endsWith ("/t2a")) {
-                    doT2a (req, count);
-                } else if (path.endsWith ("/t2b")) {
-                    doT2b (req, count);
-                } else if (path.endsWith ("/t3a")) {
-                    doT3a (req, count);
-                } else if (path.endsWith ("/t3b")) {
-                    doT3bc (req, count);
-                } else if (path.endsWith ("/t3c")) {
-                    doT3bc (req, count);
-                } else {
-                   System.out.println ("unexpected request URI");
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
+                server = HttpServer.create(addr, 0);
+            } catch (IOException ioe) {
+                throw new RuntimeException("Server could not be created");
             }
+            executor = Executors.newFixedThreadPool(10);
+            server.setExecutor(executor);
+            server.createContext("/test/realm1/t1a",
+                    new AuthenticationHandlerT1a() );
+            server.createContext("/test/realm2/t1b",
+                    new AuthenticationHandlerT1b());
+            server.createContext("/test/realm1/t1c",
+                    new AuthenticationHandlerT1c());
+            server.createContext("/test/realm2/t1d",
+                    new AuthenticationHandlerT1d());
+            server.createContext("/test/realm3/t2a",
+                    new AuthenticationHandlerT2a());
+            server.createContext("/test/realm3/t2b",
+                    new AuthenticationHandlerT2b());
+            server.createContext("/test/realm4/t3a",
+                    new AuthenticationHandlerT3a());
+            server.createContext("/test/realm4/t3b",
+                    new AuthenticationHandlerT3bc());
+            server.createContext("/test/realm4/t3c",
+                    new AuthenticationHandlerT3bc());
+            t1Cond1 = new CyclicBarrier(2);
+            t1Cond2 = new CyclicBarrier(2);
+            server.start();
+        }
+
+        public int getPort() {
+            return server.getAddress().getPort();
+        }
+
+        public void close() {
+            if (executor != null)
+                ((ExecutorService)executor).shutdownNow();
+            if (server != null)
+                server.stop(0);
         }
 
         /* T1 tests the client by sending 4 requests to 2 different realms
@@ -138,90 +148,158 @@
          * the second requests should be executed without calling the authenticator.
          * The test succeeds if the authenticator was only called twice.
          */
-        void doT1a (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                errorReply (req, "Basic realm=\"realm1\"");
-                TestHttpServer.rendezvous ("one", 2);
-                break;
-            case 1:
-                TestHttpServer.waitForCondition ("cond2");
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+        class AuthenticationHandlerT1a implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                try {
+                    switch(count) {
+                        case 0:
+                            AuthenticationHandler.errorReply(exchange,
+                                    "Basic realm=\"realm1\"");
+                            break;
+                        case 1:
+                            t1Cond1.await();
+                            t1cond2latch.await();
+                            AuthenticationHandler.okReply(exchange);
+                            break;
+                        default:
+                            System.out.println ("Unexpected request");
+                    }
+                } catch (InterruptedException |
+                                 BrokenBarrierException e)
+                        {
+                            throw new RuntimeException(e);
+                        }
+            }
+        }
+
+        class AuthenticationHandlerT1b implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                try {
+                    switch(count) {
+                        case 0:
+                            AuthenticationHandler.errorReply(exchange,
+                                    "Basic realm=\"realm2\"");
+                            break;
+                        case 1:
+                            t1Cond1.await();
+                            t1cond1latch.countDown();
+                            t1cond2latch.await();
+                            AuthenticationHandler.okReply(exchange);
+                            break;
+                        default:
+                            System.out.println ("Unexpected request");
+                    }
+                } catch (InterruptedException | BrokenBarrierException e) {
+                    throw new RuntimeException(e);
+                }
             }
         }
 
+        class AuthenticationHandlerT1c implements HttpHandler
+        {
+            volatile int count = -1;
 
-        void doT1b (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                errorReply (req, "Basic realm=\"realm2\"");
-                TestHttpServer.rendezvous ("one", 2);
-                TestHttpServer.setCondition ("cond1");
-                break;
-            case 1:
-                TestHttpServer.waitForCondition ("cond2");
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                switch(count) {
+                    case 0:
+                        AuthenticationHandler.errorReply(exchange,
+                                "Basic realm=\"realm1\"");
+                        try {
+                            t1Cond2.await();
+                        } catch (InterruptedException |
+                                 BrokenBarrierException e)
+                        {
+                            throw new RuntimeException(e);
+                        }
+                        break;
+                    case 1:
+                        AuthenticationHandler.okReply(exchange);
+                        break;
+                    default:
+                        System.out.println ("Unexpected request");
+                }
             }
         }
 
-        void doT1c (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                errorReply (req, "Basic realm=\"realm1\"");
-                TestHttpServer.rendezvous ("two", 2);
-                break;
-            case 1:
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+        class AuthenticationHandlerT1d implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                switch(count) {
+                    case 0:
+                        AuthenticationHandler.errorReply(exchange,
+                                "Basic realm=\"realm2\"");
+                        try {
+                            t1Cond2.await();
+                        } catch (InterruptedException |
+                                 BrokenBarrierException e)
+                        {
+                            throw new RuntimeException(e);
+                        }
+                        t1cond2latch.countDown();
+                        break;
+                    case 1:
+                        AuthenticationHandler.okReply(exchange);
+                        break;
+                    default:
+                        System.out.println ("Unexpected request");
+                }
             }
         }
 
-        void doT1d (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                errorReply (req, "Basic realm=\"realm2\"");
-                TestHttpServer.rendezvous ("two", 2);
-                TestHttpServer.setCondition ("cond2");
-                break;
-            case 1:
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
-            }
-        }
-
-
         /* T2 tests to check that if initial authentication fails, the second will
          * succeed, and the authenticator is called twice
          */
 
-        void doT2a (HttpTransaction req, int count) throws IOException {
-            /* This will be called several times */
-            if (count == 1) {
-                TestHttpServer.setCondition ("T2cond1");
+        class AuthenticationHandlerT2a implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                if (count == 1) {
+                    t2condlatch.countDown();
+                }
+                AuthenticationHandler.errorReply(exchange,
+                        "Basic realm=\"realm3\"");
+
             }
-            errorReply (req, "Basic realm=\"realm3\"");
         }
 
-        void doT2b (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                errorReply (req, "Basic realm=\"realm3\"");
-                break;
-            case 1:
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+         class AuthenticationHandlerT2b implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                switch(count) {
+                    case 0:
+                        AuthenticationHandler.errorReply(exchange,
+                                "Basic realm=\"realm3\"");
+                        break;
+                    case 1:
+                        AuthenticationHandler.okReply(exchange);
+                        break;
+                    default:
+                        System.out.println ("Unexpected request");
+                }
             }
         }
 
@@ -229,63 +307,117 @@
          * resource at same time. Authenticator should be called once for server
          * and once for proxy
          */
-        void doT3a (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                proxyReply (req, "Basic realm=\"proxy\"");
-                TestHttpServer.setCondition ("T3cond1");
-                break;
-            case 1:
-                errorReply (req, "Basic realm=\"realm4\"");
-                break;
-            case 2:
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+
+        class AuthenticationHandlerT3a implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                switch(count) {
+                    case 0:
+                        AuthenticationHandler.proxyReply(exchange,
+                                "Basic realm=\"proxy\"");
+                        break;
+                    case 1:
+                        t3cond1.countDown();
+                        AuthenticationHandler.errorReply(exchange,
+                                "Basic realm=\"realm4\"");
+                        break;
+                    case 2:
+                        AuthenticationHandler.okReply(exchange);
+                        break;
+                    default:
+                        System.out.println ("Unexpected request");
+                }
             }
         }
 
-        void doT3bc (HttpTransaction req, int count) throws IOException {
-            switch (count) {
-            case 0:
-                proxyReply (req, "Basic realm=\"proxy\"");
-                break;
-            case 1:
-                okReply (req);
-                break;
-            default:
-                System.out.println ("Unexpected request");
+        class AuthenticationHandlerT3bc implements HttpHandler
+        {
+            volatile int count = -1;
+
+            @Override
+            public void handle(HttpExchange exchange) throws IOException {
+                count++;
+                switch(count) {
+                    case 0:
+                        AuthenticationHandler.proxyReply(exchange,
+                                "Basic realm=\"proxy\"");
+                        break;
+                    case 1:
+                        AuthenticationHandler.okReply(exchange);
+                        break;
+                    default:
+                        System.out.println ("Unexpected request");
+                }
             }
         }
-    };
+    }
+
+    static class AuthenticationHandler {
+        static void errorReply(HttpExchange exchange, String reply)
+                throws IOException
+        {
+            exchange.getResponseHeaders().add("Connection", "close");
+            exchange.getResponseHeaders().add("WWW-Authenticate", reply);
+            exchange.sendResponseHeaders(401, 0);
+            exchange.close();
+        }
 
-    static TestHttpServer server;
+        static void proxyReply (HttpExchange exchange, String reply)
+                throws IOException
+        {
+            exchange.getResponseHeaders().add("Proxy-Authenticate", reply);
+            exchange.sendResponseHeaders(407, 0);
+        }
+
+        static void okReply (HttpExchange exchange) throws IOException {
+            exchange.getResponseHeaders().add("Connection", "close");
+            String response = "Hello .";
+            exchange.sendResponseHeaders(200, response.getBytes().length);
+            OutputStream os = exchange.getResponseBody();
+            os.write(response.getBytes());
+            os.close();
+            exchange.close();
+        }
+    }
+
+    static Server server;
     static MyAuthenticator auth = new MyAuthenticator ();
 
     static int redirects = 4;
 
     static Client c1,c2,c3,c4,c5,c6,c7,c8,c9;
 
-    static void doServerTests (String authority) throws Exception {
+    static CountDownLatch t1cond1latch;
+    static CountDownLatch t1cond2latch;
+    static CountDownLatch t2condlatch;
+    static CountDownLatch t3cond1;
+
+    static void doServerTests (String authority, Server server) throws Exception
+    {
         System.out.println ("Doing Server tests");
         System.out.println ("T1");
         c1 = new Client (authority, "/test/realm1/t1a", false);
         c2 = new Client (authority, "/test/realm2/t1b", false);
         c3 = new Client (authority, "/test/realm1/t1c", false);
         c4 = new Client (authority, "/test/realm2/t1d", false);
-
+        t1cond1latch = new CountDownLatch(1);
+        t1cond2latch = new CountDownLatch(1);
         c1.start(); c2.start();
-        TestHttpServer.waitForCondition ("cond1");
+        t1cond1latch.await();
         c3.start(); c4.start();
         c1.join(); c2.join(); c3.join(); c4.join();
 
         int f = auth.getCount();
         if (f != 2) {
-            except ("Authenticator was called "+f+" times. Should be 2");
+            except ("Authenticator was called "+f+" times. Should be 2",
+                    server);
         }
         if (error) {
-            except ("error occurred");
+            except ("error occurred", server);
         }
 
         auth.resetCount();
@@ -293,73 +425,71 @@
 
         c5 = new Client (authority, "/test/realm3/t2a", true);
         c6 = new Client (authority, "/test/realm3/t2b", false);
+        t2condlatch = new CountDownLatch(1);
         c5.start ();
-        TestHttpServer.waitForCondition ("T2cond1");
+        t2condlatch.await();
         c6.start ();
         c5.join(); c6.join();
 
         f = auth.getCount();
         if (f != redirects+1) {
-            except ("Authenticator was called "+f+" times. Should be: " + redirects+1);
+            except ("Authenticator was called "+f+" times. Should be: "
+                    + redirects+1, server);
         }
         if (error) {
-            except ("error occurred");
+            except ("error occurred", server);
         }
     }
 
-    static void doProxyTests (String authority) throws Exception {
+    static void doProxyTests (String authority, Server server) throws Exception
+    {
         System.out.println ("Doing Proxy tests");
         c7 = new Client (authority, "/test/realm4/t3a", false);
         c8 = new Client (authority, "/test/realm4/t3b", false);
         c9 = new Client (authority, "/test/realm4/t3c", false);
+        t3cond1 = new CountDownLatch(1);
         c7.start ();
-        TestHttpServer.waitForCondition ("T3cond1");
+        t3cond1.await();
         c8.start ();
         c9.start ();
         c7.join(); c8.join(); c9.join();
 
         int f = auth.getCount();
         if (f != 2) {
-            except ("Authenticator was called "+f+" times. Should be: " + 2);
+            except ("Authenticator was called "+f+" times. Should be: " + 2,
+                    server);
         }
         if (error) {
-            except ("error occurred");
+            except ("error occurred", server);
         }
     }
 
     public static void main (String[] args) throws Exception {
+        new B4769350().runTest(args[0].equals ("proxy"));
+    }
+
+    public void runTest(boolean proxy) throws Exception {
         System.setProperty ("http.maxRedirects", Integer.toString (redirects));
         System.setProperty ("http.auth.serializeRequests", "true");
         Authenticator.setDefault (auth);
-        boolean proxy = args[0].equals ("proxy");
-        try {
-            server = new TestHttpServer (new CallBack(), 10, 1, 0);
-            System.out.println ("Server: listening on port: " + server.getLocalPort());
+        try (Server server = new Server()) {
+            server.startServer();
+            System.out.println ("Server: listening on port: "
+                    + server.getPort());
             if (proxy) {
                 System.setProperty ("http.proxyHost", "localhost");
-                System.setProperty ("http.proxyPort",Integer.toString(server.getLocalPort()));
-                doProxyTests ("www.foo.com");
+                System.setProperty ("http.proxyPort",
+                        Integer.toString(server.getPort()));
+                doProxyTests ("www.foo.com", server);
             } else {
-                doServerTests ("localhost:"+server.getLocalPort());
+                doServerTests ("localhost:"+server.getPort(), server);
             }
-            server.terminate();
+        }
 
-        } catch (Exception e) {
-            if (server != null) {
-                server.terminate();
-            }
-            throw e;
-        }
     }
 
-    static void pause (int millis) {
-        try {
-            Thread.sleep (millis);
-        } catch (InterruptedException e) {}
-    }
-
-    public static void except (String s) {
-        server.terminate();
+    public static void except (String s, Server server) {
+        server.close();
         throw new RuntimeException (s);
     }
 
@@ -368,13 +498,10 @@
             super ();
         }
 
-        int count = 0;
+        volatile int count = 0;
 
+        @Override
         public PasswordAuthentication getPasswordAuthentication () {
-            //System.out.println ("Authenticator called: " + getRequestingPrompt());
-            //try {
-                //Thread.sleep (1000);
-            //} catch (InterruptedException e) {}
             PasswordAuthentication pw;
             pw = new PasswordAuthentication ("user", "pass1".toCharArray());
             count ++;
@@ -386,7 +513,8 @@
         }
 
         public int getCount () {
-            return (count);
+            return count;
         }
     }
 }
+