B4769350.java revision 6073:cea72c2bf071
1/*
2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @bug 4769350
27 * @library ../../../sun/net/www/httptest/
28 * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction AbstractCallback
29 * @run main/othervm B4769350 server
30 * @run main/othervm B4769350 proxy
31 * @summary proxy authentication username and password caching only works in serial case
32 * Run in othervm since the test sets system properties that are read by the
33 * networking stack and cached when the HTTP handler is invoked, and previous
34 * tests may already have invoked the HTTP handler.
35 */
36
37import java.io.*;
38import java.net.*;
39
40public class B4769350 {
41
42    static int count = 0;
43    static boolean error = false;
44
45    static void read (InputStream is) throws IOException {
46        int c;
47        while ((c=is.read()) != -1) {
48            //System.out.write (c);
49        }
50    }
51
52    static class Client extends Thread {
53        String authority, path;
54        boolean allowerror;
55
56        Client (String authority, String path, boolean allowerror) {
57            super("Thread-" + path);
58            this.authority = authority;
59            this.path = path;
60            this.allowerror = allowerror;
61        }
62
63        public void run () {
64            try {
65                URI u = new URI ("http", authority, path, null, null);
66                URL url = u.toURL();
67                URLConnection urlc = url.openConnection ();
68                InputStream is = urlc.getInputStream ();
69                read (is);
70                is.close();
71            } catch (URISyntaxException  e) {
72                System.out.println (e);
73                error = true;
74            } catch (IOException e) {
75                if (!allowerror) {
76                    System.out.println (Thread.currentThread().getName() + " " + e);
77                    e.printStackTrace();
78                    error = true;
79                }
80            }
81        }
82    }
83
84    static class CallBack extends AbstractCallback {
85
86        void errorReply (HttpTransaction req, String reply) throws IOException {
87            req.addResponseHeader ("Connection", "close");
88            req.addResponseHeader ("WWW-Authenticate", reply);
89            req.sendResponse (401, "Unauthorized");
90            req.orderlyClose();
91        }
92
93        void proxyReply (HttpTransaction req, String reply) throws IOException {
94            req.addResponseHeader ("Proxy-Authenticate", reply);
95            req.sendResponse (407, "Proxy Authentication Required");
96        }
97
98        void okReply (HttpTransaction req) throws IOException {
99            req.addResponseHeader ("Connection", "close");
100            req.setResponseEntityBody ("Hello .");
101            req.sendResponse (200, "Ok");
102            req.orderlyClose();
103        }
104
105        public void request (HttpTransaction req, int count) {
106            try {
107                URI uri = req.getRequestURI();
108                String path = uri.getPath();
109                if (path.endsWith ("/t1a")) {
110                    doT1a (req, count);
111                } else if (path.endsWith ("/t1b")) {
112                    doT1b (req, count);
113                } else if (path.endsWith ("/t1c")) {
114                    doT1c (req, count);
115                } else if (path.endsWith ("/t1d")) {
116                    doT1d (req, count);
117                } else if (path.endsWith ("/t2a")) {
118                    doT2a (req, count);
119                } else if (path.endsWith ("/t2b")) {
120                    doT2b (req, count);
121                } else if (path.endsWith ("/t3a")) {
122                    doT3a (req, count);
123                } else if (path.endsWith ("/t3b")) {
124                    doT3bc (req, count);
125                } else if (path.endsWith ("/t3c")) {
126                    doT3bc (req, count);
127                } else {
128                   System.out.println ("unexpected request URI");
129                }
130            } catch (IOException e) {
131                e.printStackTrace();
132            }
133        }
134
135        /* T1 tests the client by sending 4 requests to 2 different realms
136         * in parallel. The client should recognise two pairs of dependent requests
137         * and execute the first of each pair in parallel. When they both succeed
138         * the second requests should be executed without calling the authenticator.
139         * The test succeeds if the authenticator was only called twice.
140         */
141        void doT1a (HttpTransaction req, int count) throws IOException {
142            switch (count) {
143            case 0:
144                errorReply (req, "Basic realm=\"realm1\"");
145                TestHttpServer.rendezvous ("one", 2);
146                break;
147            case 1:
148                TestHttpServer.waitForCondition ("cond2");
149                okReply (req);
150                break;
151            default:
152                System.out.println ("Unexpected request");
153            }
154        }
155
156
157        void doT1b (HttpTransaction req, int count) throws IOException {
158            switch (count) {
159            case 0:
160                errorReply (req, "Basic realm=\"realm2\"");
161                TestHttpServer.rendezvous ("one", 2);
162                TestHttpServer.setCondition ("cond1");
163                break;
164            case 1:
165                TestHttpServer.waitForCondition ("cond2");
166                okReply (req);
167                break;
168            default:
169                System.out.println ("Unexpected request");
170            }
171        }
172
173        void doT1c (HttpTransaction req, int count) throws IOException {
174            switch (count) {
175            case 0:
176                errorReply (req, "Basic realm=\"realm1\"");
177                TestHttpServer.rendezvous ("two", 2);
178                break;
179            case 1:
180                okReply (req);
181                break;
182            default:
183                System.out.println ("Unexpected request");
184            }
185        }
186
187        void doT1d (HttpTransaction req, int count) throws IOException {
188            switch (count) {
189            case 0:
190                errorReply (req, "Basic realm=\"realm2\"");
191                TestHttpServer.rendezvous ("two", 2);
192                TestHttpServer.setCondition ("cond2");
193                break;
194            case 1:
195                okReply (req);
196                break;
197            default:
198                System.out.println ("Unexpected request");
199            }
200        }
201
202
203        /* T2 tests to check that if initial authentication fails, the second will
204         * succeed, and the authenticator is called twice
205         */
206
207        void doT2a (HttpTransaction req, int count) throws IOException {
208            /* This will be called several times */
209            if (count == 1) {
210                TestHttpServer.setCondition ("T2cond1");
211            }
212            errorReply (req, "Basic realm=\"realm3\"");
213        }
214
215        void doT2b (HttpTransaction req, int count) throws IOException {
216            switch (count) {
217            case 0:
218                errorReply (req, "Basic realm=\"realm3\"");
219                break;
220            case 1:
221                okReply (req);
222                break;
223            default:
224                System.out.println ("Unexpected request");
225            }
226        }
227
228        /* T3 tests proxy and server authentication. three threads request same
229         * resource at same time. Authenticator should be called once for server
230         * and once for proxy
231         */
232        void doT3a (HttpTransaction req, int count) throws IOException {
233            switch (count) {
234            case 0:
235                proxyReply (req, "Basic realm=\"proxy\"");
236                TestHttpServer.setCondition ("T3cond1");
237                break;
238            case 1:
239                errorReply (req, "Basic realm=\"realm4\"");
240                break;
241            case 2:
242                okReply (req);
243                break;
244            default:
245                System.out.println ("Unexpected request");
246            }
247        }
248
249        void doT3bc (HttpTransaction req, int count) throws IOException {
250            switch (count) {
251            case 0:
252                proxyReply (req, "Basic realm=\"proxy\"");
253                break;
254            case 1:
255                okReply (req);
256                break;
257            default:
258                System.out.println ("Unexpected request");
259            }
260        }
261    };
262
263    static TestHttpServer server;
264    static MyAuthenticator auth = new MyAuthenticator ();
265
266    static int redirects = 4;
267
268    static Client c1,c2,c3,c4,c5,c6,c7,c8,c9;
269
270    static void doServerTests (String authority) throws Exception {
271        System.out.println ("Doing Server tests");
272        System.out.println ("T1");
273        c1 = new Client (authority, "/test/realm1/t1a", false);
274        c2 = new Client (authority, "/test/realm2/t1b", false);
275        c3 = new Client (authority, "/test/realm1/t1c", false);
276        c4 = new Client (authority, "/test/realm2/t1d", false);
277
278        c1.start(); c2.start();
279        TestHttpServer.waitForCondition ("cond1");
280        c3.start(); c4.start();
281        c1.join(); c2.join(); c3.join(); c4.join();
282
283        int f = auth.getCount();
284        if (f != 2) {
285            except ("Authenticator was called "+f+" times. Should be 2");
286        }
287        if (error) {
288            except ("error occurred");
289        }
290
291        auth.resetCount();
292        System.out.println ("T2");
293
294        c5 = new Client (authority, "/test/realm3/t2a", true);
295        c6 = new Client (authority, "/test/realm3/t2b", false);
296        c5.start ();
297        TestHttpServer.waitForCondition ("T2cond1");
298        c6.start ();
299        c5.join(); c6.join();
300
301        f = auth.getCount();
302        if (f != redirects+1) {
303            except ("Authenticator was called "+f+" times. Should be: " + redirects+1);
304        }
305        if (error) {
306            except ("error occurred");
307        }
308    }
309
310    static void doProxyTests (String authority) throws Exception {
311        System.out.println ("Doing Proxy tests");
312        c7 = new Client (authority, "/test/realm4/t3a", false);
313        c8 = new Client (authority, "/test/realm4/t3b", false);
314        c9 = new Client (authority, "/test/realm4/t3c", false);
315        c7.start ();
316        TestHttpServer.waitForCondition ("T3cond1");
317        c8.start ();
318        c9.start ();
319        c7.join(); c8.join(); c9.join();
320
321        int f = auth.getCount();
322        if (f != 2) {
323            except ("Authenticator was called "+f+" times. Should be: " + 2);
324        }
325        if (error) {
326            except ("error occurred");
327        }
328    }
329
330    public static void main (String[] args) throws Exception {
331        System.setProperty ("http.maxRedirects", Integer.toString (redirects));
332        System.setProperty ("http.auth.serializeRequests", "true");
333        Authenticator.setDefault (auth);
334        boolean proxy = args[0].equals ("proxy");
335        try {
336            server = new TestHttpServer (new CallBack(), 10, 1, 0);
337            System.out.println ("Server: listening on port: " + server.getLocalPort());
338            if (proxy) {
339                System.setProperty ("http.proxyHost", "localhost");
340                System.setProperty ("http.proxyPort",Integer.toString(server.getLocalPort()));
341                doProxyTests ("www.foo.com");
342            } else {
343                doServerTests ("localhost:"+server.getLocalPort());
344            }
345            server.terminate();
346
347        } catch (Exception e) {
348            if (server != null) {
349                server.terminate();
350            }
351            throw e;
352        }
353    }
354
355    static void pause (int millis) {
356        try {
357            Thread.sleep (millis);
358        } catch (InterruptedException e) {}
359    }
360
361    public static void except (String s) {
362        server.terminate();
363        throw new RuntimeException (s);
364    }
365
366    static class MyAuthenticator extends Authenticator {
367        MyAuthenticator () {
368            super ();
369        }
370
371        int count = 0;
372
373        public PasswordAuthentication getPasswordAuthentication () {
374            //System.out.println ("Authenticator called: " + getRequestingPrompt());
375            //try {
376                //Thread.sleep (1000);
377            //} catch (InterruptedException e) {}
378            PasswordAuthentication pw;
379            pw = new PasswordAuthentication ("user", "pass1".toCharArray());
380            count ++;
381            return pw;
382        }
383
384        public void resetCount () {
385            count = 0;
386        }
387
388        public int getCount () {
389            return (count);
390        }
391    }
392}
393