1 // Copyright 2016 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net.impl; 6 7 import org.chromium.net.UrlResponseInfo; 8 9 import java.util.ArrayList; 10 import java.util.Collections; 11 import java.util.List; 12 import java.util.Locale; 13 import java.util.Map; 14 import java.util.TreeMap; 15 import java.util.concurrent.atomic.AtomicLong; 16 17 /** 18 * Implements the container for basic information about a response. Included in 19 * {@link org.chromium.net.UrlRequest.Callback} callbacks. Each 20 * {@link org.chromium.net.UrlRequest.Callback#onRedirectReceived onRedirectReceived()} 21 * callback gets a different copy of {@code UrlResponseInfo} describing a particular 22 * redirect response. 23 */ 24 public final class UrlResponseInfoImpl extends UrlResponseInfo { 25 private final List<String> mResponseInfoUrlChain; 26 private final int mHttpStatusCode; 27 private final String mHttpStatusText; 28 private final boolean mWasCached; 29 private final String mNegotiatedProtocol; 30 private final String mProxyServer; 31 private final AtomicLong mReceivedByteCount; 32 private final HeaderBlockImpl mHeaders; 33 34 /** Unmodifiable container of response headers or trailers. */ 35 public static final class HeaderBlockImpl extends HeaderBlock { 36 private final List<Map.Entry<String, String>> mAllHeadersList; 37 private Map<String, List<String>> mHeadersMap; 38 HeaderBlockImpl(List<Map.Entry<String, String>> allHeadersList)39 HeaderBlockImpl(List<Map.Entry<String, String>> allHeadersList) { 40 mAllHeadersList = allHeadersList; 41 } 42 43 @Override getAsList()44 public List<Map.Entry<String, String>> getAsList() { 45 return mAllHeadersList; 46 } 47 48 @Override getAsMap()49 public Map<String, List<String>> getAsMap() { 50 // This is potentially racy...but races will only result in wasted resource. 51 if (mHeadersMap != null) { 52 return mHeadersMap; 53 } 54 Map<String, List<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 55 for (Map.Entry<String, String> entry : mAllHeadersList) { 56 List<String> values = new ArrayList<String>(); 57 if (map.containsKey(entry.getKey())) { 58 values.addAll(map.get(entry.getKey())); 59 } 60 values.add(entry.getValue()); 61 map.put(entry.getKey(), Collections.unmodifiableList(values)); 62 } 63 mHeadersMap = Collections.unmodifiableMap(map); 64 return mHeadersMap; 65 } 66 } 67 68 /** 69 * Creates an implementation of {@link UrlResponseInfo}. 70 * 71 * @param urlChain the URL chain. The first entry is the originally requested URL; 72 * the following entries are redirects followed. 73 * @param httpStatusCode the HTTP status code. 74 * @param httpStatusText the HTTP status text of the status line. 75 * @param allHeadersList list of response header field and value pairs. 76 * @param wasCached {@code true} if the response came from the cache, {@code false} 77 * otherwise. 78 * @param negotiatedProtocol the protocol negotiated with the server. 79 * @param proxyServer the proxy server that was used for the request. 80 * @param receivedByteCount minimum count of bytes received from the network to process this 81 * request. 82 */ UrlResponseInfoImpl( List<String> urlChain, int httpStatusCode, String httpStatusText, List<Map.Entry<String, String>> allHeadersList, boolean wasCached, String negotiatedProtocol, String proxyServer, long receivedByteCount)83 public UrlResponseInfoImpl( 84 List<String> urlChain, 85 int httpStatusCode, 86 String httpStatusText, 87 List<Map.Entry<String, String>> allHeadersList, 88 boolean wasCached, 89 String negotiatedProtocol, 90 String proxyServer, 91 long receivedByteCount) { 92 mResponseInfoUrlChain = Collections.unmodifiableList(urlChain); 93 mHttpStatusCode = httpStatusCode; 94 mHttpStatusText = httpStatusText; 95 mHeaders = new HeaderBlockImpl(Collections.unmodifiableList(allHeadersList)); 96 mWasCached = wasCached; 97 mNegotiatedProtocol = negotiatedProtocol; 98 mProxyServer = proxyServer; 99 mReceivedByteCount = new AtomicLong(receivedByteCount); 100 } 101 102 /** Constructor for backwards compatibility. See main constructor above for more info. */ 103 @Deprecated UrlResponseInfoImpl( List<String> urlChain, int httpStatusCode, String httpStatusText, List<Map.Entry<String, String>> allHeadersList, boolean wasCached, String negotiatedProtocol, String proxyServer)104 public UrlResponseInfoImpl( 105 List<String> urlChain, 106 int httpStatusCode, 107 String httpStatusText, 108 List<Map.Entry<String, String>> allHeadersList, 109 boolean wasCached, 110 String negotiatedProtocol, 111 String proxyServer) { 112 this( 113 urlChain, 114 httpStatusCode, 115 httpStatusText, 116 allHeadersList, 117 wasCached, 118 negotiatedProtocol, 119 proxyServer, 120 0); 121 } 122 123 @Override getUrl()124 public String getUrl() { 125 return mResponseInfoUrlChain.get(mResponseInfoUrlChain.size() - 1); 126 } 127 128 @Override getUrlChain()129 public List<String> getUrlChain() { 130 return mResponseInfoUrlChain; 131 } 132 133 @Override getHttpStatusCode()134 public int getHttpStatusCode() { 135 return mHttpStatusCode; 136 } 137 138 @Override getHttpStatusText()139 public String getHttpStatusText() { 140 return mHttpStatusText; 141 } 142 143 @Override getAllHeadersAsList()144 public List<Map.Entry<String, String>> getAllHeadersAsList() { 145 return mHeaders.getAsList(); 146 } 147 148 @Override getAllHeaders()149 public Map<String, List<String>> getAllHeaders() { 150 return mHeaders.getAsMap(); 151 } 152 153 @Override wasCached()154 public boolean wasCached() { 155 return mWasCached; 156 } 157 158 @Override getNegotiatedProtocol()159 public String getNegotiatedProtocol() { 160 return mNegotiatedProtocol; 161 } 162 163 @Override getProxyServer()164 public String getProxyServer() { 165 return mProxyServer; 166 } 167 168 @Override getReceivedByteCount()169 public long getReceivedByteCount() { 170 return mReceivedByteCount.get(); 171 } 172 173 @Override toString()174 public String toString() { 175 return String.format( 176 Locale.ROOT, 177 "UrlResponseInfo@[%s][%s]: urlChain = %s, " 178 + "httpStatus = %d %s, headers = %s, wasCached = %b, " 179 + "negotiatedProtocol = %s, proxyServer= %s, receivedByteCount = %d", 180 // Prevent asserting on the contents of this string 181 Integer.toHexString(System.identityHashCode(this)), 182 getUrl(), 183 getUrlChain().toString(), 184 getHttpStatusCode(), 185 getHttpStatusText(), 186 getAllHeadersAsList().toString(), 187 wasCached(), 188 getNegotiatedProtocol(), 189 getProxyServer(), 190 getReceivedByteCount()); 191 } 192 193 /** Sets mReceivedByteCount. Must not be called after request completion or cancellation. */ setReceivedByteCount(long currentReceivedByteCount)194 public void setReceivedByteCount(long currentReceivedByteCount) { 195 mReceivedByteCount.set(currentReceivedByteCount); 196 } 197 } 198