You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2008/12/01 20:09:46 UTC

svn commit: r722180 - in /httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http: conn/ssl/TestSSLSocketFactory.java localserver/LocalTestServer.java

Author: olegk
Date: Mon Dec  1 11:09:46 2008
New Revision: 722180

URL: http://svn.apache.org/viewvc?rev=722180&view=rev
Log:
* refactored local test server
* added option to specify an SSL context for the local test server
* fixed SSL socket factory test case failing intermittently when running JRE 1.6

Modified:
    httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
    httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/localserver/LocalTestServer.java

Modified: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java?rev=722180&r1=722179&r2=722180&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java Mon Dec  1 11:09:46 2008
@@ -32,14 +32,9 @@
 package org.apache.http.conn.ssl;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.math.BigInteger;
-import java.net.ServerSocket;
-import java.net.Socket;
 import java.security.KeyFactory;
 import java.security.KeyStore;
 import java.security.PrivateKey;
@@ -47,13 +42,25 @@
 import java.security.cert.X509Certificate;
 import java.security.spec.RSAPrivateCrtKeySpec;
 
-import javax.net.ServerSocketFactory;
-import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.localserver.LocalTestServer;
 import org.apache.http.params.BasicHttpParams;
 import org.apache.http.params.HttpParams;
 
@@ -81,6 +88,30 @@
         return ts;
     }
 
+    static class TestX509HostnameVerifier implements X509HostnameVerifier {
+
+        private boolean fired = false;
+        
+        public boolean verify(String host, SSLSession session) {
+            return true;
+        }
+
+        public void verify(String host, SSLSocket ssl) throws IOException {
+            this.fired = true;
+        }
+
+        public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
+        }
+
+        public void verify(String host, X509Certificate cert) throws SSLException {
+        }
+        
+        public boolean isFired() {
+            return this.fired;
+        }
+        
+    }
+    
     public void testCreateSocket() throws Exception {
         HttpParams params = new BasicHttpParams();
         String password = "changeit";
@@ -113,95 +144,44 @@
         ks.setKeyEntry("RSA_KEY", pk, pwd, chain);
         ks.setCertificateEntry("CERT", chain[2]); // Let's trust ourselves. :-)
 
-        File tempFile = File.createTempFile("junit", "jks");
+        KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory
+                .getDefaultAlgorithm());
+        kmfactory.init(ks, pwd);
+        KeyManager[] keymanagers = kmfactory.getKeyManagers();
+            
+        TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
+                TrustManagerFactory.getDefaultAlgorithm());
+        tmfactory.init(ks);
+        TrustManager[] trustmanagers = tmfactory.getTrustManagers();
+        
+        SSLContext sslcontext = SSLContext.getInstance("TLSv1");
+        sslcontext.init(keymanagers, trustmanagers, null);
+        
+        LocalTestServer server = new LocalTestServer(null, null, null, sslcontext);
+        server.registerDefaultHandlers();
+        server.start();
         try {
-            String path = tempFile.getCanonicalPath();
-            tempFile.deleteOnExit();
-            FileOutputStream fOut = new FileOutputStream(tempFile);
-            ks.store(fOut, pwd);
-            fOut.close();
-
-            System.setProperty("javax.net.ssl.keyStore", path);
-            System.setProperty("javax.net.ssl.keyStorePassword", password);
-            System.setProperty("javax.net.ssl.trustStore", path);
-            System.setProperty("javax.net.ssl.trustStorePassword", password);
-
-            ServerSocketFactory server = SSLServerSocketFactory.getDefault();
-            // Let the operating system just choose an available port:
-            ServerSocket serverSocket = server.createServerSocket(0);
-            serverSocket.setSoTimeout(30000);
-            int port = serverSocket.getLocalPort();
-            // System.out.println("\nlistening on port: " + port);
-
-            SSLSocketFactory ssf = SSLSocketFactory.getSocketFactory();
-            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
-
-            // Test 1 - createSocket()
-            IOException[] e = new IOException[1];
-            boolean[] success = new boolean[1];
-            listen(serverSocket, e, success);
-            Socket s = ssf.connectSocket(null, "localhost", port,
-                                         null, 0, params);
-            exerciseSocket(s, e, success);
-
-            // Test 2 - createSocket( Socket ), where we upgrade a plain socket
-            //          to SSL.
-            success[0] = false;
-            listen(serverSocket, e, success);
-            s = new Socket("localhost", port);
-            s = ssf.createSocket(s, "localhost", port, true);
-            exerciseSocket(s, e, success);
-        }
-        finally {
-            tempFile.delete();
+            
+            TestX509HostnameVerifier hostnameVerifier = new TestX509HostnameVerifier();
+            
+            SSLSocketFactory socketFactory = new SSLSocketFactory(sslcontext);
+            socketFactory.setHostnameVerifier(hostnameVerifier);
+            
+            Scheme https = new Scheme("https", socketFactory, 443); 
+            DefaultHttpClient httpclient = new DefaultHttpClient();
+            httpclient.getConnectionManager().getSchemeRegistry().register(https);
+            
+            HttpHost target = new HttpHost(
+                    LocalTestServer.TEST_SERVER_ADDR.getHostName(),
+                    server.getServicePort(),
+                    "https");
+            HttpGet httpget = new HttpGet("/random/100");
+            HttpResponse response = httpclient.execute(target, httpget);
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertTrue(hostnameVerifier.isFired());
+        } finally {
+            server.stop();
         }
     }
 
