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 package org.chromium.net.impl; 5 6 import android.annotation.SuppressLint; 7 import android.os.Build; 8 9 import org.chromium.net.BidirectionalStream; 10 import org.chromium.net.CronetEngine; 11 import org.chromium.net.ExperimentalBidirectionalStream; 12 13 import java.util.AbstractMap; 14 import java.util.ArrayList; 15 import java.util.Collection; 16 import java.util.Map; 17 import java.util.concurrent.Executor; 18 19 /** Implementation of {@link ExperimentalBidirectionalStream.Builder}. */ 20 public class BidirectionalStreamBuilderImpl extends ExperimentalBidirectionalStream.Builder { 21 // All fields are temporary storage of ExperimentalBidirectionalStream configuration to be 22 // copied to CronetBidirectionalStream. 23 24 // CronetEngine to create the stream. 25 private final CronetEngineBase mCronetEngine; 26 // URL to request. 27 private final String mUrl; 28 // Callback to receive progress callbacks. 29 private final BidirectionalStream.Callback mCallback; 30 // Executor on which callbacks will be invoked. 31 private final Executor mExecutor; 32 // List of request headers, stored as header field name and value pairs. 33 private final ArrayList<Map.Entry<String, String>> mRequestHeaders = new ArrayList<>(); 34 35 // HTTP method for the request. Default to POST. 36 private String mHttpMethod = "POST"; 37 // Priority of the stream. Default is medium. 38 @CronetEngineBase.StreamPriority private int mPriority = STREAM_PRIORITY_MEDIUM; 39 40 private boolean mDelayRequestHeadersUntilFirstFlush; 41 42 // Request reporting annotations. 43 private Collection<Object> mRequestAnnotations; 44 45 private boolean mTrafficStatsTagSet; 46 private int mTrafficStatsTag; 47 private boolean mTrafficStatsUidSet; 48 private int mTrafficStatsUid; 49 private long mNetworkHandle = CronetEngineBase.DEFAULT_NETWORK_HANDLE; 50 51 /** 52 * Creates a builder for {@link BidirectionalStream} objects. All callbacks for 53 * generated {@code BidirectionalStream} objects will be invoked on 54 * {@code executor}. {@code executor} must not run tasks on the 55 * current thread, otherwise the networking operations may block and exceptions 56 * may be thrown at shutdown time. 57 * 58 * @param url the URL for the generated stream 59 * @param callback the {@link BidirectionalStream.Callback} object that gets invoked upon 60 * different events 61 * occuring 62 * @param executor the {@link Executor} on which {@code callback} methods will be invoked 63 * @param cronetEngine the {@link CronetEngine} used to create the stream 64 */ BidirectionalStreamBuilderImpl( String url, BidirectionalStream.Callback callback, Executor executor, CronetEngineBase cronetEngine)65 BidirectionalStreamBuilderImpl( 66 String url, 67 BidirectionalStream.Callback callback, 68 Executor executor, 69 CronetEngineBase cronetEngine) { 70 super(); 71 if (url == null) { 72 throw new NullPointerException("URL is required."); 73 } 74 if (callback == null) { 75 throw new NullPointerException("Callback is required."); 76 } 77 if (executor == null) { 78 throw new NullPointerException("Executor is required."); 79 } 80 if (cronetEngine == null) { 81 throw new NullPointerException("CronetEngine is required."); 82 } 83 mUrl = url; 84 mCallback = callback; 85 mExecutor = executor; 86 mCronetEngine = cronetEngine; 87 } 88 89 @Override setHttpMethod(String method)90 public BidirectionalStreamBuilderImpl setHttpMethod(String method) { 91 if (method == null) { 92 throw new NullPointerException("Method is required."); 93 } 94 mHttpMethod = method; 95 return this; 96 } 97 98 @Override addHeader(String header, String value)99 public BidirectionalStreamBuilderImpl addHeader(String header, String value) { 100 if (header == null) { 101 throw new NullPointerException("Invalid header name."); 102 } 103 if (value == null) { 104 throw new NullPointerException("Invalid header value."); 105 } 106 mRequestHeaders.add(new AbstractMap.SimpleImmutableEntry<>(header, value)); 107 return this; 108 } 109 110 @Override setPriority( @ronetEngineBase.StreamPriority int priority)111 public BidirectionalStreamBuilderImpl setPriority( 112 @CronetEngineBase.StreamPriority int priority) { 113 mPriority = priority; 114 return this; 115 } 116 117 @Override delayRequestHeadersUntilFirstFlush( boolean delayRequestHeadersUntilFirstFlush)118 public BidirectionalStreamBuilderImpl delayRequestHeadersUntilFirstFlush( 119 boolean delayRequestHeadersUntilFirstFlush) { 120 mDelayRequestHeadersUntilFirstFlush = delayRequestHeadersUntilFirstFlush; 121 return this; 122 } 123 124 @Override addRequestAnnotation(Object annotation)125 public ExperimentalBidirectionalStream.Builder addRequestAnnotation(Object annotation) { 126 if (annotation == null) { 127 throw new NullPointerException("Invalid metrics annotation."); 128 } 129 if (mRequestAnnotations == null) { 130 mRequestAnnotations = new ArrayList<Object>(); 131 } 132 mRequestAnnotations.add(annotation); 133 return this; 134 } 135 136 @Override setTrafficStatsTag(int tag)137 public ExperimentalBidirectionalStream.Builder setTrafficStatsTag(int tag) { 138 mTrafficStatsTagSet = true; 139 mTrafficStatsTag = tag; 140 return this; 141 } 142 143 @Override setTrafficStatsUid(int uid)144 public ExperimentalBidirectionalStream.Builder setTrafficStatsUid(int uid) { 145 mTrafficStatsUidSet = true; 146 mTrafficStatsUid = uid; 147 return this; 148 } 149 150 @Override bindToNetwork(long networkHandle)151 public ExperimentalBidirectionalStream.Builder bindToNetwork(long networkHandle) { 152 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 153 throw new UnsupportedOperationException( 154 "The multi-network API is available starting from Android Marshmallow"); 155 } 156 mNetworkHandle = networkHandle; 157 return this; 158 } 159 160 @Override 161 @SuppressLint("WrongConstant") // TODO(jbudorick): Remove this after rolling to the N SDK. build()162 public ExperimentalBidirectionalStream build() { 163 return mCronetEngine.createBidirectionalStream( 164 mUrl, 165 mCallback, 166 mExecutor, 167 mHttpMethod, 168 mRequestHeaders, 169 mPriority, 170 mDelayRequestHeadersUntilFirstFlush, 171 mRequestAnnotations, 172 mTrafficStatsTagSet, 173 mTrafficStatsTag, 174 mTrafficStatsUidSet, 175 mTrafficStatsUid, 176 mNetworkHandle); 177 } 178 } 179