nostra13 / Android-Universal-Image-Loader

Powerful and flexible library for loading, caching and displaying images on Android.
Apache License 2.0
16.79k stars 6.1k forks source link

[1.8.0] memoryCacheExtraOptions affixes the values to the Uri (https) #188

Closed chrisjenx closed 11 years ago

chrisjenx commented 11 years ago

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

nostra13 commented 11 years ago

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();
        }
    }
}
chrisjenx commented 11 years ago

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.

nostra13 commented 11 years ago

Did you found the reason?

chrisjenx commented 11 years ago

I haven't had chance going to investigate this weekend On 8 Mar 2013 09:35, "Sergey Tarasevich" notifications@github.com 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 .

Narfss commented 11 years ago

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.

chrisjenx commented 11 years ago

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.

nostra13 commented 11 years ago

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

Narfss commented 11 years ago

Great, now works perfect.

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

chrisjenx commented 11 years ago

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.

doridori commented 11 years ago

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

chrisjenx commented 11 years ago

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

doridori commented 11 years ago

oh sorry, my bad

doridori commented 11 years ago

@chrisjenx bug fix works great for

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .imageDownloader(new CustomImageDownloader(context)) //bug fix
nostra13 commented 11 years ago

Still can't understand how it could happen.

Lukafin commented 11 years ago

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?

nostra13 commented 11 years ago

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

Lukafin commented 11 years ago

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.

doridori commented 11 years ago

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

nostra13 commented 11 years ago

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.

chrisjenx commented 11 years ago

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" notifications@github.com 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 .

PankovSerge commented 9 years ago

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

HarryMMR commented 9 years ago

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!

huluwa-dev commented 8 years ago

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

HarryMMR commented 8 years ago

Have anyone found a fix? I need it ASAP.

zhdh2008 commented 8 years ago

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