MD5 校验值:1036132062d4d223cd1a714f5bbea98b
HttpUrlSource.java 文件包含反编译后的源代码,请注意,该内容仅供学习和参考使用,不得用于非法用途。
package com.danikula.videocache; import android.text.TextUtils; import com.danikula.videocache.headers.EmptyHeadersInjector; import com.danikula.videocache.headers.HeaderInjector; import com.danikula.videocache.sourcestorage.SourceInfoStorage; import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpUrlSource implements Source { private static final Logger LOG = LoggerFactory.getLogger("HttpUrlSource"); private static final int MAX_REDIRECTS = 5; private HttpURLConnection connection; private final HeaderInjector headerInjector; private InputStream inputStream; private SourceInfo sourceInfo; private final SourceInfoStorage sourceInfoStorage; public HttpUrlSource(String url) { this(url, SourceInfoStorageFactory.newEmptySourceInfoStorage()); } public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage) { this(url, sourceInfoStorage, new EmptyHeadersInjector()); } public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) { this.sourceInfoStorage = (SourceInfoStorage) Preconditions.checkNotNull(sourceInfoStorage); this.headerInjector = (HeaderInjector) Preconditions.checkNotNull(headerInjector); SourceInfo sourceInfo = sourceInfoStorage.get(url); this.sourceInfo = sourceInfo != null ? sourceInfo : new SourceInfo(url, -2147483648L, ProxyCacheUtils.getSupposablyMime(url)); } public HttpUrlSource(HttpUrlSource source) { this.sourceInfo = source.sourceInfo; this.sourceInfoStorage = source.sourceInfoStorage; this.headerInjector = source.headerInjector; } @Override public synchronized long length() throws ProxyCacheException { if (this.sourceInfo.length == -2147483648L) { fetchContentInfo(); } return this.sourceInfo.length; } @Override public void open(long offset) throws ProxyCacheException { try { HttpURLConnection openConnection = openConnection(offset, -1); this.connection = openConnection; String mime = openConnection.getContentType(); this.inputStream = new BufferedInputStream(this.connection.getInputStream(), 8192); long length = readSourceAvailableBytes(this.connection, offset, this.connection.getResponseCode()); SourceInfo sourceInfo = new SourceInfo(this.sourceInfo.url, length, mime); this.sourceInfo = sourceInfo; this.sourceInfoStorage.put(sourceInfo.url, this.sourceInfo); } catch (IOException e) { throw new ProxyCacheException("Error opening connection for " + this.sourceInfo.url + " with offset " + offset, e); } } private long readSourceAvailableBytes(HttpURLConnection connection, long offset, int responseCode) throws IOException { long contentLength = getContentLength(connection); return responseCode == 200 ? contentLength : responseCode == 206 ? contentLength + offset : this.sourceInfo.length; } private long getContentLength(HttpURLConnection connection) { String contentLengthValue = connection.getHeaderField("Content-Length"); if (contentLengthValue == null) { return -1L; } return Long.parseLong(contentLengthValue); } @Override public void close() throws ProxyCacheException { HttpURLConnection httpURLConnection = this.connection; if (httpURLConnection != null) { try { httpURLConnection.disconnect(); } catch (ArrayIndexOutOfBoundsException e) { LOG.error("Error closing connection correctly. Should happen only on Android L. If anybody know how to fix it, please visit https://github.com/danikula/AndroidVideoCache/issues/88. Until good solution is not know, just ignore this issue :(", (Throwable) e); } catch (IllegalArgumentException e2) { e = e2; throw new RuntimeException("Wait... but why? WTF!? Really shouldn't happen any more after fixing https://github.com/danikula/AndroidVideoCache/issues/43. If you read it on your device log, please, notify me danikula@gmail.com or create issue here https://github.com/danikula/AndroidVideoCache/issues.", e); } catch (NullPointerException e3) { e = e3; throw new RuntimeException("Wait... but why? WTF!? Really shouldn't happen any more after fixing https://github.com/danikula/AndroidVideoCache/issues/43. If you read it on your device log, please, notify me danikula@gmail.com or create issue here https://github.com/danikula/AndroidVideoCache/issues.", e); } } } @Override public int read(byte[] buffer) throws ProxyCacheException { InputStream inputStream = this.inputStream; if (inputStream == null) { throw new ProxyCacheException("Error reading data from " + this.sourceInfo.url + ": connection is absent!"); } try { return inputStream.read(buffer, 0, buffer.length); } catch (InterruptedIOException e) { throw new InterruptedProxyCacheException("Reading source " + this.sourceInfo.url + " is interrupted", e); } catch (IOException e2) { throw new ProxyCacheException("Error reading data from " + this.sourceInfo.url, e2); } } private void fetchContentInfo() throws ProxyCacheException { LOG.debug("Read content info from " + this.sourceInfo.url); HttpURLConnection urlConnection = null; InputStream inputStream = null; try { try { urlConnection = openConnection(0L, 10000); long length = getContentLength(urlConnection); String mime = urlConnection.getContentType(); inputStream = urlConnection.getInputStream(); SourceInfo sourceInfo = new SourceInfo(this.sourceInfo.url, length, mime); this.sourceInfo = sourceInfo; this.sourceInfoStorage.put(sourceInfo.url, this.sourceInfo); LOG.debug("Source info fetched: " + this.sourceInfo); ProxyCacheUtils.close(inputStream); if (urlConnection == null) { return; } } catch (IOException e) { LOG.error("Error fetching info from " + this.sourceInfo.url, (Throwable) e); ProxyCacheUtils.close(inputStream); if (urlConnection == null) { return; } } urlConnection.disconnect(); } catch (Throwable th) { ProxyCacheUtils.close(inputStream); if (urlConnection != null) { urlConnection.disconnect(); } throw th; } } private HttpURLConnection openConnection(long offset, int timeout) throws IOException, ProxyCacheException { String str; HttpURLConnection connection; boolean redirected; int redirectCount = 0; String url = this.sourceInfo.url; do { Logger logger = LOG; StringBuilder sb = new StringBuilder(); sb.append("Open connection "); if (offset > 0) { str = " with offset " + offset; } else { str = ""; } sb.append(str); sb.append(" to "); sb.append(url); logger.debug(sb.toString()); connection = (HttpURLConnection) new URL(url).openConnection(); injectCustomHeaders(connection, url); if (offset > 0) { connection.setRequestProperty("Range", "bytes=" + offset + "-"); } if (timeout > 0) { connection.setConnectTimeout(timeout); connection.setReadTimeout(timeout); } int code = connection.getResponseCode(); redirected = code == 301 || code == 302 || code == 303; if (redirected) { url = connection.getHeaderField("Location"); redirectCount++; connection.disconnect(); } if (redirectCount > 5) { throw new ProxyCacheException("Too many redirects: " + redirectCount); } } while (redirected); return connection; } private void injectCustomHeaders(HttpURLConnection connection, String url) { Map<String, String> extraHeaders = this.headerInjector.addHeaders(url); for (Map.Entry<String, String> header : extraHeaders.entrySet()) { connection.setRequestProperty(header.getKey(), header.getValue()); } } public synchronized String getMime() throws ProxyCacheException { if (TextUtils.isEmpty(this.sourceInfo.mime)) { fetchContentInfo(); } return this.sourceInfo.mime; } public String getUrl() { return this.sourceInfo.url; } public String toString() { return "HttpUrlSource{sourceInfo='" + this.sourceInfo + "}"; } }