changeset 717:882d1bc0ff8f

Merge with: Fix for portalbank.no (trying get after failed head requests) and tests
author Jiri Vanek <jvanek@redhat.com>
date Thu, 02 May 2013 16:05:57 +0200
parents 01c529dee2b7 (current diff) f20482af9a95 (diff)
children 64d08fb70c0f
files ChangeLog
diffstat 12 files changed, 841 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu May 02 15:55:51 2013 +0200
+++ b/ChangeLog	Thu May 02 16:05:57 2013 +0200
@@ -1,3 +1,35 @@
+2013-05-02  Jiri Vanek  <jvanek@redhat.com>
+
+	Added various tests related to portalbank.no fixes
+	* netx/net/sourceforge/jnlp/cache/Resource.java: added fixme to warn
+	before wrong url comparator
+	* netx/net/sourceforge/jnlp/Version.java: removed useless main. Its
+	purpose moved to new
+	* tests/netx/unit/net/sourceforge/jnlp/VersionTest: some small tests to
+	version class
+	* tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java:
+	added tests to	(getUrlResponseCode) and (findBestUrl)
+	* tests/netx/unit/net/sourceforge/jnlp/util/HttpUtilsTest.java: added tests for
+	(consumeAndCloseConnectionSilently) and (consumeAndCloseConnection)
+	* tests/netx/unit/net/sourceforge/jnlp/util/UrlUtilsTest: added license header
+	* tests/test-extensions/net/sourceforge/jnlp/ServerLauncher.java: and
+	* tests/test-extensions/net/sourceforge/jnlp/TinyHttpdImpl.java: added
+	support for simulation of not working HEAD request.
+
+2013-05-02  Jiri Vanek  <jvanek@redhat.com>
+
+	Fix for portalbank.no (trying get after failed head requests)
+	* net/sourceforge/jnlp/cache/ResourceTracker : (findBestUrl)
+	now trying GET after each error request of HEAD type. Changed and
+	added debug messages. (getUrlResponseCode) closing of stream
+	moved to separate method HttpUtils.consumeAndCloseConnectionSilently
+	* net/sourceforge/jnlp/util/HttpUtils.java: new file designed  for
+	http utils. Now contains (consumeAndCloseConnection) and
+	(consumeAndCloseConnectionSilently) which calls consumeAndCloseConnection
+	but do not rethrow exception
+	* netx/net/sourceforge/jnlp/util/StreamUtils.java: removed
+	(consumeAndCloseInputStream) now improved and moved to HttpUtils
+
 2013-05-02  Jana Fabrikova  <jfabriko@redhat.com>
 
 	* tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java:
--- a/netx/net/sourceforge/jnlp/Version.java	Thu May 02 15:55:51 2013 +0200
+++ b/netx/net/sourceforge/jnlp/Version.java	Thu May 02 16:05:57 2013 +0200
@@ -308,42 +308,6 @@
 
     public String toString() {
         return versionString;
-    }
-
-    /**
-     * Test.
-     */
-    /*
-    public static void main(String args[]) {
-        Version jvms[] = {
-            new Version("1.1* 1.3*"),
-            new Version("1.2+"),
-        };
-
-        Version versions[] = {
-            new Version("1.1"),
-            new Version("1.1.8"),
-            new Version("1.2"),
-            new Version("1.3"),
-            new Version("2.0"),
-            new Version("1.3.1"),
-            new Version("1.2.1"),
-            new Version("1.3.1-beta"),
-            new Version("1.1 1.2"),
-            new Version("1.2 1.3"),
-        };
-
-        for (int j = 0; j < jvms.length; j++) {
-            for (int v = 0; v < versions.length; v++) {
-                System.out.print( jvms[j].toString() + " " );
-                if (!jvms[j].matches(versions[v]))
-                    System.out.print( "!" );
-                System.out.println( "matches " + versions[v].toString() );
-            }
-        }
-
-        System.out.println("Test completed");
-    }
-    */
+    }  
 
 }
