All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bumptech.glide.load.model.LazyHeaders Maven / Gradle / Ivy

Go to download

A fast and efficient image loading library for Android focused on smooth scrolling.

There is a newer version: 5.0.0-rc01
Show newest version
package com.bumptech.glide.load.model;

import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A wrapper class for a set of headers to be included in a Glide request, allowing headers to be
 * constructed lazily.
 *
 * 

Ideally headers are constructed once and then re-used for multiple loads, rather then being * constructed individually for each load. * *

This class is thread safe. */ public final class LazyHeaders implements Headers { private final Map> headers; private volatile Map combinedHeaders; LazyHeaders(Map> headers) { this.headers = Collections.unmodifiableMap(headers); } @Override public Map getHeaders() { if (combinedHeaders == null) { synchronized (this) { if (combinedHeaders == null) { this.combinedHeaders = Collections.unmodifiableMap(generateHeaders()); } } } return combinedHeaders; } private Map generateHeaders() { Map combinedHeaders = new HashMap<>(); for (Map.Entry> entry : headers.entrySet()) { String values = buildHeaderValue(entry.getValue()); if (!TextUtils.isEmpty(values)) { combinedHeaders.put(entry.getKey(), values); } } return combinedHeaders; } @NonNull private String buildHeaderValue(@NonNull List factories) { StringBuilder sb = new StringBuilder(); int size = factories.size(); for (int i = 0; i < size; i++) { LazyHeaderFactory factory = factories.get(i); String header = factory.buildHeader(); if (!TextUtils.isEmpty(header)) { sb.append(header); if (i != factories.size() - 1) { sb.append(','); } } } return sb.toString(); } @Override public String toString() { return "LazyHeaders{" + "headers=" + headers + '}'; } @Override public boolean equals(Object o) { if (o instanceof LazyHeaders) { LazyHeaders other = (LazyHeaders) o; return headers.equals(other.headers); } return false; } @Override public int hashCode() { return headers.hashCode(); } /** * Adds an {@link LazyHeaderFactory} that will be used to construct a value for the given key* * lazily on a background thread. * *

This class is not thread safe. * *

This class may include default values for User-Agent and Accept-Encoding headers. These will * be replaced by calls to either {@link #setHeader(String, LazyHeaderFactory)} or {@link * #addHeader(String, String)}, even though {@link #addHeader(String, LazyHeaderFactory)} would * usually append an additional value. */ public static final class Builder { private static final String USER_AGENT_HEADER = "User-Agent"; private static final String DEFAULT_USER_AGENT = getSanitizedUserAgent(); private static final Map> DEFAULT_HEADERS; // Set Accept-Encoding header to do our best to avoid gzip since it's both inefficient for // images and also makes it more difficult for us to detect and prevent partial content // rendering. See #440. static { Map> temp = new HashMap<>(2); if (!TextUtils.isEmpty(DEFAULT_USER_AGENT)) { temp.put( USER_AGENT_HEADER, Collections.singletonList( new StringHeaderFactory(DEFAULT_USER_AGENT))); } DEFAULT_HEADERS = Collections.unmodifiableMap(temp); } private boolean copyOnModify = true; private Map> headers = DEFAULT_HEADERS; private boolean isUserAgentDefault = true; /** * Adds a value for the given header and returns this builder. * *

Use {@link #addHeader(String, LazyHeaderFactory)} if obtaining the value requires I/O * (i.e. an OAuth token). * * @see #addHeader(String, LazyHeaderFactory) */ public Builder addHeader(@NonNull String key, @NonNull String value) { return addHeader(key, new StringHeaderFactory(value)); } /** * Adds an {@link LazyHeaderFactory} that will be used to construct a value for the given key * lazily on a background thread. * *

Headers may have multiple values whose order is defined by the order in which this method * is called. * *

This class does not prevent you from adding the same value to a given key multiple times */ public Builder addHeader(@NonNull String key, @NonNull LazyHeaderFactory factory) { if (isUserAgentDefault && USER_AGENT_HEADER.equalsIgnoreCase(key)) { return setHeader(key, factory); } copyIfNecessary(); getFactories(key).add(factory); return this; } /** * Replaces all existing {@link LazyHeaderFactory LazyHeaderFactorys} for the given key with the * given {@link LazyHeaderFactory}. * *

If the given value is {@code null}, the header at the given key will be removed. * *

Use {@link #setHeader(String, LazyHeaderFactory)} if obtaining the value requires I/O * (i.e. an OAuth token). */ @SuppressWarnings({"UnusedReturnValue", "WeakerAccess"}) // Public API public Builder setHeader(@NonNull String key, @Nullable String value) { return setHeader(key, value == null ? null : new StringHeaderFactory(value)); } /** * Replaces all existing {@link LazyHeaderFactory LazyHeaderFactorys} for the given key with the * given {@link LazyHeaderFactory}. * *

If the given value is {@code null}, the header at the given key will be removed. */ public Builder setHeader(@NonNull String key, @Nullable LazyHeaderFactory factory) { copyIfNecessary(); if (factory == null) { headers.remove(key); } else { List factories = getFactories(key); factories.clear(); factories.add(factory); } if (isUserAgentDefault && USER_AGENT_HEADER.equalsIgnoreCase(key)) { isUserAgentDefault = false; } return this; } private List getFactories(String key) { List factories = headers.get(key); if (factories == null) { factories = new ArrayList<>(); headers.put(key, factories); } return factories; } private void copyIfNecessary() { if (copyOnModify) { copyOnModify = false; headers = copyHeaders(); } } /** Returns a new immutable {@link LazyHeaders} object. */ public LazyHeaders build() { copyOnModify = true; return new LazyHeaders(headers); } private Map> copyHeaders() { Map> result = new HashMap<>(headers.size()); for (Map.Entry> entry : headers.entrySet()) { @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") List valueCopy = new ArrayList<>(entry.getValue()); result.put(entry.getKey(), valueCopy); } return result; } /** * Ensures that the default header will pass OkHttp3's checks for header values. * * @see #2331 */ @VisibleForTesting static String getSanitizedUserAgent() { String defaultUserAgent = System.getProperty("http.agent"); if (TextUtils.isEmpty(defaultUserAgent)) { return defaultUserAgent; } int length = defaultUserAgent.length(); StringBuilder sb = new StringBuilder(defaultUserAgent.length()); for (int i = 0; i < length; i++) { char c = defaultUserAgent.charAt(i); if ((c > '\u001f' || c == '\t') && c < '\u007f') { sb.append(c); } else { sb.append('?'); } } return sb.toString(); } } static final class StringHeaderFactory implements LazyHeaderFactory { @NonNull private final String value; StringHeaderFactory(@NonNull String value) { this.value = value; } @Override public String buildHeader() { return value; } @Override public String toString() { return "StringHeaderFactory{" + "value='" + value + '\'' + '}'; } @Override public boolean equals(Object o) { if (o instanceof StringHeaderFactory) { StringHeaderFactory other = (StringHeaderFactory) o; return value.equals(other.value); } return false; } @Override public int hashCode() { return value.hashCode(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy