Hi All,

Hope all is well!

Have been experiencing some interesting behaviour with the source resolver
today, and in particular the java.net.HttpURLConnection implementation.

Have a look at this code:

URL url = new URL("http://localhost:8080/something/somewhere/";);
URLConnection conn = url.openConnection();
HttpURLConnection c = (HttpURLConnection) conn;
                        
System.out.println("1." + c.getInputStream());
System.out.println("2." + c.getLastModified());
System.out.println("3." + c.getContentType());
System.out.println("4." + c.getResponseCode());

Assuming that the URL points to a valid server, but a bogus path - then the
following code raises a FileNotFoundException. However, if you move the
call to getInputStream() to be after getResponseCode() then no exception is
raised and and you'll receive a valid InputStream containing the error
page from the server.

This behaviour currently causes the SourceResolver to return server error
pages as valid data when resolving a particular URI. From what I can tell, 
other than examine the content returned, there's currently no easy way to 
tell whether the SourceResolver resolved the document correctly or not.

I've attached a patch that examines the return code of the
HttpURLConnection and throws a SourceException if the code is not within
the valid range of 200-206 as defined by the HTTP RFC. 

This fixes the problem, but prevents people from parsing error pages as
Source objects (if anyone did that before?). Perhaps someone could take a 
look at the patch as maybe there's a better solution? Any ideas? If not 
let me know, and I'll apply the patch attached.

Cheers,

Marcus


-- 
        .....
     ,,$$$$$$$$$,      Marcus Crafter
    ;$'      '$$$$:    Computer Systems Engineer
    $:         $$$$:   ManageSoft GmbH
     $       o_)$$$:   82-84 Mainzer Landstrasse
     ;$,    _/\ &&:'   60327 Frankfurt Germany
       '     /( &&&
           \_&&&&'
          &&&&.
    &&&&&&&:
Index: src/java/org/apache/excalibur/source/impl/URLSource.java
===================================================================
RCS file: 
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/URLSource.java,v
retrieving revision 1.24
diff -u -r1.24 URLSource.java
--- src/java/org/apache/excalibur/source/impl/URLSource.java    4 Apr 2003 16:36:51 
-0000       1.24
+++ src/java/org/apache/excalibur/source/impl/URLSource.java    27 Jun 2003 16:33:57 
-0000
@@ -54,8 +54,10 @@
  */
 package org.apache.excalibur.source.impl;
 
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.lang.reflect.Method;
 import java.net.HttpURLConnection;
 import java.net.URL;
@@ -278,9 +280,77 @@
                 return input;
             }
         }
+        if (m_connection instanceof HttpURLConnection) {
+            validateConnection((HttpURLConnection)m_connection);
+        }
         input = m_connection.getInputStream();
         m_connection = null; // make sure a new m_connection is created next time
         return input;
+    }
+
+    /**
+     * Method which ascertains whether a given [EMAIL PROTECTED] HttpURLConnection} is
+     * able to return valid data or not. 
+     *
+     * <p>Valid return codes from HTTP servers are defined 
+     * <a 
href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2";>here</a>
+     * to be in the range 200-206 (inclusive)</p>
+     *
+     * <p>This method checks that the given connection object has a return code
+     * within this range, and if not, raises a [EMAIL PROTECTED] SourceException} 
with the return
+     * code and any data sent by the server</p>
+     *
+     * @param conn a [EMAIL PROTECTED] HttpURLConnection} instance
+     * @throws SourceException if the request did not succeed
+     * @exception IOException if an error occurs
+     */
+    private void validateConnection(final HttpURLConnection conn) 
+        throws SourceException, IOException {
+        final int responseCode = conn.getResponseCode();
+        final int[] SUCCESS_CODES =
+            {
+                HttpURLConnection.HTTP_OK,
+                HttpURLConnection.HTTP_CREATED,
+                HttpURLConnection.HTTP_ACCEPTED,
+                HttpURLConnection.HTTP_NOT_AUTHORITATIVE,
+                HttpURLConnection.HTTP_NO_CONTENT,
+                HttpURLConnection.HTTP_RESET,
+                HttpURLConnection.HTTP_PARTIAL,
+            };
+
+        for (int i = 0; i < SUCCESS_CODES.length; ++i) {
+            if (responseCode == SUCCESS_CODES[i])
+                return;
+        }
+
+        // response from the server was not successful, return an error to the caller
+        final String responseText = readString(conn.getInputStream());
+
+        throw new SourceException(
+            "Request for " + conn.getURL() + " was unsuccessful " +
+            "(" + responseCode + ")" + ", response from server:\n" + responseText
+        );
+    }
+
+    /**
+     * Helper method to read an [EMAIL PROTECTED] InputStream} into a [EMAIL 
PROTECTED] String}.
+     *
+     * @param stream input [EMAIL PROTECTED] InputStream}
+     * @return a contents in the [EMAIL PROTECTED] InputStream} as a [EMAIL 
PROTECTED] String}
+     * @exception IOException if an error occurs
+     */
+    private String readString(final InputStream stream) throws IOException {
+        final BufferedReader is = 
+            new BufferedReader(new InputStreamReader(stream));
+        String line;
+        StringBuffer resp = new StringBuffer();
+
+        while ((line = is.readLine()) != null) {
+            resp.append(line);
+            resp.append('\n');
+        }
+
+        return resp.toString();
     }
 
     private static boolean checkedURLClass = false;

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to