--- a/netx/net/sourceforge/jnlp/cache/Resource.java	Thu May 02 15:55:51 2013 +0200
+++ b/netx/net/sourceforge/jnlp/cache/Resource.java	Thu May 02 16:05:57 2013 +0200
@@ -109,6 +109,8 @@
         synchronized (resources) {
             Resource resource = new Resource(location, requestVersion, updatePolicy);
 
+            //FIXME - url ignores port during its comparison
+            //this may affect test-suites
             int index = resources.indexOf(resource);
             if (index >= 0) { // return existing object
                 Resource result = resources.get(index);
--- a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java	Thu May 02 15:55:51 2013 +0200
+++ b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java	Thu May 02 16:05:57 2013 +0200
@@ -24,14 +24,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
-import java.net.URLDecoder;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -49,7 +45,7 @@
 import net.sourceforge.jnlp.event.DownloadEvent;
 import net.sourceforge.jnlp.event.DownloadListener;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
-import net.sourceforge.jnlp.util.StreamUtils;
+import net.sourceforge.jnlp.util.HttpUtils;
 import net.sourceforge.jnlp.util.UrlUtils;
 import net.sourceforge.jnlp.util.WeakList;
 
@@ -118,6 +114,9 @@
 
     /** max threads */
     private static final int maxThreads = 5;
+    
+    /** methods used to try individual URLs when choosing best*/
+    private static final String[] requestMethods = {"HEAD", "GET"};
 
     /** running threads */
     private static int threads = 0;
@@ -859,7 +858,7 @@
      * @return the response code if HTTP connection, or HttpURLConnection.HTTP_OK if not.
      * @throws IOException
      */
-    private static int getUrlResponseCode(URL url, Map<String, String> requestProperties, String requestMethod) throws IOException {
+     static int getUrlResponseCode(URL url, Map<String, String> requestProperties, String requestMethod) throws IOException {
         URLConnection connection = url.openConnection();
 
         for (Map.Entry<String, String> property : requestProperties.entrySet()){
@@ -874,7 +873,7 @@
 
             /* Fully consuming current request helps with connection re-use 
              * See http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html */
-            StreamUtils.consumeAndCloseInputStream(httpConnection.getInputStream());
+            HttpUtils.consumeAndCloseConnectionSilently(httpConnection);
 
             return responseCode;
         }
@@ -891,7 +890,7 @@
      * @param resource the resource
      * @return the best URL, or null if all failed to resolve
      */
-    private URL findBestUrl(Resource resource) {
+     URL findBestUrl(Resource resource) {
         DownloadOptions options = downloadOptions.get(resource);
         if (options == null) {
             options = new DownloadOptions(false, false);
@@ -903,33 +902,33 @@
                     resource.toString() + " : " + urls);
         }
 
-        for (URL url : urls) {
-            try {
-                Map<String, String> requestProperties = new HashMap<String, String>();
-                requestProperties.put("Accept-Encoding", "pack200-gzip, gzip");
+         for (String requestMethod : requestMethods) {
+             for (URL url : urls) {
+                 try {
+                     Map<String, String> requestProperties = new HashMap<String, String>();
+                     requestProperties.put("Accept-Encoding", "pack200-gzip, gzip");
 
-                int responseCode = getUrlResponseCode(url, requestProperties, "HEAD");
-
-                if (responseCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED ) {
-                    System.err.println("NOTE: The server does not appear to support HEAD requests, falling back to GET requests.");
-                    /* Fallback: use GET request in the rare case the server does not support HEAD requests */
-                    responseCode = getUrlResponseCode(url, requestProperties, "GET");
-                }
+                     int responseCode = getUrlResponseCode(url, requestProperties, requestMethod);
 
-                /* Check if within valid response code range */
-                if (responseCode >= 200 && responseCode < 300) {
-                    if (JNLPRuntime.isDebug()) {
-                        System.err.println("best url for " + resource.toString() + " is " + url.toString());
-                    }
-                    return url; /* This is the best URL */
-                }
-            } catch (IOException e) {
-                // continue to next candidate
-                if (JNLPRuntime.isDebug()) {
-                    System.err.println("While processing " + url.toString() + " for resource " + resource.toString() + " got " + e);
-                }
-            }
-        }
+                     if (responseCode < 200 || responseCode >= 300) {
+                         if (JNLPRuntime.isDebug()) {
+                             System.err.println("For "+resource.toString()+" the server returned " + responseCode + " code for "+requestMethod+" request for " + url.toExternalForm());
+                         }
+                     }else {
+                         if (JNLPRuntime.isDebug()) {
+                             System.out.println("best url for " + resource.toString() + " is " + url.toString() + " by " + requestMethod);
+                         }
+                         return url; /* This is the best URL */
+                     } 
+                 } catch (IOException e) {
+                     // continue to next candidate
+                     if (JNLPRuntime.isDebug()) {
+                         System.err.println("While processing " + url.toString() + " by " + requestMethod + " for resource " + resource.toString() + " got " + e + ": ");
+                         e.printStackTrace();
+                     }
+                 }
+             }
+         }
 
         /* No valid URL, return null */
         return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/util/HttpUtils.java	Thu May 02 16:05:57 2013 +0200
@@ -0,0 +1,76 @@
+/* 
+ Copyright (C) 2011 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2.
+
+ IcedTea 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+
+public class HttpUtils {
+
+    /**
+     * Ensure a HttpURLConnection is fully read, required for correct behavior.
+     * Captured IOException is consumed and printed
+     */
+    public static void consumeAndCloseConnectionSilently(HttpURLConnection c) {
+        try {
+            consumeAndCloseConnection(c);
+        } catch (IOException ex) {
+            ex.printStackTrace(System.err);
+        }
+    }
+
+    /**
+     * Ensure a HttpURLConnection is fully read, required for correct behavior
+     * 
+     * @throws IOException
+     */
+    public static void consumeAndCloseConnection(HttpURLConnection c) throws IOException {
+        InputStream in = null;
+        try {
+            in = c.getInputStream();
+            byte[] throwAwayBuffer = new byte[256];
+            while (in.read(throwAwayBuffer) > 0) {
+                /* ignore contents */
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+}
--- a/netx/net/sourceforge/jnlp/util/StreamUtils.java	Thu May 02 15:55:51 2013 +0200
+++ b/netx/net/sourceforge/jnlp/util/StreamUtils.java	Thu May 02 16:05:57 2013 +0200
@@ -45,19 +45,6 @@
 
 public class StreamUtils {
 
-    /**
-     * Ensure a stream is fully read, required for correct behaviour in some
-     * APIs, namely HttpURLConnection.
-     * @throws IOException 
-     */
-    public static void consumeAndCloseInputStream(InputStream in) throws IOException {
-        byte[] throwAwayBuffer = new byte[256];
-        while (in.read(throwAwayBuffer) > 0) {
-            /* ignore contents */
-        }
-        in.close();
-    }
-
     /***
      * Closes a stream, without throwing IOException.
      * In case of IOException, prints the stack trace to System.err.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/netx/unit/net/sourceforge/jnlp/VersionTest.java	Thu May 02 16:05:57 2013 +0200
@@ -0,0 +1,98 @@
+/* 
+ Copyright (C) 2011 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2.
+
+ IcedTea 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class VersionTest {
+
+    private static boolean[] results = {true,
+        true,
+        false,
+        true,
+        false,
+        true,
+        false,
+        true,
+        false,
+        false,
+        false,
+        false,
+        true,
+        true,
+        true,
+        true,
+        true,
+        true,
+        false,
+        true};
+    private static Version jvms[] = {
+        new Version("1.1* 1.3*"),
+        new Version("1.2+"),};
+    private static Version versions[] = {
+        new Version("1.1"),
+        new Version("1.1.8"),
+        new Version("1.2"),
+        new Version("1.3"),
+        new Version("2.0"),
+        new Version("1.3.1"),
+        new Version("1.2.1"),
+        new Version("1.3.1-beta"),
+        new Version("1.1 1.2"),
+        new Version("1.2 1.3"),};
+
+    @Test
+    public void testMatches() {
+
+        int i = 0;
+        for (int j = 0; j < jvms.length; j++) {
+            for (int v = 0; v < versions.length; v++) {
+                i++;
+                String debugOutput = i + " " + jvms[j].toString() + " ";
+                if (!jvms[j].matches(versions[v])) {
+                    debugOutput += "!";
+                }
+                debugOutput += "matches " + versions[v].toString();
+                ServerAccess.logOutputReprint(debugOutput);
+                Assert.assertEquals(results[i - 1], jvms[j].matches(versions[v]));
+            }
+        }
+
+
+    }
+}
--- a/tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java	Thu May 02 15:55:51 2013 +0200
+++ b/tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java	Thu May 02 16:05:57 2013 +0200
@@ -1,54 +1,70 @@
 /* ResourceTrackerTest.java
-Copyright (C) 2012 Red Hat, Inc.
+ Copyright (C) 2012 Red Hat, Inc.
 
-This file is part of IcedTea.
+ This file is part of IcedTea.
 
-IcedTea is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License as published by
-the Free Software Foundation, version 2.
+ IcedTea is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2.
 
-IcedTea 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 for more details.
+ IcedTea 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 for more details.
 
-You should have received a copy of the GNU General Public License
-along with IcedTea; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
 
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library.  Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
 
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module.  An independent module is a module which is not derived from
-or based on this library.  If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so.  If you do not wish to do so, delete this
-exception statement from your version.
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
  */
 package net.sourceforge.jnlp.cache;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
 import java.net.URL;
-
+import java.util.HashMap;
+import net.sourceforge.jnlp.ServerAccess;
+import net.sourceforge.jnlp.ServerLauncher;
+import net.sourceforge.jnlp.Version;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.util.UrlUtils;
-
+import org.junit.AfterClass;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
-/** Test various corner cases of the parser */
 public class ResourceTrackerTest {
 
+    public static ServerLauncher testServer;
+    public static ServerLauncher testServerWithBrokenHead;
+    private static PrintStream backedUpStream;
+    private static ByteArrayOutputStream currentErrorStream;
+    private static final String nameStub1 = "itw-server";
+    private static final String nameStub2 = "test-file";
+
     @Test
     public void testNormalizeUrl() throws Exception {
         URL[] u = getUrls();
@@ -58,13 +74,12 @@
         Assert.assertNull("first url should be null", u[0]);
         Assert.assertNull("first normalized url should be null", n[0]);
         for (int i = 1; i < CHANGE_BORDER; i++) {
-            Assert.assertTrue("url " + i + " must be equals too normlaized url " + i, u[i].equals(n[i]));
+            Assert.assertTrue("url " + i + " must be equals too normalized url " + i, u[i].equals(n[i]));
         }
         for (int i = CHANGE_BORDER; i < n.length; i++) {
-            Assert.assertFalse("url " + i + " must be normalized (and so not equals) too normlaized url " + i, u[i].equals(n[i]));
+            Assert.assertFalse("url " + i + " must be normalized (and so not equals) too normalized url " + i, u[i].equals(n[i]));
         }
     }
-
     public static final int CHANGE_BORDER = 6;
 
     public static URL[] getUrls() throws MalformedURLException {
@@ -97,4 +112,229 @@
         return n;
 
     }
+  
+    @BeforeClass
+    public static void redirectErr() {
+        if (backedUpStream == null) {
+            backedUpStream = System.err;
+        }
+        currentErrorStream = new ByteArrayOutputStream();
+        System.setErr(new PrintStream(currentErrorStream));
+
+    }
+
+    @AfterClass
+    public static void redirectErrBack() throws UnsupportedEncodingException {
+        ServerAccess.logErrorReprint(currentErrorStream.toString("utf-8"));
+        System.setErr(backedUpStream);
+
+    }
+
+    @BeforeClass
+    public static void onDebug() {
+        JNLPRuntime.setDebug(true);
+    }
+
+    @AfterClass
+    public static void offDebug() {
+        JNLPRuntime.setDebug(false);
+    }
+
+    @BeforeClass
+    public static void startServer() throws IOException {
+        testServer = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort());
+    }
+
+    @BeforeClass
+    public static void startServer2() throws IOException {
+        testServerWithBrokenHead = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort());
+        testServerWithBrokenHead.setSupportingHeadRequest(false);
+    }
+
+    @AfterClass
+    public static void stopServer() {
+        testServer.stop();
+    }
+
+    @AfterClass
+    public static void stopServer2() {
+        testServerWithBrokenHead.stop();
+    }
+
+    @Test
+    public void getUrlResponseCodeTestWorkingHeadRequest() throws IOException {
+        redirectErr();
+        try {
+            File f = File.createTempFile(nameStub1, nameStub2);
+            int i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "HEAD");
+            Assert.assertEquals(HttpURLConnection.HTTP_OK, i);
+            f.delete();
+            i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "HEAD");
+            Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i);
+        } finally {
+            redirectErrBack();
+        }
+    }
+
+    @Test
+    public void getUrlResponseCodeTestNotWorkingHeadRequest() throws IOException {
+        redirectErr();
+        try {
+            File f = File.createTempFile(nameStub1, nameStub2);
+            int i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), "HEAD");
+            Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i);
+            f.delete();
+            i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), "HEAD");
+            Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i);
+        } finally {
+            redirectErrBack();
+        }
+    }
+
+    @Test
+    public void getUrlResponseCodeTestGetRequestOnNotWorkingHeadRequest() throws IOException {
+        redirectErr();
+        try {
+            File f = File.createTempFile(nameStub1, nameStub2);
+            int i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), "GET");
+            Assert.assertEquals(HttpURLConnection.HTTP_OK, i);
+            f.delete();
+            i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), "GET");
+            Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i);
+        } finally {
+            redirectErrBack();
+        }
+    }
+
+    @Test
+    public void getUrlResponseCodeTestGetRequest() throws IOException {
+        redirectErr();
+        try {
+            File f = File.createTempFile(nameStub1, nameStub2);
+            int i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "GET");
+            Assert.assertEquals(HttpURLConnection.HTTP_OK, i);
+            f.delete();
+            i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "GET");
+            Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i);
+        } finally {
+            redirectErrBack();
+        }
+    }
+
+    @Test
+    public void getUrlResponseCodeTestWrongRequest() throws IOException {
+        redirectErr();
+        try {
+            File f = File.createTempFile(nameStub1, nameStub2);
+            Exception exception = null;
+            try {
+                ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "SomethingWrong");
+            } catch (Exception ex) {
+                exception = ex;
+            }
+            Assert.assertNotNull(exception);
+            exception = null;
+            f.delete();
+            try {
+                ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), "SomethingWrong");
+            } catch (Exception ex) {
+                exception = ex;
+            }
+            Assert.assertNotNull(exception);;
+        } finally {
+            redirectErrBack();
+        }
+
+    }
+
+    @Test
+    public void findBestUrltest() throws IOException {
+        redirectErr();
+        try {
+            File fileForServerWithHeader = File.createTempFile(nameStub1, nameStub2);
+            File versionedFileForServerWithHeader = new File(fileForServerWithHeader.getParentFile(), fileForServerWithHeader.getName() + "-2.0");
+            versionedFileForServerWithHeader.createNewFile();
+
+            File fileForServerWithoutHeader = File.createTempFile(nameStub1, nameStub2);
+            File versionedFileForServerWithoutHeader = new File(fileForServerWithoutHeader.getParentFile(), fileForServerWithoutHeader.getName() + "-2.0");
+            versionedFileForServerWithoutHeader.createNewFile();
+
+            ResourceTracker rt = new ResourceTracker();
+            Resource r1 = Resource.getResource(testServer.getUrl(fileForServerWithHeader.getName()), null, UpdatePolicy.NEVER);
+            Resource r2 = Resource.getResource(testServerWithBrokenHead.getUrl(fileForServerWithoutHeader.getName()), null, UpdatePolicy.NEVER);
+            Resource r3 = Resource.getResource(testServer.getUrl(versionedFileForServerWithHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER);
+            Resource r4 = Resource.getResource(testServerWithBrokenHead.getUrl(versionedFileForServerWithoutHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER);
+            assertOnServerWithHeader(rt.findBestUrl(r1));
+            assertVersionedOneOnServerWithHeader(rt.findBestUrl(r3));
+            assertOnServerWithoutHeader(rt.findBestUrl(r2));
+            assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4));
+
+            fileForServerWithHeader.delete();
+            Assert.assertNull(rt.findBestUrl(r1));
+            assertVersionedOneOnServerWithHeader(rt.findBestUrl(r3));
+            assertOnServerWithoutHeader(rt.findBestUrl(r2));
+            assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4));
+
+            versionedFileForServerWithHeader.delete();
+            Assert.assertNull(rt.findBestUrl(r1));
+            Assert.assertNull(rt.findBestUrl(r3));
+            assertOnServerWithoutHeader(rt.findBestUrl(r2));
+            assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4));
+
+            versionedFileForServerWithoutHeader.delete();
+            Assert.assertNull(rt.findBestUrl(r1));
+            Assert.assertNull(rt.findBestUrl(r3));
+            assertOnServerWithoutHeader(rt.findBestUrl(r2));
+            Assert.assertNull(rt.findBestUrl(r4));
+
+
+            fileForServerWithoutHeader.delete();
+            Assert.assertNull(rt.findBestUrl(r1));
+            Assert.assertNull(rt.findBestUrl(r3));
+            Assert.assertNull(rt.findBestUrl(r2));
+            Assert.assertNull(rt.findBestUrl(r4));
+        } finally {
+            redirectErrBack();
+        }
+
+    }
+
+    private void assertOnServerWithHeader(URL u) {
+        assertCommonComponentsOfUrl(u);
+        assertPort(u, testServer.getPort());
+    }
+
+    private void assertVersionedOneOnServerWithHeader(URL u) {
+        assertCommonComponentsOfUrl(u);
+        assertPort(u, testServer.getPort());
+        assertVersion(u);
+    }
+
+    private void assertOnServerWithoutHeader(URL u) {
+        assertCommonComponentsOfUrl(u);
+        assertPort(u, testServerWithBrokenHead.getPort());
+    }
+
+    private void assertVersionedOneOnServerWithoutHeader(URL u) {
+        assertCommonComponentsOfUrl(u);
+        assertPort(u, testServerWithBrokenHead.getPort());
+        assertVersion(u);
+    }
+
+    private void assertCommonComponentsOfUrl(URL u) {
+        Assert.assertTrue(u.getProtocol().equals("http"));
+        Assert.assertTrue(u.getHost().equals("localhost"));
+        Assert.assertTrue(u.getPath().contains(nameStub1));
+        Assert.assertTrue(u.getPath().contains(nameStub2));
+        ServerAccess.logOutputReprint(u.toExternalForm());
+    }
+
+    private void assertPort(URL u, int port) {
+        Assert.assertTrue(u.getPort() == port);
+    }
+
+    private void assertVersion(URL u) {
+        Assert.assertTrue(u.getPath().contains("-2.0"));
+        Assert.assertTrue(u.getQuery().contains("version-id=1.0"));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/netx/unit/net/sourceforge/jnlp/util/HttpUtilsTest.java	Thu May 02 16:05:57 2013 +0200
@@ -0,0 +1,248 @@
+/*
+ Copyright (C) 2012 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ IcedTea 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+package net.sourceforge.jnlp.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import net.sourceforge.jnlp.ServerAccess;
+import net.sourceforge.jnlp.ServerLauncher;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpUtilsTest {
+    
+    private static PrintStream backedUpStream;
+    private static ByteArrayOutputStream nwErrorStream;
+     
+    public static void redirectErr() {
+        if (backedUpStream == null) {
+            backedUpStream = System.err;
+        }
+        nwErrorStream = new ByteArrayOutputStream();
+        System.setErr(new PrintStream(nwErrorStream));
+
+    }
+
+    
+    public static void redirectErrBack() throws UnsupportedEncodingException {
+        ServerAccess.logErrorReprint(nwErrorStream.toString("utf-8"));
+        System.setErr(backedUpStream);
+
+    }
+
+    @Test
+    public void consumeAndCloseConnectionSilentlyTest() throws IOException {
+        redirectErr();
+        try{
+        Exception exception = null;
+        try {
+            HttpUtils.consumeAndCloseConnectionSilently(new HttpURLConnection(null) {
+                @Override
+                public void disconnect() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public void connect() throws IOException {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNull("no exception expected - was" + exception, exception);
+
+
+
+        try {
+            HttpUtils.consumeAndCloseConnectionSilently(new HttpURLConnection(new URL("http://localhost/blahblah")) {
+                @Override
+                public void disconnect() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public void connect() throws IOException {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNull("no exception expected - was" + exception, exception);
+        
+        ServerLauncher serverLauncher =ServerAccess.getIndependentInstance(System.getProperty("user.dir"), ServerAccess.findFreePort());
+        try{
+                try {
+            HttpUtils.consumeAndCloseConnectionSilently(new HttpURLConnection(serverLauncher.getUrl("definitelyNotExisitnfFileInHappyMemoryOfAdam")) { //:)
+                @Override
+                public void disconnect() {
+                   
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    return false;
+                }
+
+                @Override
+                public void connect() throws IOException {
+                   
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNull("no exception expected - was" + exception, exception);
+        }finally{
+            try{
+            serverLauncher.stop();
+            }catch(Exception ex){
+                ServerAccess.logException(ex);
+            }
+        }
+        }finally{
+            redirectErrBack();
+        }
+    }
+    
+    @Test
+    public void consumeAndCloseConnectionTest() throws IOException {
+        redirectErr();
+        try{
+        Exception exception = null;
+        try {
+            HttpUtils.consumeAndCloseConnection(new HttpURLConnection(null) {
+                @Override
+                public void disconnect() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public void connect() throws IOException {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNotNull("exception expected - wasnt" + exception, exception);
+
+
+
+        try {
+            HttpUtils.consumeAndCloseConnection(new HttpURLConnection(new URL("http://localhost/blahblah")) {
+                @Override
+                public void disconnect() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+
+                @Override
+                public void connect() throws IOException {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNotNull("exception expected - wasnt" + exception, exception);
+        
+        ServerLauncher s =ServerAccess.getIndependentInstance(System.getProperty("user.dir"), ServerAccess.findFreePort());
+        try{
+                try {
+            HttpUtils.consumeAndCloseConnection(new HttpURLConnection(s.getUrl("blahblahblah")) {
+                @Override
+                public void disconnect() {
+                   
+                }
+
+                @Override
+                public boolean usingProxy() {
+                    return false;
+                }
+
+                @Override
+                public void connect() throws IOException {
+                   
+                }
+            });
+        } catch (Exception ex) {
+            ServerAccess.logException(ex);
+            exception = ex;
+        }
+        Assert.assertNotNull(" exception expected - wasnt" + exception, exception);
+        }finally{
+            try{
+            s.stop();
+            }catch(Exception ex){
+                ServerAccess.logException(ex);
+            }
+        }
+        }finally{
+            redirectErrBack();
+        }
+    }
+}
--- a/tests/netx/unit/net/sourceforge/jnlp/util/UrlUtilsTest.java	Thu May 02 15:55:51 2013 +0200
+++ b/tests/netx/unit/net/sourceforge/jnlp/util/UrlUtilsTest.java	Thu May 02 16:05:57 2013 +0200
@@ -1,3 +1,40 @@
+/*
+   Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
 package net.sourceforge.jnlp.util;
 
 import static org.junit.Assert.assertEquals;
--- a/tests/test-extensions/net/sourceforge/jnlp/ServerLauncher.java	Thu May 02 15:55:51 2013 +0200
+++ b/tests/test-extensions/net/sourceforge/jnlp/ServerLauncher.java	Thu May 02 16:05:57 2013 +0200
@@ -57,7 +57,18 @@
     private final Integer port;
     private final File dir;
     private ServerSocket serverSocket;
+    private boolean supportingHeadRequest = true;
 
+    public void setSupportingHeadRequest(boolean supportsHead) {
+        this.supportingHeadRequest = supportsHead;
+    }
+
+    public boolean isSupportingHeadRequest() {
+        return supportingHeadRequest;
+    }
+
+    
+    
     public String getServerName() {
         return serverName;
     }
@@ -102,10 +113,12 @@
         try {
             serverSocket = new ServerSocket(port);
             while (running) {
-                new TinyHttpdImpl(serverSocket.accept(), dir, port);
+                TinyHttpdImpl server = new TinyHttpdImpl(serverSocket.accept(), dir, port,false);
+                server.setSupportingHeadRequest(isSupportingHeadRequest());
+                server.start();
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            ServerAccess.logException(e);
         } finally {
             running = false;
         }
--- a/tests/test-extensions/net/sourceforge/jnlp/TinyHttpdImpl.java	Thu May 02 15:55:51 2013 +0200
+++ b/tests/test-extensions/net/sourceforge/jnlp/TinyHttpdImpl.java	Thu May 02 16:05:57 2013 +0200
@@ -42,6 +42,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
 import java.net.Socket;
 import java.net.SocketException;
 import java.net.URLDecoder;
@@ -55,25 +56,41 @@
  * When resource starts with XslowX prefix, then resouce (without XslowX)
  * is returned, but its delivery is delayed
  */
-class TinyHttpdImpl extends Thread {
+public class TinyHttpdImpl extends Thread {
 
     Socket c;
     private final File dir;
     private final int port;
     private boolean canRun = true;
     private static final String XSX = "/XslowX";
-
+    private boolean supportingHeadRequest = true;
+    
     public TinyHttpdImpl(Socket s, File f, int port) {
+        this(s, f, port, true);
+    }
+    public TinyHttpdImpl(Socket s, File f, int port, boolean start) {
         c = s;
         this.dir = f;
         this.port = port;
-        start();
+        if (start){
+            start();
+        }
     }
 
     public void setCanRun(boolean canRun) {
         this.canRun = canRun;
     }
 
+    public void setSupportingHeadRequest(boolean supportsHead) {
+        this.supportingHeadRequest = supportsHead;
+    }
+
+    public boolean isSupportingHeadRequest() {
+        return supportingHeadRequest;
+    }
+    
+    
+
     public int getPort() {
         return port;
     }
@@ -92,6 +109,11 @@
 
                     boolean isGetRequest = s.startsWith("GET");
                     boolean isHeadRequest = s.startsWith("HEAD");
+                    
+                    if (isHeadRequest && !isSupportingHeadRequest()){
+                        o.writeBytes("HTTP/1.0 "+HttpURLConnection.HTTP_NOT_IMPLEMENTED+" Not Implemented\n");
+                        continue;
+                    }
 
                     if (isGetRequest || isHeadRequest ) {
                         StringTokenizer t = new StringTokenizer(s, " ");
@@ -120,7 +142,7 @@
                         } else if (p.toLowerCase().endsWith(".jar")) {
                             content = ct + "application/x-jar\n";
                         }
-                        o.writeBytes("HTTP/1.0 200 OK\nContent-Length:" + l + "\n" + content + "\n");
+                        o.writeBytes("HTTP/1.0 "+HttpURLConnection.HTTP_OK+" OK\nContent-Length:" + l + "\n" + content + "\n");
 
                         if (isHeadRequest) {
                             continue; // Skip sending body