1 package android.net.http; 2 3 import androidx.annotation.NonNull; 4 5 import java.util.ArrayList; 6 import java.util.Collections; 7 import java.util.List; 8 import java.util.Map; 9 import java.util.TreeMap; 10 11 // This is an almost identical clone of org.chromium.net.impl.UrlResponseInfoImpl.HeaderBlockImpl 12 // with few minor changes to `mAllHeadersList`. This is needed because we need to maintain the 13 // request headers in the wrapper layer between HttpEngine and CronetEngine because the wrapper 14 // does not have access to the backend's HeaderBlock. This results in the HeaderBlocks being 15 // duplicated, once inside HttpEngine and another time inside CronetEngine. 16 public final class HeaderBlockImpl extends android.net.http.HeaderBlock { 17 private final List<Map.Entry<String, String>> mAllHeadersList; 18 private Map<String, List<String>> mAllHeadersMap; 19 HeaderBlockImpl(List<Map.Entry<String, String>> allHeaders)20 public HeaderBlockImpl(List<Map.Entry<String, String>> allHeaders) { 21 this.mAllHeadersList = Collections.unmodifiableList(allHeaders); 22 } 23 24 @NonNull 25 @Override getAsList()26 public List<Map.Entry<String, String>> getAsList() { 27 return mAllHeadersList; 28 } 29 30 @NonNull 31 @Override getAsMap()32 public Map<String, List<String>> getAsMap() { 33 if (mAllHeadersMap != null) { 34 return mAllHeadersMap; 35 } 36 synchronized (mAllHeadersList) { 37 // This is potentially racy...but races will only result in multiple creation 38 // of the same map. 39 Map<String, List<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 40 for (Map.Entry<String, String> entry : mAllHeadersList) { 41 List<String> values = new ArrayList<>(); 42 if (map.containsKey(entry.getKey())) { 43 values.addAll(map.get(entry.getKey())); 44 } 45 values.add(entry.getValue()); 46 map.put(entry.getKey(), Collections.unmodifiableList(values)); 47 } 48 mAllHeadersMap = Collections.unmodifiableMap(map); 49 } 50 return mAllHeadersMap; 51 } 52 } 53