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 2009/07/16 23:30:39 UTC

svn commit: r794870 - in /httpcomponents/httpclient/trunk: ./ httpclient/src/main/java/org/apache/http/client/utils/ httpclient/src/test/java/org/apache/http/client/utils/

Author: olegk
Date: Thu Jul 16 21:30:38 2009
New Revision: 794870

URL: http://svn.apache.org/viewvc?rev=794870&view=rev
Log:
HTTPCLIENT-861: URI reference resolution fails examples in RFC 3986

Added:
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java   (with props)
Modified:
    httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java

Modified: httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/RELEASE_NOTES.txt?rev=794870&r1=794869&r2=794870&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/trunk/RELEASE_NOTES.txt Thu Jul 16 21:30:38 2009
@@ -47,21 +47,25 @@
   Some protected variables in connection management class have been
   made final in order to help ensure their thread safety: 
 
-	org.apache.http.conn.BasicEofSensorWatcher#attemptReuse
-	org.apache.http.conn.BasicEofSensorWatcher#managedConn
-	org.apache.http.impl.conn.DefaultClientConnectionOperator#schemeRegistry
-	org.apache.http.impl.conn.DefaultHttpRoutePlanner#schemeRegistry
-	org.apache.http.impl.conn.ProxySelectorRoutePlanner#schemeRegistry
-	org.apache.http.impl.conn.SingleClientConnManager#alwaysShutDown
-	org.apache.http.impl.conn.SingleClientConnManager#connOperator
-	org.apache.http.impl.conn.SingleClientConnManager#schemeRegistry
-	org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager#connOperator
-	org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager#schemeRegistry
-	
+    org.apache.http.conn.BasicEofSensorWatcher#attemptReuse
+    org.apache.http.conn.BasicEofSensorWatcher#managedConn
+    org.apache.http.impl.conn.DefaultClientConnectionOperator#schemeRegistry
+    org.apache.http.impl.conn.DefaultHttpRoutePlanner#schemeRegistry
+    org.apache.http.impl.conn.ProxySelectorRoutePlanner#schemeRegistry
+    org.apache.http.impl.conn.SingleClientConnManager#alwaysShutDown
+    org.apache.http.impl.conn.SingleClientConnManager#connOperator
+    org.apache.http.impl.conn.SingleClientConnManager#schemeRegistry
+    org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager#connOperator
+    org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager#schemeRegistry
+    
 
 Bug fixes since 4.0 BETA2 release 
 -------------------
 
+* [HTTPCLIENT-861] URIUtils#resolve is now compatible with all examples given 
+  in RFC 3986.
+  Contributed by Johannes Koch <johannes.koch at fit.fraunhofer.de>
+
 * [HTTPCLIENT-860] HttpClient no longer converts redirects of PUT/POST to GET 
   for status codes 301, 302, 307, as required by the HTTP spec.
   Contributed by Oleg Kalnichevski <olegk at apache.org>
@@ -153,85 +157,6 @@
   Contributed by Oleg Kalnichevski <olegk at apache.org>
 
 
