Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(544)

Side by Side Diff: components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java

Issue 2613393002: [Cronet] In JavaUrlRequest avoid thread-unsafe access to HttpURLConnection (Closed)
Patch Set: address comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/cronet/android/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.net.impl; 5 package org.chromium.net.impl;
6 6
7 import android.annotation.SuppressLint; 7 import android.annotation.SuppressLint;
8 import android.annotation.TargetApi; 8 import android.annotation.TargetApi;
9 import android.net.TrafficStats; 9 import android.net.TrafficStats;
10 import android.os.Build; 10 import android.os.Build;
(...skipping 10 matching lines...) Expand all
21 import java.io.IOException; 21 import java.io.IOException;
22 import java.io.OutputStream; 22 import java.io.OutputStream;
23 import java.net.HttpURLConnection; 23 import java.net.HttpURLConnection;
24 import java.net.URI; 24 import java.net.URI;
25 import java.net.URL; 25 import java.net.URL;
26 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
27 import java.nio.channels.Channels; 27 import java.nio.channels.Channels;
28 import java.nio.channels.ReadableByteChannel; 28 import java.nio.channels.ReadableByteChannel;
29 import java.nio.channels.WritableByteChannel; 29 import java.nio.channels.WritableByteChannel;
30 import java.util.AbstractMap.SimpleEntry; 30 import java.util.AbstractMap.SimpleEntry;
31 import java.util.ArrayDeque;
31 import java.util.ArrayList; 32 import java.util.ArrayList;
32 import java.util.Collections; 33 import java.util.Collections;
33 import java.util.List; 34 import java.util.List;
34 import java.util.Map; 35 import java.util.Map;
35 import java.util.TreeMap; 36 import java.util.TreeMap;
36 import java.util.concurrent.Executor; 37 import java.util.concurrent.Executor;
37 import java.util.concurrent.RejectedExecutionException; 38 import java.util.concurrent.RejectedExecutionException;
38 import java.util.concurrent.atomic.AtomicBoolean; 39 import java.util.concurrent.atomic.AtomicBoolean;
39 import java.util.concurrent.atomic.AtomicReference; 40 import java.util.concurrent.atomic.AtomicReference;
40 41
42 import javax.annotation.concurrent.GuardedBy;
43
41 /** 44 /**
42 * Pure java UrlRequest, backed by {@link HttpURLConnection}. 45 * Pure java UrlRequest, backed by {@link HttpURLConnection}.
43 */ 46 */
44 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) // TrafficStats only availabl e on ICS 47 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) // TrafficStats only availabl e on ICS
45 final class JavaUrlRequest extends UrlRequestBase { 48 final class JavaUrlRequest extends UrlRequestBase {
46 private static final String X_ANDROID = "X-Android"; 49 private static final String X_ANDROID = "X-Android";
47 private static final String X_ANDROID_SELECTED_TRANSPORT = "X-Android-Select ed-Transport"; 50 private static final String X_ANDROID_SELECTED_TRANSPORT = "X-Android-Select ed-Transport";
48 private static final String TAG = "JavaUrlConnection"; 51 private static final String TAG = "JavaUrlConnection";
49 private static final int DEFAULT_UPLOAD_BUFFER_SIZE = 8192; 52 private static final int DEFAULT_UPLOAD_BUFFER_SIZE = 8192;
50 private static final int DEFAULT_CHUNK_LENGTH = DEFAULT_UPLOAD_BUFFER_SIZE; 53 private static final int DEFAULT_CHUNK_LENGTH = DEFAULT_UPLOAD_BUFFER_SIZE;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 STARTED, 122 STARTED,
120 REDIRECT_RECEIVED, 123 REDIRECT_RECEIVED,
121 AWAITING_FOLLOW_REDIRECT, 124 AWAITING_FOLLOW_REDIRECT,
122 AWAITING_READ, 125 AWAITING_READ,
123 READING, 126 READING,
124 ERROR, 127 ERROR,
125 COMPLETE, 128 COMPLETE,
126 CANCELLED, 129 CANCELLED,
127 } 130 }
128 131
132 // Executor that runs one task at a time on an underlying Executor.
133 private class SeriaizingExecutor implements Executor {
Charles 2017/01/11 16:50:05 private final class
pauljensen 2017/01/11 16:53:50 Done.
134 private final Executor mUnderlyingExecutor;
135 // Queue of tasks to run. First element is the task currently executing .
136 // Task processing loop is running if queue is not empty. Synchronized on itself.
137 @GuardedBy("mTaskQueue")
138 private final ArrayDeque<Runnable> mTaskQueue = new ArrayDeque<>();
139
140 public SeriaizingExecutor(Executor underlyingExecutor) {
Charles 2017/01/11 16:50:05 No need for public
pauljensen 2017/01/11 16:53:50 Done.
141 mUnderlyingExecutor = underlyingExecutor;
142 }
143
144 private void runTask(final Runnable task) {
145 mUnderlyingExecutor.execute(new Runnable() {
146 @Override
147 public void run() {
148 try {
149 task.run();
150 } finally {
151 Runnable nextTask;
152 synchronized (mTaskQueue) {
153 mTaskQueue.removeFirst();
154 nextTask = mTaskQueue.peekFirst();
155 }
156 if (nextTask != null) {
157 runTask(nextTask);
158 }
159 }
160 }
161 });
162 }
163
164 @Override
165 public void execute(Runnable command) {
166 synchronized (mTaskQueue) {
167 mTaskQueue.addLast(command);
168 // Task processing loop is already running if there are other it ems in mTaskQueue.
169 if (mTaskQueue.size() > 1) {
170 return;
171 }
172 }
173 runTask(command);
174 };
175 }
176
129 /** 177 /**
130 * @param executor The executor used for reading and writing from sockets 178 * @param executor The executor used for reading and writing from sockets
131 * @param userExecutor The executor used to dispatch to {@code callback} 179 * @param userExecutor The executor used to dispatch to {@code callback}
132 */ 180 */
133 JavaUrlRequest(Callback callback, final Executor executor, Executor userExec utor, String url, 181 JavaUrlRequest(Callback callback, final Executor executor, Executor userExec utor, String url,
134 String userAgent, boolean allowDirectExecutor) { 182 String userAgent, boolean allowDirectExecutor) {
135 if (url == null) { 183 if (url == null) {
136 throw new NullPointerException("URL is required"); 184 throw new NullPointerException("URL is required");
137 } 185 }
138 if (callback == null) { 186 if (callback == null) {
139 throw new NullPointerException("Listener is required"); 187 throw new NullPointerException("Listener is required");
140 } 188 }
141 if (executor == null) { 189 if (executor == null) {
142 throw new NullPointerException("Executor is required"); 190 throw new NullPointerException("Executor is required");
143 } 191 }
144 if (userExecutor == null) { 192 if (userExecutor == null) {
145 throw new NullPointerException("userExecutor is required"); 193 throw new NullPointerException("userExecutor is required");
146 } 194 }
147 195
148 this.mAllowDirectExecutor = allowDirectExecutor; 196 this.mAllowDirectExecutor = allowDirectExecutor;
149 this.mCallbackAsync = new AsyncUrlRequestCallback(callback, userExecutor ); 197 this.mCallbackAsync = new AsyncUrlRequestCallback(callback, userExecutor );
150 this.mTrafficStatsTag = TrafficStats.getThreadStatsTag(); 198 this.mTrafficStatsTag = TrafficStats.getThreadStatsTag();
151 this.mExecutor = new Executor() { 199 this.mExecutor = new SeriaizingExecutor(new Executor() {
152 @Override 200 @Override
153 public void execute(final Runnable command) { 201 public void execute(final Runnable command) {
154 executor.execute(new Runnable() { 202 executor.execute(new Runnable() {
155 @Override 203 @Override
156 public void run() { 204 public void run() {
157 int oldTag = TrafficStats.getThreadStatsTag(); 205 int oldTag = TrafficStats.getThreadStatsTag();
158 TrafficStats.setThreadStatsTag(mTrafficStatsTag); 206 TrafficStats.setThreadStatsTag(mTrafficStatsTag);
159 try { 207 try {
160 command.run(); 208 command.run();
161 } finally { 209 } finally {
162 TrafficStats.setThreadStatsTag(oldTag); 210 TrafficStats.setThreadStatsTag(oldTag);
163 } 211 }
164 } 212 }
165 }); 213 });
166 } 214 }
167 }; 215 });
168 this.mCurrentUrl = url; 216 this.mCurrentUrl = url;
169 this.mUserAgent = userAgent; 217 this.mUserAgent = userAgent;
170 } 218 }
171 219
172 @Override 220 @Override
173 public void setHttpMethod(String method) { 221 public void setHttpMethod(String method) {
174 checkNotStarted(); 222 checkNotStarted();
175 if (method == null) { 223 if (method == null) {
176 throw new NullPointerException("Method is required."); 224 throw new NullPointerException("Method is required.");
177 } 225 }
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 // Can't throw directly from here, since the delegate execut or could catch this 1020 // Can't throw directly from here, since the delegate execut or could catch this
973 // exception. 1021 // exception.
974 mExecutedInline = new InlineExecutionProhibitedException(); 1022 mExecutedInline = new InlineExecutionProhibitedException();
975 return; 1023 return;
976 } 1024 }
977 mCommand.run(); 1025 mCommand.run();
978 } 1026 }
979 } 1027 }
980 } 1028 }
981 } 1029 }
OLDNEW
« no previous file with comments | « components/cronet/android/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698