QQ浏览器 v12.2.3.7053版本的 MD5 值为:8285ab3059e5c8b521a264dfbc5c3685
以下内容为反编译后的 CronetHttpURLConnection.java 源代码,内容仅作参考
package com.tencent.mtt.network.tbsnet;
import android.util.Pair;
import com.huawei.hms.support.hianalytics.HiAnalyticsConstant;
import com.tencent.common.featuretoggle.FeatureToggle;
import com.tencent.common.http.HttpTimeRecord;
import com.tencent.common.threadpool.BrowserExecutorSupplier;
import com.tencent.mtt.AppInfoHolder;
import com.tencent.mtt.apkplugin.impl.IAPInjectService;
import com.tencent.mtt.browser.jsextension.open.IOpenJsApis;
import com.tencent.mtt.network.QBUrl;
import com.tencent.mtt.network.queen.KingCardRequest;
import com.tencent.mtt.network.queen.QueenHandler;
import com.tencent.mtt.network.queen.QueenReporter;
import com.tencent.tbs.common.internal.service.StatServerHolder;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.cert.Certificate;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.chromium.net.CronetEngine;
import org.chromium.net.CronetException;
import org.chromium.net.ExperimentalUrlRequest;
import org.chromium.net.UrlRequest;
import org.chromium.net.UrlResponseInfo;
import qb.network.BuildConfig;
public class CronetHttpURLConnection extends HttpsURLConnection {
private static final String CONTENT_LENGTH = "Content-Length";
private static final String TAG = CronetHttpURLConnection.class.getSimpleName();
private long endTime;
boolean hasRequestHeaderAcceptEncoding;
boolean hasRequestHeaderRange;
int mConnectionTimeout;
private final CronetEngine mCronetEngine;
private IOException mException;
private boolean mHasResponseHeadersOrCompleted;
private CronetInputStream mInputStream;
boolean mIsKingProxyEnable;
KingCardRequest mKingCardRequest;
private final MessageLoop mMessageLoop;
private boolean mOnRedirectCalled;
private CronetOutputStream mOutputStream;
private Random mRandomGen;
private UrlRequest mRequest;
private final List<Pair<String, String>> mRequestHeaders;
private List<Map.Entry<String, String>> mResponseHeadersList;
private Map<String, List<String>> mResponseHeadersMap;
private UrlResponseInfo mResponseInfo;
String mTag;
private int mTrafficStatsTag;
private boolean mTrafficStatsTagSet;
private int mTrafficStatsUid;
private boolean mTrafficStatsUidSet;
private long receiveHeaderTime;
private long startTime;
boolean transparentGzip;
public class CronetUrlRequestCallback extends UrlRequest.Callback {
public CronetUrlRequestCallback() {
}
private void setResponseDataCompleted(IOException iOException) {
CronetHttpURLConnection.this.mException = iOException;
if (CronetHttpURLConnection.this.mInputStream != null) {
CronetHttpURLConnection.this.mInputStream.setResponseDataCompleted(iOException);
}
if (CronetHttpURLConnection.this.mOutputStream != null) {
CronetHttpURLConnection.this.mOutputStream.setRequestCompleted(iOException);
}
CronetHttpURLConnection.this.mHasResponseHeadersOrCompleted = true;
CronetHttpURLConnection.this.mMessageLoop.quit();
}
@Override
public void onCanceled(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo) {
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
setResponseDataCompleted(new IOException("disconnect() called"));
CronetHttpURLConnection.this.uploadNetworkQualityToBeacon("cancel");
}
@Override
public void onFailed(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo, CronetException cronetException) {
if (cronetException == null) {
throw new IllegalStateException("Exception cannot be null in onFailed.");
}
TbsNetLiveLogger.error(CronetHttpURLConnection.TAG, "CronetHttpURLConnection url=" + CronetHttpURLConnection.this.getURL().toString() + " onFailure e=" + cronetException.getMessage());
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
setResponseDataCompleted(cronetException);
CronetHttpURLConnection.this.uploadNetworkQualityToBeacon("false");
CronetHttpURLConnection.this.printDebugNetworkLogIfNeeded(urlResponseInfo, true, cronetException);
}
@Override
public void onReadCompleted(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo, ByteBuffer byteBuffer) {
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
CronetHttpURLConnection.this.mMessageLoop.quit();
}
@Override
public void onRedirectReceived(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo, String str) {
CronetHttpURLConnection.this.mOnRedirectCalled = true;
try {
URL url = new URL(str);
boolean equals = url.getProtocol().equals(CronetHttpURLConnection.this.url.getProtocol());
if (CronetHttpURLConnection.this.instanceFollowRedirects) {
CronetHttpURLConnection.this.url = url;
}
if (CronetHttpURLConnection.this.instanceFollowRedirects && equals) {
CronetHttpURLConnection.this.mRequest.followRedirect();
return;
}
} catch (MalformedURLException unused) {
}
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
CronetHttpURLConnection.this.mRequest.cancel();
setResponseDataCompleted(null);
}
@Override
public void onResponseStarted(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo) {
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
CronetHttpURLConnection.this.mHasResponseHeadersOrCompleted = true;
CronetHttpURLConnection.this.mMessageLoop.quit();
CronetHttpURLConnection.this.receiveHeaderTime = System.currentTimeMillis();
if (FeatureToggle.a(BuildConfig.BUG_TOGGLE_91651997)) {
return;
}
CronetHttpURLConnection.this.queenReport();
}
@Override
public void onSucceeded(UrlRequest urlRequest, UrlResponseInfo urlResponseInfo) {
CronetHttpURLConnection.this.mResponseInfo = urlResponseInfo;
setResponseDataCompleted(null);
CronetHttpURLConnection.this.uploadNetworkQualityToBeacon(IOpenJsApis.TRUE);
CronetHttpURLConnection.this.printDebugNetworkLogIfNeeded(urlResponseInfo, false, null);
}
}
public CronetHttpURLConnection(QBUrl qBUrl, CronetEngine cronetEngine) {
super(qBUrl.a());
this.startTime = -1L;
this.endTime = -1L;
this.receiveHeaderTime = -1L;
this.mRandomGen = new Random();
boolean z = false;
this.transparentGzip = false;
this.hasRequestHeaderAcceptEncoding = false;
this.hasRequestHeaderRange = false;
this.mIsKingProxyEnable = false;
this.mConnectionTimeout = 10000;
this.mTag = qBUrl.c();
if (qBUrl.b() && !qBUrl.i()) {
z = true;
}
this.mIsKingProxyEnable = z;
this.mCronetEngine = cronetEngine;
this.mMessageLoop = new MessageLoop(this);
this.mInputStream = new CronetInputStream(this);
this.mRequestHeaders = new ArrayList();
}
private void checkHasResponseHeaders() throws IOException {
if (!this.mHasResponseHeadersOrCompleted) {
throw new IllegalStateException("No response.");
}
IOException iOException = this.mException;
if (iOException != null) {
throw iOException;
}
if (this.mResponseInfo == null) {
throw new NullPointerException("Response info is null when there is no exception.");
}
}
private void checkRequestHeader() {
for (Pair<String, String> pair : this.mRequestHeaders) {
if (((String) pair.first).equalsIgnoreCase("Accept-Encoding")) {
this.hasRequestHeaderAcceptEncoding = true;
}
if (((String) pair.first).equalsIgnoreCase("Range")) {
this.hasRequestHeaderRange = true;
}
}
}
private void checkTransparentGzip() {
for (Map.Entry<String, String> entry : this.mResponseInfo.getAllHeadersAsList()) {
if (entry.getKey().equalsIgnoreCase("Content-Encoding") && entry.getValue().equalsIgnoreCase("gzip")) {
this.transparentGzip = true;
}
}
}
public void doUpload(String str) {
try {
if (this.mResponseInfo.getUrl().startsWith("https://otheve.beacon.qq.com")) {
return;
}
HashMap hashMap = new HashMap();
hashMap.put("url", this.mResponseInfo.getUrl());
hashMap.put("success", str);
hashMap.put(HiAnalyticsConstant.HaKey.BI_KEY_RESULT, "" + this.mResponseInfo.getHttpStatusCode());
hashMap.put("contentLength", "" + this.mResponseInfo.getReceivedByteCount());
hashMap.put("receive_body", "" + (this.endTime - this.receiveHeaderTime));
hashMap.put("receive_header", "" + (this.receiveHeaderTime - this.startTime));
hashMap.put("dns", "" + ((this.mResponseInfo.getDnsEndTime() - this.mResponseInfo.getDnsStartTime()) / 1000));
hashMap.put("connect", "" + ((this.mResponseInfo.getConnectEndTime() - this.mResponseInfo.getConnectStartTime()) / 1000));
hashMap.put("isReuse", "" + this.mResponseInfo.isSocketReuse());
hashMap.put("network_total", "" + (this.endTime - this.startTime));
hashMap.put("exceptionMsg", this.mException != null ? this.mException.getMessage() : "");
hashMap.put("guid", AppInfoHolder.getAppInfoByID(AppInfoHolder.AppInfoID.APP_INFO_GUID));
hashMap.put("qua2", AppInfoHolder.getAppInfoByID(AppInfoHolder.AppInfoID.APP_INFO_QUA2_3));
hashMap.put("connectionType", "CronetHttpURLConnection");
StatServerHolder.statWithBeacon("MTT_NETWORK_QUALITY_STAT_BEACON", hashMap);
} catch (Exception unused) {
}
}
private int findRequestProperty(String str) {
for (int i = 0; i < this.mRequestHeaders.size(); i++) {
if (((String) this.mRequestHeaders.get(i).first).equalsIgnoreCase(str)) {
return i;
}
}
return -1;
}
private Map<String, List<String>> getAllHeaders() {
Map<String, List<String>> map = this.mResponseHeadersMap;
if (map != null) {
return map;
}
TreeMap treeMap = new TreeMap(String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, String> entry : getAllHeadersAsList()) {
ArrayList arrayList = new ArrayList();
if (treeMap.containsKey(entry.getKey())) {
arrayList.addAll((Collection) treeMap.get(entry.getKey()));
}
arrayList.add(entry.getValue());
treeMap.put(entry.getKey(), Collections.unmodifiableList(arrayList));
}
this.mResponseHeadersMap = Collections.unmodifiableMap(treeMap);
return this.mResponseHeadersMap;
}
private List<Map.Entry<String, String>> getAllHeadersAsList() {
List<Map.Entry<String, String>> list = this.mResponseHeadersList;
if (list != null) {
return list;
}
checkTransparentGzip();
this.mResponseHeadersList = new ArrayList();
for (Map.Entry<String, String> entry : this.mResponseInfo.getAllHeadersAsList()) {
if ((!entry.getKey().equalsIgnoreCase("Content-Length") && !entry.getKey().equalsIgnoreCase("Content-Encoding")) || !this.transparentGzip || !this.hasRequestHeaderAcceptEncoding || this.hasRequestHeaderRange) {
if (!entry.getKey().equalsIgnoreCase("Content-Encoding")) {
this.mResponseHeadersList.add(new AbstractMap.SimpleImmutableEntry(entry));
}
}
}
this.mResponseHeadersList = Collections.unmodifiableList(this.mResponseHeadersList);
return this.mResponseHeadersList;
}
private Map.Entry<String, String> getHeaderFieldEntry(int i) {
try {
getResponse();
List<Map.Entry<String, String>> allHeadersAsList = getAllHeadersAsList();
if (i >= allHeadersAsList.size()) {
return null;
}
return allHeadersAsList.get(i);
} catch (IOException unused) {
return null;
}
}
private void getResponse() throws IOException {
CronetOutputStream cronetOutputStream = this.mOutputStream;
if (cronetOutputStream != null) {
cronetOutputStream.checkReceivedEnoughContent();
if (isChunkedUpload()) {
this.mOutputStream.close();
}
this.mOutputStream.setHasGetResponse();
}
if (!this.mHasResponseHeadersOrCompleted) {
startRequest();
this.mMessageLoop.loop(this.mConnectionTimeout + 1000);
}
checkHasResponseHeaders();
}
private long getStreamingModeContentLength() {
long j = this.fixedContentLength;
try {
long j2 = getClass().getField("fixedContentLengthLong").getLong(this);
return j2 != -1 ? j2 : j;
} catch (IllegalAccessException | NoSuchFieldException unused) {
return j;
}
}
private boolean isChunkedUpload() {
return this.chunkLength > 0;
}
private void prepareAndTransformRequest() {
boolean z;
if (FeatureToggle.a(BuildConfig.BUG_TOGGLE_91651997) || !(z = this.mIsKingProxyEnable)) {
return;
}
this.mKingCardRequest = new KingCardRequest(this.mTag, z);
this.mCronetEngine.setKingCardUser(QueenHandler.a().a(this.mRequest, getURL(), this.mKingCardRequest, this.mCronetEngine));
}
private void prepareRequestHeaders(ExperimentalUrlRequest.Builder builder) throws IOException {
if (this.doOutput || this.method.equals("POST")) {
if (this.method.equals("GET")) {
this.method = "POST";
}
CronetOutputStream cronetOutputStream = this.mOutputStream;
if (cronetOutputStream != null) {
builder.setUploadDataProvider(cronetOutputStream.getUploadDataProvider(), (Executor) this.mMessageLoop);
if (getRequestProperty("Content-Length") == null && !isChunkedUpload()) {
addRequestProperty("Content-Length", Long.toString(this.mOutputStream.getUploadDataProvider().getLength()));
}
this.mOutputStream.setConnected();
} else if (getRequestProperty("Content-Length") == null) {
addRequestProperty("Content-Length", "0");
}
if (getRequestProperty("Content-Type") == null) {
addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
}
}
}
public void printDebugNetworkLogIfNeeded(UrlResponseInfo urlResponseInfo, boolean z, CronetException cronetException) {
long j;
long j2;
long j3;
long j4;
if (HttpTimeRecord.isDebugMode || z) {
List<Pair<String, String>> list = this.mRequestHeaders;
if (list.indexOf("Accept-Encoding") != -1) {
list.remove("Accept-Encoding");
}
UrlResponseInfo urlResponseInfo2 = this.mResponseInfo;
long j5 = -1;
if (urlResponseInfo2 != null) {
long j6 = this.endTime - (-1);
long j7 = (-1) - this.startTime;
j2 = (urlResponseInfo2.getDnsEndTime() - this.mResponseInfo.getDnsStartTime()) / 1000;
j3 = (this.mResponseInfo.getConnectEndTime() - this.mResponseInfo.getConnectStartTime()) / 1000;
j4 = this.endTime - this.startTime;
j5 = j6;
j = j7;
} else {
j = -1;
j2 = -1;
j3 = -1;
j4 = -1;
}
String str = TAG;
StringBuilder sb = new StringBuilder();
sb.append("CronetHttpURLConnection onSucceeded url=");
sb.append(this.url.toString());
sb.append(" receive_body_time=");
sb.append(j5);
sb.append(" receive_header_time=");
sb.append(j);
sb.append(" dns_time=");
sb.append(j2);
sb.append(" connect_time=");
sb.append(j3);
sb.append(" network_total_time=");
sb.append(j4);
sb.append(" requestHeader=");
sb.append(list.toString());
sb.append(" responseHeader=");
sb.append((urlResponseInfo == null || urlResponseInfo.getAllHeaders() == null) ? IAPInjectService.EP_NULL : urlResponseInfo.getAllHeaders().toString());
String str2 = "";
if (z) {
str2 = "" + cronetException.getMessage();
}
sb.append(str2);
TbsNetLiveLogger.error(str, sb.toString());
}
}
public void queenReport() {
KingCardRequest kingCardRequest = this.mKingCardRequest;
if (kingCardRequest == null || !kingCardRequest.e()) {
return;
}
QueenReporter.a(this.mKingCardRequest.c(), this.url.toString(), getRequestProperty("Referer"), this.mResponseInfo.getHttpStatusCode(), Long.parseLong(getRequestProperty("Content-Length")), this.mKingCardRequest.a(), this.mKingCardRequest.d(), this.mKingCardRequest.b(), !this.mKingCardRequest.e());
}
private final void setRequestPropertyInternal(String str, String str2, boolean z) {
if (this.connected) {
throw new IllegalStateException("Cannot modify request property after connection is made.");
}
int findRequestProperty = findRequestProperty(str);
if (findRequestProperty >= 0) {
if (!z) {
throw new UnsupportedOperationException("Cannot add multiple headers of the same key, " + str + ". crbug.com/432719.");
}
this.mRequestHeaders.remove(findRequestProperty);
}
this.mRequestHeaders.add(Pair.create(str, str2));
}
private void startRequest() throws IOException {
if (this.connected) {
return;
}
ExperimentalUrlRequest.Builder builder = (ExperimentalUrlRequest.Builder) this.mCronetEngine.newUrlRequestBuilder(getURL().toString(), new CronetUrlRequestCallback(), this.mMessageLoop);
prepareRequestHeaders(builder);
for (Pair<String, String> pair : this.mRequestHeaders) {
if (!((String) pair.first).equalsIgnoreCase("Accept-Encoding")) {
builder.addHeader((String) pair.first, (String) pair.second);
}
}
checkRequestHeader();
if (!getUseCaches()) {
builder.disableCache();
}
builder.setHttpMethod(this.method);
if (this.mTrafficStatsTagSet) {
builder.setTrafficStatsTag(this.mTrafficStatsTag);
}
if (this.mTrafficStatsUidSet) {
builder.setTrafficStatsUid(this.mTrafficStatsUid);
}
this.mRequest = builder.build();
this.mRequest.SetConnectionTimeout(this.mConnectionTimeout);
prepareAndTransformRequest();
this.mRequest.start();
this.startTime = System.currentTimeMillis();
this.connected = true;
}
public void uploadNetworkQualityToBeacon(final String str) {
this.endTime = System.currentTimeMillis();
if (this.mRandomGen.nextInt(100) >= 5 || this.mResponseInfo == null) {
return;
}
BrowserExecutorSupplier.postForIoTasks(new BrowserExecutorSupplier.BackgroundRunable() {
@Override
public void doRun() {
CronetHttpURLConnection.this.doUpload(str);
}
});
}
@Override
public final void addRequestProperty(String str, String str2) {
setRequestPropertyInternal(str, str2, false);
}
@Override
public void connect() throws IOException {
getOutputStream();
}
@Override
public void disconnect() {
if (this.connected) {
this.mRequest.cancel();
}
}
@Override
public String getCipherSuite() {
return null;
}
@Override
public InputStream getErrorStream() {
try {
getResponse();
if (this.mResponseInfo.getHttpStatusCode() >= 400) {
return this.mInputStream;
}
return null;
} catch (IOException unused) {
return null;
}
}
@Override
public final String getHeaderField(int i) {
Map.Entry<String, String> headerFieldEntry = getHeaderFieldEntry(i);
if (headerFieldEntry == null) {
return null;
}
return headerFieldEntry.getValue();
}
@Override
public final String getHeaderField(String str) {
try {
getResponse();
Map<String, List<String>> allHeaders = getAllHeaders();
if (!allHeaders.containsKey(str)) {
return null;
}
return allHeaders.get(str).get(r4.size() - 1);
} catch (IOException unused) {
return null;
}
}
@Override
public final String getHeaderFieldKey(int i) {
Map.Entry<String, String> headerFieldEntry = getHeaderFieldEntry(i);
if (headerFieldEntry == null) {
return null;
}
return headerFieldEntry.getKey();
}
@Override
public Map<String, List<String>> getHeaderFields() {
try {
getResponse();
return getAllHeaders();
} catch (IOException unused) {
return Collections.emptyMap();
}
}
@Override
public InputStream getInputStream() throws IOException {
getResponse();
if (!this.instanceFollowRedirects && this.mOnRedirectCalled) {
throw new IOException("Cannot read response body of a redirect.");
}
if (this.mResponseInfo.getHttpStatusCode() < 400) {
return this.mInputStream;
}
throw new FileNotFoundException(this.url.toString());
}
@Override
public Certificate[] getLocalCertificates() {
return null;
}
public void getMoreData(ByteBuffer byteBuffer) throws IOException {
this.mRequest.read(byteBuffer);
this.mMessageLoop.loop(getReadTimeout());
}
@Override
public OutputStream getOutputStream() throws IOException {
if (this.mOutputStream == null && (this.doOutput || this.method.equals("POST"))) {
if (this.connected) {
throw new ProtocolException("Cannot write to OutputStream after receiving response.");
}
if (isChunkedUpload()) {
this.mOutputStream = new CronetChunkedOutputStream(this.chunkLength, this.mMessageLoop);
} else {
long streamingModeContentLength = getStreamingModeContentLength();
if (streamingModeContentLength != -1) {
this.mOutputStream = new CronetFixedModeOutputStream(streamingModeContentLength, this.mMessageLoop);
} else {
String requestProperty = getRequestProperty("Content-Length");
if (requestProperty == null) {
this.mOutputStream = new CronetBufferedOutputStream();
} else {
this.mOutputStream = new CronetBufferedOutputStream(Long.parseLong(requestProperty));
}
}
}
startRequest();
}
return this.mOutputStream;
}
@Override
public Map<String, List<String>> getRequestProperties() {
if (this.connected) {
throw new IllegalStateException("Cannot access request headers after connection is set.");
}
TreeMap treeMap = new TreeMap(String.CASE_INSENSITIVE_ORDER);
for (Pair<String, String> pair : this.mRequestHeaders) {
if (treeMap.containsKey(pair.first)) {
throw new IllegalStateException("Should not have multiple values.");
}
ArrayList arrayList = new ArrayList();
arrayList.add(pair.second);
treeMap.put(pair.first, Collections.unmodifiableList(arrayList));
}
return Collections.unmodifiableMap(treeMap);
}
@Override
public String getRequestProperty(String str) {
int findRequestProperty = findRequestProperty(str);
if (findRequestProperty >= 0) {
return (String) this.mRequestHeaders.get(findRequestProperty).second;
}
return null;
}
@Override
public int getResponseCode() throws IOException {
getResponse();
return this.mResponseInfo.getHttpStatusCode();
}
@Override
public String getResponseMessage() throws IOException {
getResponse();
return this.mResponseInfo.getHttpStatusText();
}
@Override
public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException {
return null;
}
@Override
public void setConnectTimeout(int i) {
this.mConnectionTimeout = i;
}
@Override
public final void setRequestProperty(String str, String str2) {
setRequestPropertyInternal(str, str2, true);
}
public void setTrafficStatsTag(int i) {
if (this.connected) {
throw new IllegalStateException("Cannot modify traffic stats tag after connection is made.");
}
this.mTrafficStatsTagSet = true;
this.mTrafficStatsTag = i;
}
public void setTrafficStatsUid(int i) {
if (this.connected) {
throw new IllegalStateException("Cannot modify traffic stats UID after connection is made.");
}
this.mTrafficStatsUidSet = true;
this.mTrafficStatsUid = i;
}
@Override
public boolean usingProxy() {
return false;
}
}