-    private static void listen(final ServerSocket ss,
-                               final IOException[] e,
-                               final boolean[] success) {
-        Runnable r = new Runnable() {
-            public void run() {
-                try {
-                    Socket s = ss.accept();
-                    InputStream in = s.getInputStream();
-                    OutputStream out = s.getOutputStream();
-                    out.write("server says hello\n".getBytes());
-                    byte[] buf = new byte[4096];
-                    in.read(buf);
-                    out.close();
-                    in.close();
-                    s.close();
-                } catch(IOException ioe) {
-                    e[0] = ioe;
-                } finally {
-                    success[0] = true;
-                }
-            }
-        };
-        new Thread(r).start();
-        Thread.yield();
-    }
-
-    private static void exerciseSocket(Socket s, IOException[] e,
-                                       boolean[] success)
-          throws IOException {
-        InputStream in = s.getInputStream();
-        OutputStream out = s.getOutputStream();
-        out.write(42);
-        byte[] buf = new byte[4096];
-        in.read(buf);
-        out.close();
-        in.close();
-        s.close();
-        // String response = new String( buf, 0, c );
-        while(!success[0]) {
-            Thread.yield();
-        }
-        if(e[0] != null) {
-            throw e[0];
-        }
-    }
-
-
 }

Modified: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/localserver/LocalTestServer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/localserver/LocalTestServer.java?rev=722180&r1=722179&r2=722180&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/localserver/LocalTestServer.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/localserver/LocalTestServer.java Mon Dec  1 11:09:46 2008
@@ -41,6 +41,9 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.HttpException;
 import org.apache.http.HttpServerConnection;
@@ -85,21 +88,24 @@
         new InetSocketAddress("127.0.0.1", 0);
 
     /** The request handler registry. */
-    public HttpRequestHandlerRegistry handlerRegistry;
+    private final HttpRequestHandlerRegistry handlerRegistry;
 
     /** The server-side connection re-use strategy. */
-    public ConnectionReuseStrategy reuseStrategy;
+    private final ConnectionReuseStrategy reuseStrategy;
 
     /**
      * The HTTP processor.
      * If the interceptors are thread safe and the list is not
      * modified during operation, the processor is thread safe.
      */
-    public BasicHttpProcessor httpProcessor;
+    private final BasicHttpProcessor httpProcessor;
 
     /** The server parameters. */
-    public HttpParams serverParams;
+    private final HttpParams serverParams;
 
+    /** Optional SSL context */
+    private final SSLContext sslcontext;
+    
     /** The server socket, while being served. */
     protected volatile ServerSocket servicedSocket;
 
