Monday, October 17, 2016

HttpUrlConnection setting Range in Android is ignored

Leave a Comment

I'm trying get a 206 response from my server using Android.

Here's the code.

@Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_splash);     new AsyncTask<Void, Void, Void>() {         @Override         protected Void doInBackground(Void... params) {             try {                 URL url = new URL("http://aviddapp.com/10mb.file");                 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();                 urlConnection.setRequestProperty("Range", "bytes=1-2");                 urlConnection.connect();                  System.out.println("Response Code: " + urlConnection.getResponseCode());                 System.out.println("Content-Length: " + urlConnection.getContentLength());                 Map<String, List<String>> map = urlConnection.getHeaderFields();                 for (Map.Entry<String, List<String>> entry : map.entrySet()) {                     System.out.println("Key : " + entry.getKey() +                             " ,Value : " + entry.getValue());                 }                 InputStream inputStream = urlConnection.getInputStream();                 long size = 0;                  while(inputStream.read() != -1 )                     size++;                  System.out.println("Downloaded Size: " + size);              }catch(MalformedURLException mue) {                 mue.printStackTrace();             }catch(IOException ioe) {                 ioe.printStackTrace();             }             return null;         }     }.execute(); } 

Here's the output:

I/System.out: Respnse Code: 200 I/System.out: Content-Length: -1 I/System.out: Key : null ,Value : [HTTP/1.1 200 OK] I/System.out: Key : Accept-Ranges ,Value : [bytes] I/System.out: Key : Cache-Control ,Value : [max-age=604800, public] I/System.out: Key : Connection ,Value : [Keep-Alive] I/System.out: Key : Date ,Value : [Tue, 04 Oct 2016 07:45:22 GMT] I/System.out: Key : ETag ,Value : ["a00000-53e051f279680-gzip"] I/System.out: Key : Expires ,Value : [Tue, 11 Oct 2016 07:45:22 GMT] I/System.out: Key : Keep-Alive ,Value : [timeout=5, max=100] I/System.out: Key : Last-Modified ,Value : [Tue, 04 Oct 2016 07:36:42 GMT] I/System.out: Key : Server ,Value : [Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4] I/System.out: Key : Transfer-Encoding ,Value : [chunked] I/System.out: Key : Vary ,Value : [Accept-Encoding,User-Agent] I/System.out: Key : X-Android-Received-Millis ,Value : [1475567127403] I/System.out: Key : X-Android-Response-Source ,Value : [NETWORK 200] I/System.out: Key : X-Android-Sent-Millis ,Value : [1475567127183] I/System.out: Downloaded Size: 10485760 

Now I'm doing the same thing is pure java.

public static void main(String... args) {     try {         URL url = new URL("http://aviddapp.com/10mb.file");         HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();         urlConnection.setRequestProperty("Range", "bytes=1-2");         urlConnection.connect();          System.out.println("Respnse Code: " + urlConnection.getResponseCode());         System.out.println("Content-Length: " + urlConnection.getContentLength());         Map<String, List<String>> map = urlConnection.getHeaderFields();         for (Map.Entry<String, List<String>> entry : map.entrySet()) {             System.out.println("Key : " + entry.getKey() +                     " ,Value : " + entry.getValue());         }         InputStream inputStream = urlConnection.getInputStream();         long size = 0;          while(inputStream.read() != -1 )             size++;          System.out.println("Downloaded Size: " + size);      }catch(MalformedURLException mue) {         mue.printStackTrace();     }catch(IOException ioe) {         ioe.printStackTrace();     } } 

Here's the output

Respnse Code: 206 Content-Length: 2 Key : Keep-Alive ,Value : [timeout=5, max=100] Key : null ,Value : [HTTP/1.1 206 Partial Content] Key : Server ,Value : [Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4] Key : Content-Range ,Value : [bytes 1-2/10485760] Key : Connection ,Value : [Keep-Alive] Key : Last-Modified ,Value : [Tue, 04 Oct 2016 07:36:42 GMT] Key : Date ,Value : [Tue, 04 Oct 2016 07:42:17 GMT] Key : Accept-Ranges ,Value : [bytes] Key : Cache-Control ,Value : [max-age=604800, public] Key : ETag ,Value : ["a00000-53e051f279680"] Key : Vary ,Value : [Accept-Encoding,User-Agent] Key : Expires ,Value : [Tue, 11 Oct 2016 07:42:17 GMT] Key : Content-Length ,Value : [2] Downloaded Size: 2 

As you can see I'm getting diffrent response codes in both cases. It seems like Android is not passing Range to the server maybe? What's happening here?

PS: I'm getting a 206 if the file size is 1mb.

4 Answers

Answers 1

I am relatively certain the error is not in the Android code.

It looks like the server might be delivering spurious results.

You can check with a third party tool (such as Postman) to determine the headers that web service is delivering.

My results using Postman. As you can see, it is delivering HTTP 200 (not 206). It is also not wending a capped Content-Length. If the server is yours, perhaps check that it is configured correctly. Also check your code with other servers.

Postman results

Answers 2

Hi Can u try this piece of code, it seems i am getting HTTP 206 here.

new Thread() {             @Override             public void run() {                 try {                     URL url = new URL("http://aviddapp.com/10mb.file");                     HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); //                    urlConnection.setRequestMethod("HEAD");                     urlConnection.setRequestProperty("Accept-Encoding", "");                      urlConnection.setRequestProperty("Range", "bytes=1-2");                     urlConnection.connect();                      System.out.println("Response Code: " + urlConnection.getResponseCode());                     System.out.println("Content-Length: " + urlConnection.getContentLength());                     Map<String, List<String>> map = urlConnection.getHeaderFields();                     for (Map.Entry<String, List<String>> entry : map.entrySet()) {                         System.out.println("Key : " + entry.getKey() +                                 " ,Value : " + entry.getValue());                     }                     InputStream inputStream = urlConnection.getInputStream();                     long size = 0;                      while (inputStream.read() != -1)                         size++;                      System.out.println("Downloaded Size: " + size);                  } catch (IOException ioe) {                     ioe.printStackTrace();                 }             }         }.start(); 

You just have to add this in async task.

Check this result commenting on/off this line.

urlConnection.setRequestProperty("Accept-Encoding", ""); 

Answers 3

I am not sure if this is related to Content-Length being cleared by android implementation by default. Look at the below snippet from the source code where it says it does gzip compression by default.

https://android.googlesource.com/platform/libcore/+/2e317a02b5a8f9b319488ab9311521e8b4f87a0a/luni/src/main/java/java/net/HttpURLConnection.java

By default, this implementation of HttpURLConnection requests that servers use gzip compression and it automatically decompresses the data for callers of getInputStream(). The Content-Encoding and Content-Length response headers are cleared in this case.

Can you try disabling the default caching using below code to check if that works?

urlConnection.setRequestProperty("Accept-Encoding", "identity");

PS: Sorry for bad formattings. Using the mobile version of SO.

Answers 4

Have you tried like that:

    urlConnection.setRequestProperty("Range", "bytes=1000-"); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment