9

I have struggled with several class implementations to retrieve chunked data without success. Following is a simplified code module that has the problem. After surfing around the web, it appears there have been problems in the past (2009, 2010; ver 1.1, 1.5), but they should be resolved by now. I have not seen any definitive success with Android platform for this protocol.

Help!

I am able to see some response if I put an invalid token -- the web service will respond with an application error message. However, the valid url and token will simply respond with a detection of the chunked protocol (isChunked() returns true), but nothing gets read and nothing times-out, etc.

The exact same URL issued with CURL from a command line works as expected and displays the continuous content (published data from web service).

Are there any web service side hacks e.g., add more end-of-lines, to force the receiving stream??

                URI uri;
                try {
                    uri = new URI("http://cws.mycompany.com/service/events?accesskeyid=8226f3ddc65a420abc391d8f1fe12de44766146762_1298174060748");
                    HttpClient httpClient=new DefaultHttpClient(); 
                    HttpGet httpGet=new HttpGet(uri); 
                    ResponseHandler<String> rh=new BasicResponseHandler(); 
                    String responseString=httpClient.execute(httpGet,rh); 
                    Log.d(TAG, "response as string:\n" + responseString);
                } catch (URISyntaxException e) {
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                } catch (ClientProtocolException e) {
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                } catch (IOException e) {
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                }
mobibob
  • 8,670
  • 20
  • 82
  • 131
  • Why is this such a difficult question to answer? Either it can't be done or there are missing params. – mobibob Feb 21 '11 at 06:24
  • Can I put a bounty on this now, or do I have to wait for it to get stale? BTW - I am trying the AndroidHttpClientConnection class from the Froyo framework. – mobibob Feb 21 '11 at 18:41
  • Are you testing on device or emulator? Are you behind some kind of proxy? See this - it seems to have problems with certain proxies: http://code.google.com/p/android/issues/detail?id=2168 – Peter Knego Feb 28 '11 at 08:53
  • @Peter Knego - thanks for that. I did find that series of articles and pursued that path. I was hoping for a relationship to the device testing or apache version. I am not using the emulator and confirmed that I am not behind a proxy. Meanwhile, I have made progress by using the DefaultHttpClient, I am now getting a stream of data as bytes. It is not being detected as ChunkedInputStream, so I cannot take advantage of the data assembly. I have an algorithm that can decode the stream, however, I don't think it is general purpose, such that if the web service changes, my code will break. – mobibob Feb 28 '11 at 17:17

1 Answers1

9

I've tested out the code that you wrote on my emulator with Android 2.2 and it works fine. The chunked url I was using was:

        uri = new URI("http://www.httpwatch.com/httpgallery/chunked/");

I noticed that the BasicResponseHandler continues to try to read until it reaches the end of stream, and gives back then entire data all at once. The code could hang waiting for the stream to close. Does your webservice end the stream? or does it continue to give back chunks forever? I don't see a method to get back just the first chunked, but I did write a simple handler that just reads the first read from the input stream (which given a large enough buffer corresponds to the chunk). In the case of the URI I used for testing, it returns each line of the HTML file as a chunk. You can see just the first one returned here.

If this works for you, then you could easily write a handler that returns instead of a string, returns an Enumeration or some other object where you could return each of the chunks. Or even your own class.

public class ChunkedResponseHandler implements ResponseHandler<String> {
    public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {

        HttpEntity entity = response.getEntity();
        InputStream in = entity.getContent();
        StringBuffer out = new StringBuffer();
        byte[] b = new byte[4096];
        int n =  in.read(b);
        out.append(new String(b, 0, n));        
        return out.toString();
    }
}
christophercotton
  • 5,829
  • 2
  • 34
  • 49
  • Thanks - that works. The web service I am attached to is streaming continuously so that explains why the BasicResponseHandler does not help me. I have a "read-object" method to assemble/parse the data into the individual streaming objects. Now to find out how to get ChunkedInputStream to work ... – mobibob Mar 01 '11 at 18:18
  • In the debugger, you can see that the InputStream returned by getContent() is wrapped around the ChunkendInputStream if that helps at all. – christophercotton Mar 01 '11 at 20:03
  • Hmmm ... early in my investigation, I put a getContent().getClass().toString() debug message and I recall it was something like EofInputStream. I will check again with the new code. – mobibob Mar 01 '11 at 20:59
  • 1
    It is an EofSensorInputStream, but in the debugger you can see it has a wrappedStream with a class of ChunkedInputStream. You can have the ResponseHandler subclass return your objects. Since the ResponseHandler does everything for you, and just need to read the available number of bytes using the `InputStream#available()` I haven't tested it completely, but in the chunked version I did it mapped correctly. – christophercotton Mar 01 '11 at 21:21
  • +1 for that comment! I will definitely be refactoring my code to use your suggestions. – mobibob Mar 02 '11 at 20:32