@@ -116,24 +122,52 @@
      * @param proc      the HTTP processors to be used by the server, or
      *                  <code>null</code> to use a
      *                  {@link #newProcessor default} processor
+     * @param reuseStrat the connection reuse strategy to be used by the 
+     *                  server, or <code>null</code> to use
+     *                  {@link #newConnectionReuseStrategy() default}
+     *                  strategy.                 
      * @param params    the parameters to be used by the server, or
      *                  <code>null</code> to use
      *                  {@link #newDefaultParams default} parameters
+     * @param sslcontext optional SSL context if the server is to leverage
+     *                   SSL/TLS transport security
      */
-    public LocalTestServer(BasicHttpProcessor proc, HttpParams params) {
-        handlerRegistry = new HttpRequestHandlerRegistry();
-        reuseStrategy = new DefaultConnectionReuseStrategy();
-        httpProcessor = (proc != null) ? proc : newProcessor();
-        serverParams = (params != null) ? params : newDefaultParams();
+    public LocalTestServer(
+            BasicHttpProcessor proc, 
+            ConnectionReuseStrategy reuseStrat,
+            HttpParams params, 
+            SSLContext sslcontext) {
+        super();
+        this.handlerRegistry = new HttpRequestHandlerRegistry();
+        this.reuseStrategy = (reuseStrat != null) ? reuseStrat: newConnectionReuseStrategy();
+        this.httpProcessor = (proc != null) ? proc : newProcessor();
+        this.serverParams = (params != null) ? params : newDefaultParams();
+        this.sslcontext = sslcontext;
     }
 
 
     /**
+     * Creates a new test server.
+     *
+     * @param proc      the HTTP processors to be used by the server, or
+     *                  <code>null</code> to use a
+     *                  {@link #newProcessor default} processor
+     * @param params    the parameters to be used by the server, or
+     *                  <code>null</code> to use
+     *                  {@link #newDefaultParams default} parameters
+     */
+    public LocalTestServer(
+            BasicHttpProcessor proc, 
+            HttpParams params) {
+        this(proc, null, params, null);
+    }
+
+    /**
      * Obtains an HTTP protocol processor with default interceptors.
      *
      * @return  a protocol processor for server-side use
      */
-    public static BasicHttpProcessor newProcessor() {
+    protected BasicHttpProcessor newProcessor() {
 
         BasicHttpProcessor httpproc = new BasicHttpProcessor();
         httpproc.addInterceptor(new ResponseDate());
@@ -150,7 +184,7 @@
      *
      * @return  default parameters
      */
-    public static HttpParams newDefaultParams() {
+    protected HttpParams newDefaultParams() {
         HttpParams params = new BasicHttpParams();
         params
             .setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
@@ -166,6 +200,11 @@
         return params;
     }
     
+    protected ConnectionReuseStrategy newConnectionReuseStrategy() {
+        return new DefaultConnectionReuseStrategy();
+    }
+    
+    
     /**
      * Returns the number of connections this test server has accepted.
      */
@@ -210,16 +249,6 @@
 
 
     /**
-     * Specifies the connection re-use strategy.
-     *
-     * @param strategy  the re-use strategy
-     */
-    public void setReuseStrategy(ConnectionReuseStrategy strategy) {
-        reuseStrategy = strategy;
-    }
-
-
-    /**
      * Starts this test server.
      * Use {@link #getServicePort getServicePort}
      * to obtain the port number afterwards.
@@ -229,7 +258,14 @@
             throw new IllegalStateException
                 (this.toString() + " already running");
 
-        ServerSocket ssock = new ServerSocket();
+        ServerSocket ssock;
+        if (sslcontext != null) {
+            SSLServerSocketFactory sf = sslcontext.getServerSocketFactory();
+            ssock = sf.createServerSocket();
+        } else {
+            ssock = new ServerSocket();
+        }
+        
         ssock.setReuseAddress(true); // probably pointless for port '0'
         ssock.bind(TEST_SERVER_ADDR);
         servicedSocket = ssock;
@@ -257,12 +293,16 @@
 
         if (listenerThread != null) {
             listenerThread.interrupt();
-            //@@@ listenerThread.join(); ?
-            listenerThread = null;
         }
     }
 
 
+    public void awaitTermination(long timeMs) throws InterruptedException {
+        if (listenerThread != null) {
+            listenerThread.join(timeMs);
+        }
+    }
+    
     @Override
     public String toString() {
         ServerSocket ssock = servicedSocket; // avoid synchronization