16

HttpURLConnection.getInputStream() gives UnknownLengthHttpInputStream and due to this Document parsing throws SAX parser exception.

Following is the code

try{
    URL url = new URL(uri);
    HttpURLConnection connection =
    (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setRequestProperty("Accept", "application/xml");

    InputStream xml = connection.getInputStream();
    System.out.println(connection.getResponseCode());
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(connection.getInputStream());
    doc.getDocumentElement().normalize();

}catch(Exception e){
    e.printStackTrace();
}

Any one knows the reason for UnknownLengthHttpInputStream. I'm getting this error only in android and this code works perfectly in Java Project.

Following is the exception from LogCat:

08-08 11:07:40.490: W/System.err(1493): org.xml.sax.SAXParseException: Unexpected end of document
08-08 11:07:40.504: W/System.err(1493): at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:129)
08-08 11:07:40.510: W/System.err(1493): at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:107)
08-08 11:07:40.510: W/System.err(1493): at com.example.testws.MainActivity.onCreate(MainActivity.java:59)
08-08 11:07:40.520: W/System.err(1493): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-08 11:07:40.530: W/System.err(1493): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)

Thanks in advance.

13
  • 1
    Attach the exception from logcat? Commented Aug 8, 2012 at 7:18
  • @Jens I have attached the exception from logcat.. Commented Aug 8, 2012 at 10:37
  • 3
    you get the UnknownLengthHttpInputStream stream because your server isn't supplying a Content-Length or using chunked transfer encoding. When the server does not supply either it must signal the end of the HTTP body by closing the connection - which it appears to do mid-document in this case. Do you have any possibility to sniff the web server traffic when performing this call (e.g. using WireShark)? Commented Aug 8, 2012 at 10:42
  • 1
    Try printing 'xml' variable immediately after assigning value to it. Does it prints response on console or generates error? Commented Aug 8, 2012 at 11:19
  • 1
    For SOAP calls try to use KSoap2 instead HTTP calls Commented Aug 10, 2012 at 10:02

6 Answers 6

3

Its probably a Http 1.0 (old server or misconfiguration) server or no keep alive configured. In this case the length of the stream is known at the time the connection is closed from the server. Try specifying http1.1 and keep-alive in your request header (some googling will help on that). Only if the content length attribute is specified in the server response, you'll know the stream length in advance.

Workaround: read the http stream into a ByteBufferStream completely (until read() returns -1). Then throw the ByteBufferInputStream to your library (length is known now)

Sign up to request clarification or add additional context in comments.

Comments

0

Have you tried to use the apache libraries for this? I would suggest the following:

try {
        HttpClient client = new DefaultHttpClient();  
        String getURL = "http://www.google.com";
        HttpGet get = new HttpGet(getURL);
        HttpResponse responseGet = client.execute(get);  
        HttpEntity resEntityGet = responseGet.getEntity();  
        if (resEntityGet != null) {  
                    //do something with the response
                    Log.i("GET RESPONSE",EntityUtils.toString(resEntityGet));
                }
} catch (Exception e) {
    e.printStackTrace();
}

and then get the stream for the HttpEntity itself. Smth like:

InputStream st = entity.getContent();

More examples here: http://www.softwarepassion.com/android-series-get-post-and-multipart-post-requests/

Comments

0

To handle response use this method it will take care of all !!

public static ResponseHandler<String> getResponseHandlerInstance(final Handler handler) {
      final ResponseHandler<String> responseHandler = new ResponseHandler<String>() {

         public String handleResponse(final HttpResponse response) {
            Message message = handler.obtainMessage();
            Bundle bundle = new Bundle();
            StatusLine status = response.getStatusLine();
            Log.d(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " statusCode - " + status.getStatusCode());
            Log.d(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " statusReasonPhrase - " + status.getReasonPhrase());
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
               try {
                  result = HTTPRequestHelper.inputStreamToString(entity.getContent());
                  bundle.putString("RESPONSE", result);
                  message.setData(bundle);
                  handler.sendMessage(message);
               } catch (IOException e) {
                  Log.e(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG, e);
                  bundle.putString("RESPONSE", "Error - " + e.getMessage());
                  message.setData(bundle);
                  handler.sendMessage(message);
               }
            } else {
               Log.w(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " empty response entity, HTTP error occurred");
               bundle.putString("RESPONSE", "Error - " + response.getStatusLine().getReasonPhrase());
               message.setData(bundle);
               handler.sendMessage(message);
            }
            return result;
         }
      };
      return responseHandler;
   }

   private static String inputStreamToString(final InputStream stream) throws IOException {
      BufferedReader br = new BufferedReader(new InputStreamReader(stream));
      StringBuilder sb = new StringBuilder();
      String line = null;
      while ((line = br.readLine()) != null) {
         sb.append(line + "\n");
      }
      br.close();
      return sb.toString();
   }

Comments

0

Once try it like this

if(connection.getResponseCode() ==HttpURLConnection.HTTP_OK){

  InputStream xml = connection.getInputStream();   
  ..........
}else{

//problem in URI/connection .....
}

Comments

0

Here the problem comes when SAX parser could not get the length of InputStream data. To fix this problem, save the contents read from the xml (InputStream) in to a String variable and make an InputStream from the variable for parse method of DocumentBuilder. To do this modify your code as follows :

try {
            URL url = new URL(uri);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Accept", "application/xml");
            InputStream xml = connection.getInputStream();

            DataInputStream dis = new DataInputStream(xml);
            StringBuilder sb = new StringBuilder();
            int asci = dis.read();
            while (asci > 0) {
                sb.append((char) asci);
                asci = dis.read();
            }
            String inputXML = sb.toString();            
            String predefinedXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <EmotionDB></EmotionDB>";
            InputStream inputStream = new ByteArrayInputStream(inputXML.getBytes());//use predefinedXML.getBytes() instead of inputXML.getBytes() for sample test


            System.out.println(connection.getResponseCode());
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(inputStream);
            doc.getDocumentElement().normalize();

        } catch (Exception e) {
            e.printStackTrace();
        }

Here the inputStream will have a correct content length as it is built from a ByteArrayInputStream with a fixed number of bytes.

Comments

-2

You will need to close the output stream properly within the service to avoid this exception. If you are using a third party library then make sure that you have set the response header

Content-Type
Content-Length

If you are using a java service you can get the content-length from method

File.length()

3 Comments

The HTTP Protocol says that you can have a response without a Content-Length header in particular cases : w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 Moreover, you can not always modify the service you're calling because it's not always yours.
What do you suggest then for a solution ?
honestly I think it is because of fixing the request type. by connection.setRequestProperty("Accept", "application/xml"); You may not know how is the URL responding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.