-HttpClient API changes (generated by JarDiff 0.2)
---------------------------------------
-Class changed: org.apache.http.conn.scheme.PlainSocketFactory
-  Methods removed:
-    public boolean equals(java.lang.Object);
-    public int hashCode();
-
-Class changed: org.apache.http.conn.ssl.AbstractVerifier
-  Method changed:
-  old:
-    public final boolean verify(java.lang.String, javax.net.ssl.SSLSession);
-
-  new:
-    deprecated: public final boolean verify(java.lang.String, javax.net.ssl.SSLSession);
-
-Class changed: org.apache.http.impl.conn.tsccm.BasicPoolEntry
-  Methods added:
-    protected void shutdownEntry();
-
-Class changed: org.apache.http.impl.cookie.RFC2965Spec
-  Methods added:
-    protected java.util.List parse(org.apache.http.HeaderElement[], org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-
-API diff generated by JarDiff http://www.osjava.org/jardiff/
-
-HttpMime API changes (generated by JarDiff 0.2)
---------------------------------------
-Class added: 
-  public org.apache.http.entity.mime.UnexpectedMimeException extends java.lang.RuntimeException
-Class added: 
-  public abstract org.apache.http.entity.mime.content.AbstractContentBody extends org.apache.james.mime4j.message.AbstractBody implements org.apache.http.entity.mime.content.ContentBody
-Class changed: org.apache.http.entity.mime.content.FileBody
-  Methods removed:
-    public java.util.Map getContentTypeParameters();
-    public java.lang.String getMediaType();
-    public java.lang.String getMimeType();
-    public java.lang.String getSubType();
-
-  Methods added:
-    public FileBody(java.io.File, java.lang.String);
-
-  Class descriptor changed:
-  old:
-    public org.apache.http.entity.mime.content.FileBody extends org.apache.james.mime4j.message.AbstractBody implements org.apache.james.mime4j.message.BinaryBody, org.apache.http.entity.mime.content.ContentBody
-  new:
-    public org.apache.http.entity.mime.content.FileBody extends org.apache.http.entity.mime.content.AbstractContentBody implements org.apache.james.mime4j.message.BinaryBody
-Class changed: org.apache.http.entity.mime.content.InputStreamBody
-  Methods removed:
-    public java.util.Map getContentTypeParameters();
-    public java.lang.String getMediaType();
-    public java.lang.String getMimeType();
-    public java.lang.String getSubType();
-
-  Methods added:
-    public InputStreamBody(java.io.InputStream, java.lang.String, java.lang.String);
-
-  Class descriptor changed:
-  old:
-    public org.apache.http.entity.mime.content.InputStreamBody extends org.apache.james.mime4j.message.AbstractBody implements org.apache.james.mime4j.message.BinaryBody, org.apache.http.entity.mime.content.ContentBody
-  new:
-    public org.apache.http.entity.mime.content.InputStreamBody extends org.apache.http.entity.mime.content.AbstractContentBody implements org.apache.james.mime4j.message.BinaryBody
-Class changed: org.apache.http.entity.mime.content.StringBody
-  Methods removed:
-    public java.lang.String getMediaType();
-    public java.lang.String getMimeType();
-    public java.lang.String getSubType();
-
-  Methods added:
-    public StringBody(java.lang.String, java.lang.String, java.nio.charset.Charset) throws java.io.UnsupportedEncodingException;
-
-  Class descriptor changed:
-  old:
-    public org.apache.http.entity.mime.content.StringBody extends org.apache.james.mime4j.message.AbstractBody implements org.apache.james.mime4j.message.TextBody, org.apache.http.entity.mime.content.ContentBody
-  new:
-    public org.apache.http.entity.mime.content.StringBody extends org.apache.http.entity.mime.content.AbstractContentBody implements org.apache.james.mime4j.message.TextBody
-API diff generated by JarDiff http://www.osjava.org/jardiff/
-
---------------------------------------
-
 4.0 Beta 1
 -------------------
 

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java?rev=794870&r1=794869&r2=794870&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java Thu Jul 16 21:30:38 2009
@@ -28,6 +28,7 @@
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.Stack;
 
 import net.jcip.annotations.Immutable;
 
@@ -171,8 +172,8 @@
     }
 
     /**
-     * Resolves a URI reference against a base URI. Work-around for bug in
-     * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+     * Resolves a URI reference against a base URI. Work-around for bugs in
+     * java.net.URI (e.g. <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
      *
      * @param baseURI the base URI
      * @param reference the URI reference
@@ -185,7 +186,11 @@
         if (reference == null) {
             throw new IllegalArgumentException("Reference URI may nor be null");
         }
-        boolean emptyReference = reference.toString().length() == 0;
+        String s = reference.toString();
+        if (s.startsWith("?")) {
+            return resolveReferenceStartingWithQueryString(baseURI, reference);
+        }
+        boolean emptyReference = s.length() == 0;
         if (emptyReference) {
             reference = URI.create("#");
         }
@@ -195,7 +200,60 @@
             resolved = URI.create(resolvedString.substring(0,
                 resolvedString.indexOf('#')));
         }
-        return resolved;
+        return removeDotSegments(resolved);
+    }
+
+    /**
+     * Resolves a reference starting with a query string.
+     * 
+     * @param baseURI the base URI
+     * @param reference the URI reference starting with a query string
+     * @return the resulting URI
+     */
+    private static URI resolveReferenceStartingWithQueryString(
+            final URI baseURI, final URI reference) {
+        String baseUri = baseURI.toString();
+        baseUri = baseUri.indexOf('?') > -1 ?
+            baseUri.substring(0, baseUri.indexOf('?')) : baseUri;
+        return URI.create(baseUri + reference.toString());
+    }
+
+    /**
+     * Removes dot segments according to RFC 3986, section 5.2.4
+     * 
+     * @param uri the original URI
+     * @return the URI without dot segments
+     */
+    private static URI removeDotSegments(URI uri) {
+        String path = uri.getPath();
+        if ((path == null) || (path.indexOf("/.") == -1)) {
+            // No dot segments to remove
+            return uri;
+        }
+        String[] inputSegments = path.split("/");
+        Stack<String> outputSegments = new Stack<String>();
+        for (int i = 0; i < inputSegments.length; i++) {
+            if ((inputSegments[i].length() == 0)
+                || (".".equals(inputSegments[i]))) {
+                // Do nothing
+            } else if ("..".equals(inputSegments[i])) {
+                if (!outputSegments.isEmpty()) {
+                    outputSegments.pop();
+                }
+            } else {
+                outputSegments.push(inputSegments[i]);
+            }
+        }
+        StringBuffer outputBuffer = new StringBuffer();
+        for (String outputSegment : outputSegments) {
+            outputBuffer.append('/').append(outputSegment);
+        }
+        try {
+            return new URI(uri.getScheme(), uri.getAuthority(),
+                outputBuffer.toString(), uri.getQuery(), uri.getFragment());
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java?rev=794870&r1=794869&r2=794870&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java Thu Jul 16 21:30:38 2009
@@ -1,8 +1,4 @@
 /*
- * $HeadURL$
- * $Revision$
- * $Date$
- *
  * ====================================================================
  *
  *  Licensed to the Apache Software Foundation (ASF) under one or more

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java?rev=794870&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java Thu Jul 16 21:30:38 2009
@@ -0,0 +1,251 @@
+/*
+ * ====================================================================
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.client.utils;
+
+import java.net.URI;
+
+import junit.framework.Assert;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * This TestCase contains test methods for URI resolving according to RFC 3986.
+ * The examples are listed in section "5.4 Reference Resolution Examples"
+ */
+public class TestURIUtils extends TestCase {
+
+    private URI baseURI = URI.create("http://a/b/c/d;p?q");
+
+    public TestURIUtils(final String testName) {
+        super(testName);
+    }
+
+    public static void main(String args[]) {
+        String[] testCaseName = { TestURIUtils.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    public static Test suite() {
+        return new TestSuite(TestURIUtils.class);
+    }
+
+    public void testResolve00() {
+        Assert.assertEquals("g:h", URIUtils.resolve(this.baseURI, "g:h").toString());
+    }
+
+    public void testResolve01() {
+        Assert.assertEquals("http://a/b/c/g", URIUtils.resolve(this.baseURI, "g").toString());
+    }
+
+    public void testResolve02() {
+        Assert.assertEquals("http://a/b/c/g", URIUtils.resolve(this.baseURI, "./g").toString());
+    }
+
+    public void testResolve03() {
+        Assert.assertEquals("http://a/b/c/g/", URIUtils.resolve(this.baseURI, "g/").toString());
+    }
+
+    public void testResolve04() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "/g").toString());
+    }
+
+    public void testResolve05() {
+        Assert.assertEquals("http://g", URIUtils.resolve(this.baseURI, "//g").toString());
+    }
+
+    public void testResolve06() {
+        Assert.assertEquals("http://a/b/c/d;p?y", URIUtils.resolve(this.baseURI, "?y").toString());
+    }
+
+    public void testResolve06_() {
+        Assert.assertEquals("http://a/b/c/d;p?y#f", URIUtils.resolve(this.baseURI, "?y#f")
+                .toString());
+    }
+
+    public void testResolve07() {
+        Assert.assertEquals("http://a/b/c/g?y", URIUtils.resolve(this.baseURI, "g?y").toString());
+    }
+
+    public void testResolve08() {
+        Assert
+                .assertEquals("http://a/b/c/d;p?q#s", URIUtils.resolve(this.baseURI, "#s")
+                        .toString());
+    }
+
+    public void testResolve09() {
+        Assert.assertEquals("http://a/b/c/g#s", URIUtils.resolve(this.baseURI, "g#s").toString());
+    }
+
+    public void testResolve10() {
+        Assert.assertEquals("http://a/b/c/g?y#s", URIUtils.resolve(this.baseURI, "g?y#s")
+                .toString());
+    }
+
+    public void testResolve11() {
+        Assert.assertEquals("http://a/b/c/;x", URIUtils.resolve(this.baseURI, ";x").toString());
+    }
+
+    public void testResolve12() {
+        Assert.assertEquals("http://a/b/c/g;x", URIUtils.resolve(this.baseURI, "g;x").toString());
+    }
+
+    public void testResolve13() {
+        Assert.assertEquals("http://a/b/c/g;x?y#s", URIUtils.resolve(this.baseURI, "g;x?y#s")
+                .toString());
+    }
+
+    public void testResolve14() {
+        Assert.assertEquals("http://a/b/c/d;p?q", URIUtils.resolve(this.baseURI, "").toString());
+    }
+
+    public void testResolve15() {
+        Assert.assertEquals("http://a/b/c/", URIUtils.resolve(this.baseURI, ".").toString());
+    }
+
+    public void testResolve16() {
+        Assert.assertEquals("http://a/b/c/", URIUtils.resolve(this.baseURI, "./").toString());
+    }
+
+    public void testResolve17() {
+        Assert.assertEquals("http://a/b/", URIUtils.resolve(this.baseURI, "..").toString());
+    }
+
+    public void testResolve18() {
+        Assert.assertEquals("http://a/b/", URIUtils.resolve(this.baseURI, "../").toString());
+    }
+
+    public void testResolve19() {
+        Assert.assertEquals("http://a/b/g", URIUtils.resolve(this.baseURI, "../g").toString());
+    }
+
+    public void testResolve20() {
+        Assert.assertEquals("http://a/", URIUtils.resolve(this.baseURI, "../..").toString());
+    }
+
+    public void testResolve21() {
+        Assert.assertEquals("http://a/", URIUtils.resolve(this.baseURI, "../../").toString());
+    }
+
+    public void testResolve22() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "../../g").toString());
+    }
+
+    public void testResolveAbnormal23() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "../../../g").toString());
+    }
+
+    public void testResolveAbnormal24() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "../../../../g")
+                .toString());
+    }
+
+    public void testResolve25() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "/./g").toString());
+    }
+
+    public void testResolve26() {
+        Assert.assertEquals("http://a/g", URIUtils.resolve(this.baseURI, "/../g").toString());
+    }
+
+    public void testResolve27() {
+        Assert.assertEquals("http://a/b/c/g.", URIUtils.resolve(this.baseURI, "g.").toString());
+    }
+
+    public void testResolve28() {
+        Assert.assertEquals("http://a/b/c/.g", URIUtils.resolve(this.baseURI, ".g").toString());
+    }
+
+    public void testResolve29() {
+        Assert.assertEquals("http://a/b/c/g..", URIUtils.resolve(this.baseURI, "g..").toString());
+    }
+
+    public void testResolve30() {
+        Assert.assertEquals("http://a/b/c/..g", URIUtils.resolve(this.baseURI, "..g").toString());
+    }
+
+    public void testResolve31() {
+        Assert.assertEquals("http://a/b/g", URIUtils.resolve(this.baseURI, "./../g").toString());
+    }
+
+    public void testResolve32() {
+        Assert.assertEquals("http://a/b/c/g/", URIUtils.resolve(this.baseURI, "./g/.").toString());
+    }
+
+    public void testResolve33() {
+        Assert.assertEquals("http://a/b/c/g/h", URIUtils.resolve(this.baseURI, "g/./h").toString());
+    }
+
+    public void testResolve34() {
+        Assert.assertEquals("http://a/b/c/h", URIUtils.resolve(this.baseURI, "g/../h").toString());
+    }
+
+    public void testResolve35() {
+        Assert.assertEquals("http://a/b/c/g;x=1/y", URIUtils.resolve(this.baseURI, "g;x=1/./y")
+                .toString());
+    }
+
+    public void testResolve36() {
+        Assert.assertEquals("http://a/b/c/y", URIUtils.resolve(this.baseURI, "g;x=1/../y")
+                .toString());
+    }
+
+    public void testResolve37() {
+        Assert.assertEquals("http://a/b/c/g?y/./x", URIUtils.resolve(this.baseURI, "g?y/./x")
+                .toString());
+    }
+
+    public void testResolve38() {
+        Assert.assertEquals("http://a/b/c/g?y/../x", URIUtils.resolve(this.baseURI, "g?y/../x")
+                .toString());
+    }
+
+    public void testResolve39() {
+        Assert.assertEquals("http://a/b/c/g#s/./x", URIUtils.resolve(this.baseURI, "g#s/./x")
+                .toString());
+    }
+
+    public void testResolve40() {
+        Assert.assertEquals("http://a/b/c/g#s/../x", URIUtils.resolve(this.baseURI, "g#s/../x")
+                .toString());
+    }
+
+    public void testResolve41() {
+        Assert.assertEquals("http:g", URIUtils.resolve(this.baseURI, "http:g").toString());
+    }
+
+    // examples from section 5.2.4
+    public void testResolve42() {
+        Assert.assertEquals("http://s/a/g", URIUtils.resolve(this.baseURI,
+                "http://s/a/b/c/./../../g").toString());
+    }
+
+    public void testResolve43() {
+        Assert.assertEquals("http://s/mid/6", URIUtils.resolve(this.baseURI,
+                "http://s/mid/content=5/../6").toString());
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain