This commit is contained in:
Sean Mullan 2013-10-22 09:06:42 -04:00
commit 3d8f3459a4
2 changed files with 311 additions and 291 deletions

View File

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

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8022584
* @summary Some NetworkInterface methods can leak native memory
* @run main/othervm/timeout=700 MemLeakTest
*/
/* Note: the test can cause a memory leak that's why othervm option is required
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collection;
import java.util.Collections;
public class MemLeakTest {
/**
* Memory leak is assumed, if application consumes more than specified amount of memory during its execution.
* The number is given in Kb.
*/
private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32Mb
public static void main(String[] args)
throws Exception {
if (!System.getProperty("os.name").equals("Linux")) {
System.out.println("Test only runs on Linux");
return;
}
// warm up
accessNetInterfaces(3);
long vMemBefore = getVMemSize();
accessNetInterfaces(500_000);
long vMemAfter = getVMemSize();
long vMemDelta = vMemAfter - vMemBefore;
if (vMemDelta > MEM_LEAK_THRESHOLD) {
throw new Exception("FAIL: Virtual memory usage increased by " + vMemDelta + "Kb " +
"(greater than " + MEM_LEAK_THRESHOLD + "Kb)");
}
System.out.println("PASS: Virtual memory usage increased by " + vMemDelta + "Kb " +
"(not greater than " + MEM_LEAK_THRESHOLD + "Kb)");
}
private static void accessNetInterfaces(int times) {
try {
Collection<NetworkInterface> interfaces =
Collections.list(NetworkInterface.getNetworkInterfaces());
for (int i = 0; i != times; ++i) {
for (NetworkInterface netInterface : interfaces) {
netInterface.getMTU();
netInterface.isLoopback();
netInterface.isUp();
netInterface.isPointToPoint();
netInterface.supportsMulticast();
}
}
} catch (SocketException ignore) {}
}
/**
* Returns size of virtual memory allocated to the process in Kb.
* Linux specific. On other platforms and in case of any errors returns 0.
*/
private static long getVMemSize() {
// Refer to the Linux proc(5) man page for details about /proc/self/stat file
//
// In short, this file contains status information about the current process
// written in one line. The fields are separated with spaces.
// The 23rd field is defined as 'vsize %lu Virtual memory size in bytes'
try (FileReader fileReader = new FileReader("/proc/self/stat");
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
String line = bufferedReader.readLine();
return Long.parseLong(line.split(" ")[22]) / 1024;
} catch (Exception ignore) {}
return 0;
}
}