Android-universal-image-loader: [1.8.0] memoryCacheExtraOptions affixes the values to the Uri (https)

Created on 1 Mar 2013  Â·  25Comments  Â·  Source: nostra13/Android-Universal-Image-Loader

I'm using .memoryCacheExtraOptions(512, 512)
I'm not sure if this is the desired effect but by doing this when performing webrequests it now affixes the size to the end of the image.

https://d3jpl91pxevbkh.cloudfront.net/notha/image/upload/v1360769665/1.png
becomes
https://d3jpl91pxevbkh.cloudfront.net/notha/image/upload/v1360769665/1.png_512x512
Which of course fails loading.

Cheers,
Chris

Problem

Most helpful comment

http://stackoverflow.com/questions/14789716/android-universal-image-loader-change-hxw-url-parameters

Maybe you have the problem with https, try this class:

public class AuthImageDownloader extends BaseImageDownloader {
    public static final String TAG = AuthImageDownloader.class.getName();


    public AuthImageDownloader(Context context, int connectTimeout, int readTimeout) {
        super(context, connectTimeout, readTimeout);
    }

    @Override
    protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {

        URL url = null;
        try {
            url = new URL(imageUri);
        } catch (MalformedURLException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        HttpURLConnection http = null;

        if (Scheme.ofUri(imageUri) == Scheme.HTTPS) {
            trustAllHosts();
            HttpsURLConnection https = (HttpsURLConnection) url
                    .openConnection();
            https.setHostnameVerifier(DO_NOT_VERIFY);
            http = https;
            http.connect();
        } else {
            http = (HttpURLConnection) url.openConnection();
        }

        http.setConnectTimeout(connectTimeout);
        http.setReadTimeout(readTimeout);
        return new FlushedInputStream(new BufferedInputStream(
                http.getInputStream()));
    }

    // always verify the host - dont check for certificate
    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * Trust every server - dont check for any certificate
     */
    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
        } };

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

All 25 comments

http://stackoverflow.com/questions/14789716/android-universal-image-loader-change-hxw-url-parameters

Maybe you have the problem with https, try this class:

public class AuthImageDownloader extends BaseImageDownloader {
    public static final String TAG = AuthImageDownloader.class.getName();


    public AuthImageDownloader(Context context, int connectTimeout, int readTimeout) {
        super(context, connectTimeout, readTimeout);
    }

