blob: 95195b63f53c2dd7935d563ebb38f012c50d32ba [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net.impl;
import org.chromium.net.UrlResponseInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* Implements the container for basic information about a response. Included in
* {@link org.chromium.net.UrlRequest.Callback} callbacks. Each
* {@link org.chromium.net.UrlRequest.Callback#onRedirectReceived onRedirectReceived()}
* callback gets a different copy of {@code UrlResponseInfo} describing a particular
* redirect response.
*/
public final class UrlResponseInfoImpl extends UrlResponseInfo {
private final List<String> mResponseInfoUrlChain;
private final int mHttpStatusCode;
private final String mHttpStatusText;
private final boolean mWasCached;
private final String mNegotiatedProtocol;
private final String mProxyServer;
private final AtomicLong mReceivedByteCount;
private final HeaderBlockImpl mHeaders;
/** Unmodifiable container of response headers or trailers. */
public static final class HeaderBlockImpl extends HeaderBlock {
private final List<Map.Entry<String, String>> mAllHeadersList;
private Map<String, List<String>> mHeadersMap;
HeaderBlockImpl(List<Map.Entry<String, String>> allHeadersList) {
mAllHeadersList = allHeadersList;
}
@Override
public List<Map.Entry<String, String>> getAsList() {
return mAllHeadersList;
}
@Override
public Map<String, List<String>> getAsMap() {
// This is potentially racy...but races will only result in wasted resource.
if (mHeadersMap != null) {
return mHeadersMap;
}
Map<String, List<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, String> entry : mAllHeadersList) {
List<String> values = new ArrayList<String>();
if (map.containsKey(entry.getKey())) {
values.addAll(map.get(entry.getKey()));
}
values.add(entry.getValue());
map.put(entry.getKey(), Collections.unmodifiableList(values));
}
mHeadersMap = Collections.unmodifiableMap(map);
return mHeadersMap;
}
}
/**
* Creates an implementation of {@link UrlResponseInfo}.
*
* @param urlChain the URL chain. The first entry is the originally requested URL;
* the following entries are redirects followed.
* @param httpStatusCode the HTTP status code.
* @param httpStatusText the HTTP status text of the status line.
* @param allHeadersList list of response header field and value pairs.
* @param wasCached {@code true} if the response came from the cache, {@code false}
* otherwise.
* @param negotiatedProtocol the protocol negotiated with the server.
* @param proxyServer the proxy server that was used for the request.
* @param receivedByteCount minimum count of bytes received from the network to process this
* request.
*/
public UrlResponseInfoImpl(
List<String> urlChain,
int httpStatusCode,
String httpStatusText,
List<Map.Entry<String, String>> allHeadersList,
boolean wasCached,
String negotiatedProtocol,
String proxyServer,
long receivedByteCount) {
mResponseInfoUrlChain = Collections.unmodifiableList(urlChain);
mHttpStatusCode = httpStatusCode;
mHttpStatusText = httpStatusText;
mHeaders = new HeaderBlockImpl(Collections.unmodifiableList(allHeadersList));
mWasCached = wasCached;
mNegotiatedProtocol = negotiatedProtocol;
mProxyServer = proxyServer;
mReceivedByteCount = new AtomicLong(receivedByteCount);
}
/** Constructor for backwards compatibility. See main constructor above for more info. */
@Deprecated
public UrlResponseInfoImpl(
List<String> urlChain,
int httpStatusCode,
String httpStatusText,
List<Map.Entry<String, String>> allHeadersList,
boolean wasCached,
String negotiatedProtocol,
String proxyServer) {
this(
urlChain,
httpStatusCode,
httpStatusText,
allHeadersList,
wasCached,
negotiatedProtocol,
proxyServer,
0);
}
@Override
public String getUrl() {
return mResponseInfoUrlChain.get(mResponseInfoUrlChain.size() - 1);
}
@Override
public List<String> getUrlChain() {
return mResponseInfoUrlChain;
}
@Override
public int getHttpStatusCode() {
return mHttpStatusCode;
}
@Override
public String getHttpStatusText() {
return mHttpStatusText;
}
@Override
public List<Map.Entry<String, String>> getAllHeadersAsList() {
return mHeaders.getAsList();
}
@Override
public Map<String, List<String>> getAllHeaders() {
return mHeaders.getAsMap();
}
@Override
public boolean wasCached() {
return mWasCached;
}
@Override
public String getNegotiatedProtocol() {
return mNegotiatedProtocol;
}
@Override
public String getProxyServer() {
return mProxyServer;
}
@Override
public long getReceivedByteCount() {
return mReceivedByteCount.get();
}
@Override
public String toString() {
return String.format(
Locale.ROOT,
"UrlResponseInfo@[%s][%s]: urlChain = %s, "
+ "httpStatus = %d %s, headers = %s, wasCached = %b, "
+ "negotiatedProtocol = %s, proxyServer= %s, receivedByteCount = %d",
// Prevent asserting on the contents of this string
Integer.toHexString(System.identityHashCode(this)),
getUrl(),
getUrlChain().toString(),
getHttpStatusCode(),
getHttpStatusText(),
getAllHeadersAsList().toString(),
wasCached(),
getNegotiatedProtocol(),
getProxyServer(),
getReceivedByteCount());
}
/** Sets mReceivedByteCount. Must not be called after request completion or cancellation. */
public void setReceivedByteCount(long currentReceivedByteCount) {
mReceivedByteCount.set(currentReceivedByteCount);
}
}