• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.util.Log;
9 import android.util.Pair;
10 
11 import org.chromium.net.CronetEngine;
12 import org.chromium.net.ExperimentalUrlRequest;
13 import org.chromium.net.RequestFinishedInfo;
14 import org.chromium.net.UploadDataProvider;
15 import org.chromium.net.UrlRequest;
16 
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.concurrent.Executor;
20 
21 /** Implements {@link org.chromium.net.ExperimentalUrlRequest.Builder}. */
22 public class UrlRequestBuilderImpl extends ExperimentalUrlRequest.Builder {
23     private static final String ACCEPT_ENCODING = "Accept-Encoding";
24     private static final String TAG = UrlRequestBuilderImpl.class.getSimpleName();
25 
26     // All fields are temporary storage of ExperimentalUrlRequest configuration to be
27     // copied to built ExperimentalUrlRequest.
28 
29     // CronetEngineBase to execute request.
30     private final CronetEngineBase mCronetEngine;
31     // URL to request.
32     private final String mUrl;
33     // Callback to receive progress callbacks.
34     private final UrlRequest.Callback mCallback;
35     // Executor to invoke callback on.
36     private final Executor mExecutor;
37     // HTTP method (e.g. GET, POST etc).
38     private String mMethod;
39 
40     // List of request headers, stored as header field name and value pairs.
41     private final ArrayList<Pair<String, String>> mRequestHeaders = new ArrayList<>();
42     // Disable the cache for just this request.
43     private boolean mDisableCache;
44     // Disable connection migration for just this request.
45     private boolean mDisableConnectionMigration;
46     // Priority of request. Default is medium.
47     @CronetEngineBase.RequestPriority private int mPriority = REQUEST_PRIORITY_MEDIUM;
48     // Request reporting annotations. Avoid extra object creation if no annotations added.
49     private Collection<Object> mRequestAnnotations;
50     // If request is an upload, this provides the request body data.
51     private UploadDataProvider mUploadDataProvider;
52     // Executor to call upload data provider back on.
53     private Executor mUploadDataProviderExecutor;
54     private boolean mAllowDirectExecutor;
55     private boolean mTrafficStatsTagSet;
56     private int mTrafficStatsTag;
57     private boolean mTrafficStatsUidSet;
58     private int mTrafficStatsUid;
59     private RequestFinishedInfo.Listener mRequestFinishedListener;
60     private long mNetworkHandle = CronetEngineBase.DEFAULT_NETWORK_HANDLE;
61     // Idempotency of the request.
62     @CronetEngineBase.Idempotency private int mIdempotency = DEFAULT_IDEMPOTENCY;
63 
64     /**
65      * Creates a builder for {@link UrlRequest} objects. All callbacks for
66      * generated {@link UrlRequest} objects will be invoked on
67      * {@code executor}'s thread. {@code executor} must not run tasks on the
68      * current thread to prevent blocking networking operations and causing
69      * exceptions during shutdown.
70      *
71      * @param url URL for the generated requests.
72      * @param callback callback object that gets invoked on different events.
73      * @param executor {@link Executor} on which all callbacks will be invoked.
74      * @param cronetEngine {@link CronetEngine} used to execute this request.
75      */
UrlRequestBuilderImpl( String url, UrlRequest.Callback callback, Executor executor, CronetEngineBase cronetEngine)76     UrlRequestBuilderImpl(
77             String url,
78             UrlRequest.Callback callback,
79             Executor executor,
80             CronetEngineBase cronetEngine) {
81         super();
82         if (url == null) {
83             throw new NullPointerException("URL is required.");
84         }
85         if (callback == null) {
86             throw new NullPointerException("Callback is required.");
87         }
88         if (executor == null) {
89             throw new NullPointerException("Executor is required.");
90         }
91         if (cronetEngine == null) {
92             throw new NullPointerException("CronetEngine is required.");
93         }
94         mUrl = url;
95         mCallback = callback;
96         mExecutor = executor;
97         mCronetEngine = cronetEngine;
98     }
99 
100     @Override
setHttpMethod(String method)101     public ExperimentalUrlRequest.Builder setHttpMethod(String method) {
102         if (method == null) {
103             throw new NullPointerException("Method is required.");
104         }
105         mMethod = method;
106         return this;
107     }
108 
109     @Override
addHeader(String header, String value)110     public UrlRequestBuilderImpl addHeader(String header, String value) {
111         if (header == null) {
112             throw new NullPointerException("Invalid header name.");
113         }
114         if (value == null) {
115             throw new NullPointerException("Invalid header value.");
116         }
117         if (ACCEPT_ENCODING.equalsIgnoreCase(header)) {
118             Log.w(
119                     TAG,
120                     "It's not necessary to set Accept-Encoding on requests - cronet will do"
121                             + " this automatically for you, and setting it yourself has no "
122                             + "effect. See https://crbug.com/581399 for details.",
123                     new Exception());
124             return this;
125         }
126         mRequestHeaders.add(Pair.create(header, value));
127         return this;
128     }
129 
130     @Override
disableCache()131     public UrlRequestBuilderImpl disableCache() {
132         mDisableCache = true;
133         return this;
134     }
135 
136     @Override
disableConnectionMigration()137     public UrlRequestBuilderImpl disableConnectionMigration() {
138         mDisableConnectionMigration = true;
139         return this;
140     }
141 
142     @Override
setPriority(@ronetEngineBase.RequestPriority int priority)143     public UrlRequestBuilderImpl setPriority(@CronetEngineBase.RequestPriority int priority) {
144         mPriority = priority;
145         return this;
146     }
147 
148     @Override
setIdempotency(@ronetEngineBase.Idempotency int idempotency)149     public UrlRequestBuilderImpl setIdempotency(@CronetEngineBase.Idempotency int idempotency) {
150         mIdempotency = idempotency;
151         return this;
152     }
153 
154     @Override
setUploadDataProvider( UploadDataProvider uploadDataProvider, Executor executor)155     public UrlRequestBuilderImpl setUploadDataProvider(
156             UploadDataProvider uploadDataProvider, Executor executor) {
157         if (uploadDataProvider == null) {
158             throw new NullPointerException("Invalid UploadDataProvider.");
159         }
160         if (executor == null) {
161             throw new NullPointerException("Invalid UploadDataProvider Executor.");
162         }
163         if (mMethod == null) {
164             mMethod = "POST";
165         }
166         mUploadDataProvider = uploadDataProvider;
167         mUploadDataProviderExecutor = executor;
168         return this;
169     }
170 
171     @Override
allowDirectExecutor()172     public UrlRequestBuilderImpl allowDirectExecutor() {
173         mAllowDirectExecutor = true;
174         return this;
175     }
176 
177     @Override
addRequestAnnotation(Object annotation)178     public UrlRequestBuilderImpl addRequestAnnotation(Object annotation) {
179         if (annotation == null) {
180             throw new NullPointerException("Invalid metrics annotation.");
181         }
182         if (mRequestAnnotations == null) {
183             mRequestAnnotations = new ArrayList<>();
184         }
185         mRequestAnnotations.add(annotation);
186         return this;
187     }
188 
189     @Override
setTrafficStatsTag(int tag)190     public UrlRequestBuilderImpl setTrafficStatsTag(int tag) {
191         mTrafficStatsTagSet = true;
192         mTrafficStatsTag = tag;
193         return this;
194     }
195 
196     @Override
setTrafficStatsUid(int uid)197     public UrlRequestBuilderImpl setTrafficStatsUid(int uid) {
198         mTrafficStatsUidSet = true;
199         mTrafficStatsUid = uid;
200         return this;
201     }
202 
203     @Override
setRequestFinishedListener(RequestFinishedInfo.Listener listener)204     public UrlRequestBuilderImpl setRequestFinishedListener(RequestFinishedInfo.Listener listener) {
205         mRequestFinishedListener = listener;
206         return this;
207     }
208 
209     @Override
bindToNetwork(long networkHandle)210     public UrlRequestBuilderImpl bindToNetwork(long networkHandle) {
211         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
212             throw new UnsupportedOperationException(
213                     "The multi-network API is available starting from Android Marshmallow");
214         }
215         mNetworkHandle = networkHandle;
216         return this;
217     }
218 
219     @Override
build()220     public UrlRequestBase build() {
221         @SuppressLint("WrongConstant") // TODO(jbudorick): Remove this after rolling to the N SDK.
222         final UrlRequestBase request =
223                 mCronetEngine.createRequest(
224                         mUrl,
225                         mCallback,
226                         mExecutor,
227                         mPriority,
228                         mRequestAnnotations,
229                         mDisableCache,
230                         mDisableConnectionMigration,
231                         mAllowDirectExecutor,
232                         mTrafficStatsTagSet,
233                         mTrafficStatsTag,
234                         mTrafficStatsUidSet,
235                         mTrafficStatsUid,
236                         mRequestFinishedListener,
237                         mIdempotency,
238                         mNetworkHandle);
239         if (mMethod != null) {
240             request.setHttpMethod(mMethod);
241         }
242         for (Pair<String, String> header : mRequestHeaders) {
243             request.addHeader(header.first, header.second);
244         }
245         if (mUploadDataProvider != null) {
246             request.setUploadDataProvider(mUploadDataProvider, mUploadDataProviderExecutor);
247         }
248         return request;
249     }
250 }
251