    @Override
    protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {

        URL url = null;
        try {
            url = new URL(imageUri);
        } catch (MalformedURLException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        HttpURLConnection http = null;

        if (Scheme.ofUri(imageUri) == Scheme.HTTPS) {
            trustAllHosts();
            HttpsURLConnection https = (HttpsURLConnection) url
                    .openConnection();
            https.setHostnameVerifier(DO_NOT_VERIFY);
            http = https;
            http.connect();
        } else {
            http = (HttpURLConnection) url.openConnection();
        }

        http.setConnectTimeout(connectTimeout);
        http.setReadTimeout(readTimeout);
        return new FlushedInputStream(new BufferedInputStream(
                http.getInputStream()));
    }

    // always verify the host - dont check for certificate
    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * Trust every server - dont check for any certificate
     */
    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
        } };

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Nothing to do with SSL, this line actually returns an affixed Url which is why the image loader fails.
(https://d3jpl91pxevbkh.cloudfront.net/notha/image/upload/v1360769665/1.png_512x512 which of course is bad) .

    @Override
    protected InputStream getStreamFromNetwork(URI imageUri, Object extra) throws IOException {
      Log.d(TAG, "URL="+imageUri.toString());
      //...
    }

I will look at fixing it in my fork. Seems that a certain flow makes it prefix to the wrong parts of the request.

Did you found the reason?

I haven't had chance going to investigate this weekend
On 8 Mar 2013 09:35, "Sergey Tarasevich" [email protected] wrote:

Did you found the reason?

—
Reply to this email directly or view it on GitHubhttps://github.com/nostra13/Android-Universal-Image-Loader/issues/188#issuecomment-14611118
.

Hello @nostra13 and @chrisjenx, I have a similar problem, Universal Image Downloader and SSL.

I want use the class you post before, but in the point to override getStreamFromNetwork:

public class AuthImageDownloader extends BaseImageDownloader {
...
@Override
protected InputStream getStreamFromNetwork(URI imageUri, Object extra) throws IOException {
...
}

Happens this error, and i'm not sure how to fix:

The method getStreamFromNetwork(URI, Object) of type AuthImageDownloader must override or implement a supertype method

The quick fix is remove "@Override" annotation. But of course don't works.

Thanks.

Just check that the correct method being overridden.

If eclipse is throwing an error on the override annotation it means that you are not overriding/extending the correct class thus the error.

ImageDownloader changed its API, it uses String instead of URI. Updated my comment.

Great, now works perfect.

Thanks, Is incredible how both answer so fast. ^^

This is my work around to the above bug:

package com.bizzby.http.requests;

import android.content.Context;
import android.text.TextUtils;
import com.bizzby.utils.QLog;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.http.*;
import com.nostra13.universalimageloader.core.assist.FlushedInputStream;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with Intellij with Android, BIZZBY product.
 * See licencing for usage of this code.
 * <p/>
 * User: chris
 * Date: 01/03/2013
 * Time: 15:45
 */
public class GoogleImageDownloader extends BaseImageDownloader
{

    protected static final Pattern SIZE_PATTERN = Pattern.compile("(_[0-9]+(_|x)[0-9]+)$", Pattern.CASE_INSENSITIVE);
    public static HttpTransport sHttpTransport;
    public static HttpRequestFactory sHttpRequestFactory;

    public static HttpRequest getHttpRequest(final String uri) throws IOException
    {
        if (sHttpTransport == null) sHttpTransport = AndroidHttp.newCompatibleTransport();
        if (sHttpRequestFactory == null) sHttpRequestFactory = sHttpTransport.createRequestFactory();
        return sHttpRequestFactory.buildGetRequest(new GenericUrl(uri));
    }

    private static String replaceLast(final String string, final String from, final String to)
    {
        int lastIndex = string.lastIndexOf(from);
        if (lastIndex < 0) return string;
        final String tail = string.substring(lastIndex).replaceFirst(from, to);
        return string.substring(0, lastIndex) + tail;
    }

    static String stripSizeOffUrl(final String string)
    {
        if (TextUtils.isEmpty(string)) return string;
        final Matcher matcher = SIZE_PATTERN.matcher(string);
        String group = "";
        while (matcher.find())
        {
            group = matcher.group(1);
        }
        return replaceLast(string, group, "");

    }

    public GoogleImageDownloader(final Context context)
    {
        super(context);
    }

    public GoogleImageDownloader(final Context context, final int connectTimeout, final int readTimeout)
    {
        super(context, connectTimeout, readTimeout);
    }

    @Override
    protected InputStream getStreamFromContent(URI imageUri, final Object extra) throws FileNotFoundException
    {
        imageUri = URI.create(stripSizeOffUrl(imageUri.toString()));
        return super.getStreamFromContent(imageUri, extra);
    }

    @Override
    protected InputStream getStreamFromNetwork(final URI imageUri, final Object extra) throws IOException
    {
        if (null == imageUri) return null;
        final String url = stripSizeOffUrl(imageUri.toString());
        QLog.i("ImageLoader, Downloading [" + url + "]");
        final HttpRequest request = getHttpRequest(url);
        request.setConnectTimeout(connectTimeout);
        request.setReadTimeout(readTimeout);
        final HttpResponse response = request.execute();
        if (response != null && response.isSuccessStatusCode())
        {
            return new FlushedInputStream(response.getContent(), BUFFER_SIZE);
        }
        return null;
    }
}

The cause of this is still on my list todo.

Im having this issue too - this is no fun - and why is this thread marked closed?

@doridori its not marked closed the other #163 is closed which referenced this.

oh sorry, my bad

@chrisjenx bug fix works great for

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .imageDownloader(new CustomImageDownloader(context)) //bug fix

Still can't understand how it could happen.

Nostra, i am having problems with https and your solution posted above (using AuthImageDownloader class).
The problem is in method encodeCredentials(), where it says that method for Configuration.getInstance() is undefined.

public static String encodeCredentials() {
       try {
           Configuration configuration = Configuration.getInstance();
           String auth = android.util.Base64.encodeToString((configuration.getHttpAuthLogin()
                + ":" + configuration.getHttpAuthPassword()).getBytes("UTF-8"),
                android.util.Base64.NO_WRAP);
           return auth;
       } catch (Exception ignored) {
           Log.e(TAG, ignored.getMessage(), ignored);
       }
       return "";
   }

I am missing something? What are the needed imports for above code?
If i import android.content.res.Configuration, i get even more errors?

You should use this authorization only if you need. I guess you don't. I updated AuthImageDownloader code, check it out.

Works! I used code below to make it work:

   ImageLoaderimageLoader = ImageLoader.getInstance();

    DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
            .cacheInMemory()
            .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2).build();

    Builder configBuilder = new ImageLoaderConfiguration.Builder(getActivity());
    configBuilder.imageDownloader(new AuthImageDownloader(getActivity(), 1000, 1000));
    configBuilder.defaultDisplayImageOptions(defaultOptions);
    ImageLoaderConfiguration config=configBuilder.build();

    imageLoader.init(config);

Thank you very much for your quick answer.

I see this is closed - does it now not append the dimensions to the end of the URL?

It didn't append the dimensions before. I couldn't reproduce the bug and couldn't imagine why it can happen. chrisjenx promised to look into it but he didn't I guess. If you have this bug then you can send me your project with this bug so I'll look into it.

This bug is still very active. I'm out of the county so no chance to fix.
Dori can you confirm in 1.8.2 see if still an issue?

Chris.
On 10 Apr 2013 16:24, "Sergey Tarasevich" [email protected] wrote:

It didn't append the dimensions before. I couldn't reproduce the bug and
couldn't imagine why it can happen. chrisjenx promised to look into it but
he didn't I guess. If you have this bug then you can send me your project
with this bug so I'll look into it.

—
Reply to this email directly or view it on GitHubhttps://github.com/nostra13/Android-Universal-Image-Loader/issues/188#issuecomment-16199551
.

Got this issue with 1.9.3 and https in link. Use AuthImageDownloader from your comment.

As suggested, I tried to use AuthImageDownloader to ignore SSL cert error. But from log cat, it seems that AuthImageDownloader override method is not being called and i still get same ssl error.
I already set ".imageDownloader(new AuthImageDownloader(getApplicationContext(),5000,5000)) " in ImageLoaderConfiguration.
Help please!

Got this issue with 1.9.4....How to solve it???

Have anyone found a fix? I need it ASAP.

@nostra13 Your code works well, thanks
ps: The version of UIL I use is 1.9.5

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ziem picture ziem  Â·  37Comments

giaur500 picture giaur500  Â·  6Comments

vovkab picture vovkab  Â·  36Comments

o-antsiferov picture o-antsiferov  Â·  16Comments

fistuk picture fistuk  Â·  13Comments