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

Side by Side Diff: android_webview/browser/net/android_stream_reader_url_request_job.cc

Issue 11428052: [android_webview] Fix use after free in intercepted requests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "android_webview/browser/net/android_stream_reader_url_request_job.h" 5 #include "android_webview/browser/net/android_stream_reader_url_request_job.h"
6 6
7 #include "android_webview/browser/input_stream.h" 7 #include "android_webview/browser/input_stream.h"
8 #include "android_webview/browser/net/input_stream_reader.h" 8 #include "android_webview/browser/net/input_stream_reader.h"
9 #include "base/android/jni_android.h" 9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h" 10 #include "base/android/jni_string.h"
(...skipping 12 matching lines...) Expand all
23 #include "net/http/http_util.h" 23 #include "net/http/http_util.h"
24 #include "net/url_request/url_request.h" 24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_job_manager.h" 25 #include "net/url_request/url_request_job_manager.h"
26 26
27 using android_webview::InputStream; 27 using android_webview::InputStream;
28 using android_webview::InputStreamReader; 28 using android_webview::InputStreamReader;
29 using base::android::AttachCurrentThread; 29 using base::android::AttachCurrentThread;
30 using base::PostTaskAndReplyWithResult; 30 using base::PostTaskAndReplyWithResult;
31 using content::BrowserThread; 31 using content::BrowserThread;
32 32
33 // The requests posted to the worker thread might outlive the job. Thread-safe
34 // ref counting is used to ensure that the InputStream and InputStreamReader
35 // members of this class are still there when the closure is run on the worker
36 // thread.
37 class InputStreamReaderWrapper :
38 public base::RefCountedThreadSafe<InputStreamReaderWrapper> {
39 public:
40 InputStreamReaderWrapper(
41 scoped_ptr<InputStream> input_stream,
42 scoped_ptr<InputStreamReader> input_stream_reader)
43 : input_stream_(input_stream.Pass()),
44 input_stream_reader_(input_stream_reader.Pass()) {
45 DCHECK(input_stream_);
46 DCHECK(input_stream_reader_);
47 }
48
49 android_webview::InputStream* input_stream() {
50 return input_stream_.get();
51 }
52
53 int Seek(const net::HttpByteRange& byte_range) {
54 return input_stream_reader_->Seek(byte_range);
55 }
56
57 int ReadRawData(net::IOBuffer* buffer, int buffer_size) {
58 return input_stream_reader_->ReadRawData(buffer, buffer_size);
59 }
60
61 private:
62 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>;
63 ~InputStreamReaderWrapper() {}
64
65 scoped_ptr<android_webview::InputStream> input_stream_;
66 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_;
67
68 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper);
69 };
70
33 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( 71 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob(
34 net::URLRequest* request, 72 net::URLRequest* request,
35 net::NetworkDelegate* network_delegate, 73 net::NetworkDelegate* network_delegate,
36 scoped_ptr<Delegate> delegate) 74 scoped_ptr<Delegate> delegate)
37 : URLRequestJob(request, network_delegate), 75 : URLRequestJob(request, network_delegate),
38 delegate_(delegate.Pass()), 76 delegate_(delegate.Pass()),
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 77 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
40 DCHECK(delegate_.get()); 78 DCHECK(delegate_);
41 } 79 }
42 80
43 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { 81 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() {
44 } 82 }
45 83
46 void AndroidStreamReaderURLRequestJob::Start() { 84 void AndroidStreamReaderURLRequestJob::Start() {
47 // Start reading asynchronously so that all error reporting and data 85 // Start reading asynchronously so that all error reporting and data
48 // callbacks happen as they would for network requests. 86 // callbacks happen as they would for network requests.
49 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); 87 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
88 net::ERR_IO_PENDING));
50 MessageLoop::current()->PostTask( 89 MessageLoop::current()->PostTask(
51 FROM_HERE, 90 FROM_HERE,
52 base::Bind( 91 base::Bind(
53 &AndroidStreamReaderURLRequestJob::StartAsync, 92 &AndroidStreamReaderURLRequestJob::StartAsync,
54 weak_factory_.GetWeakPtr())); 93 weak_factory_.GetWeakPtr()));
55 } 94 }
56 95
57 void AndroidStreamReaderURLRequestJob::Kill() { 96 void AndroidStreamReaderURLRequestJob::Kill() {
58 weak_factory_.InvalidateWeakPtrs(); 97 weak_factory_.InvalidateWeakPtrs();
59 URLRequestJob::Kill(); 98 URLRequestJob::Kill();
60 } 99 }
61 100
62 scoped_refptr<InputStreamReader> 101 scoped_ptr<InputStreamReader>
63 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) { 102 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) {
64 return make_scoped_refptr(new InputStreamReader(stream)); 103 return make_scoped_ptr(new InputStreamReader(stream));
65 } 104 }
66 105
67 void AndroidStreamReaderURLRequestJob::StartAsync() { 106 void AndroidStreamReaderURLRequestJob::StartAsync() {
68 JNIEnv* env = AttachCurrentThread(); 107 JNIEnv* env = AttachCurrentThread();
69 DCHECK(env); 108 DCHECK(env);
70 109
71 // This could be done in the InputStreamReader but would force more 110 // This could be done in the InputStreamReader but would force more
72 // complex synchronization in the delegate. 111 // complex synchronization in the delegate.
73 stream_ = delegate_->OpenInputStream(env, request()); 112 scoped_ptr<android_webview::InputStream> stream(
74 if (!stream_) { 113 delegate_->OpenInputStream(env, request()));
75 NotifyDone( 114
76 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); 115 if (!stream) {
116 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
117 net::ERR_FAILED));
77 return; 118 return;
78 } 119 }
79 120
80 DCHECK(!input_stream_reader_); 121 scoped_ptr<InputStreamReader> input_stream_reader(
81 input_stream_reader_ = CreateStreamReader(stream_.get()); 122 CreateStreamReader(stream.get()));
82 CHECK(input_stream_reader_); 123 DCHECK(input_stream_reader);
124
125 DCHECK(!input_stream_reader_wrapper_);
126 input_stream_reader_wrapper_ =
127 new InputStreamReaderWrapper(stream.Pass(), input_stream_reader.Pass());
83 128
84 PostTaskAndReplyWithResult( 129 PostTaskAndReplyWithResult(
85 GetWorkerThreadRunner(), 130 GetWorkerThreadRunner(),
86 FROM_HERE, 131 FROM_HERE,
87 base::Bind(&InputStreamReader::Seek, input_stream_reader_, byte_range_), 132 base::Bind(&InputStreamReaderWrapper::Seek,
133 input_stream_reader_wrapper_,
134 byte_range_),
88 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, 135 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted,
89 weak_factory_.GetWeakPtr())); 136 weak_factory_.GetWeakPtr()));
90 } 137 }
91 138
92 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted( 139 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) {
93 int result) {
94 // Clear the IO_PENDING status set in Start(). 140 // Clear the IO_PENDING status set in Start().
95 SetStatus(net::URLRequestStatus()); 141 SetStatus(net::URLRequestStatus());
96 if (result >= 0) { 142 if (result >= 0) {
97 set_expected_content_size(result); 143 set_expected_content_size(result);
98 NotifyHeadersComplete(); 144 NotifyHeadersComplete();
99 } else { 145 } else {
100 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); 146 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
101 } 147 }
102 } 148 }
103 149
104 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted( 150 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) {
105 int result) {
106 // The URLRequest API contract requires that: 151 // The URLRequest API contract requires that:
107 // * NotifyDone be called once, to set the status code, indicate the job is 152 // * NotifyDone be called once, to set the status code, indicate the job is
108 // finished (there will be no further IO), 153 // finished (there will be no further IO),
109 // * NotifyReadComplete be called if false is returned from ReadRawData to 154 // * NotifyReadComplete be called if false is returned from ReadRawData to
110 // indicate that the IOBuffer will not be used by the job anymore. 155 // indicate that the IOBuffer will not be used by the job anymore.
111 // There might be multiple calls to ReadRawData (and thus multiple calls to 156 // There might be multiple calls to ReadRawData (and thus multiple calls to
112 // NotifyReadComplete), which is why NotifyDone is called only on errors 157 // NotifyReadComplete), which is why NotifyDone is called only on errors
113 // (result < 0) and end of data (result == 0). 158 // (result < 0) and end of data (result == 0).
114 if (result == 0) { 159 if (result == 0) {
115 NotifyDone(net::URLRequestStatus()); 160 NotifyDone(net::URLRequestStatus());
116 } else if (result < 0) { 161 } else if (result < 0) {
117 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); 162 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
118 } else { 163 } else {
119 // Clear the IO_PENDING status. 164 // Clear the IO_PENDING status.
120 SetStatus(net::URLRequestStatus()); 165 SetStatus(net::URLRequestStatus());
121 } 166 }
122 NotifyReadComplete(result); 167 NotifyReadComplete(result);
123 } 168 }
124 169
125 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { 170 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() {
126 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); 171 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool());
127 } 172 }
128 173
129 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, 174 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
130 int dest_size, 175 int dest_size,
131 int* bytes_read) { 176 int* bytes_read) {
132 DCHECK(input_stream_reader_); 177 DCHECK(input_stream_reader_wrapper_);
133 178
134 PostTaskAndReplyWithResult( 179 PostTaskAndReplyWithResult(
135 GetWorkerThreadRunner(), 180 GetWorkerThreadRunner(),
136 FROM_HERE, 181 FROM_HERE,
137 base::Bind(&InputStreamReader::ReadRawData, 182 base::Bind(&InputStreamReaderWrapper::ReadRawData,
138 input_stream_reader_, 183 input_stream_reader_wrapper_,
139 base::Unretained(dest), 184 make_scoped_refptr(dest),
140 dest_size), 185 dest_size),
141 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, 186 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted,
142 weak_factory_.GetWeakPtr())); 187 weak_factory_.GetWeakPtr()));
143 188
144 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); 189 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
190 net::ERR_IO_PENDING));
145 return false; 191 return false;
146 } 192 }
147 193
148 bool AndroidStreamReaderURLRequestJob::GetMimeType( 194 bool AndroidStreamReaderURLRequestJob::GetMimeType(
149 std::string* mime_type) const { 195 std::string* mime_type) const {
150 JNIEnv* env = AttachCurrentThread(); 196 JNIEnv* env = AttachCurrentThread();
151 DCHECK(env); 197 DCHECK(env);
152 198
153 if (!stream_) 199 if (!input_stream_reader_wrapper_)
154 return false; 200 return false;
155 201
156 return delegate_->GetMimeType(env, request(), *stream_, mime_type); 202 // Since it's possible for this call to alter the InputStream a
203 // Seek or ReadRawData operation running in the background is not permitted.
204 DCHECK(!request_->status().is_io_pending());
205
206 return delegate_->GetMimeType(
207 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type);
157 } 208 }
158 209
159 bool AndroidStreamReaderURLRequestJob::GetCharset( 210 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) {
160 std::string* charset) {
161 JNIEnv* env = AttachCurrentThread(); 211 JNIEnv* env = AttachCurrentThread();
162 DCHECK(env); 212 DCHECK(env);
163 213
164 if (!stream_) 214 if (!input_stream_reader_wrapper_)
165 return false; 215 return false;
166 216
167 return delegate_->GetCharset(env, request(), *stream_, charset); 217 // Since it's possible for this call to alter the InputStream a
218 // Seek or ReadRawData operation running in the background is not permitted.
219 DCHECK(!request_->status().is_io_pending());
220
221 return delegate_->GetCharset(
222 env, request(), input_stream_reader_wrapper_->input_stream(), charset);
168 } 223 }
169 224
170 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( 225 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
171 const net::HttpRequestHeaders& headers) { 226 const net::HttpRequestHeaders& headers) {
172 std::string range_header; 227 std::string range_header;
173 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { 228 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
174 // We only extract the "Range" header so that we know how many bytes in the 229 // We only extract the "Range" header so that we know how many bytes in the
175 // stream to skip and how many to read after that. 230 // stream to skip and how many to read after that.
176 std::vector<net::HttpByteRange> ranges; 231 std::vector<net::HttpByteRange> ranges;
177 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { 232 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
178 if (ranges.size() == 1) { 233 if (ranges.size() == 1) {
179 byte_range_ = ranges[0]; 234 byte_range_ = ranges[0];
180 } else { 235 } else {
181 // We don't support multiple range requests in one single URL request, 236 // We don't support multiple range requests in one single URL request,
182 // because we need to do multipart encoding here. 237 // because we need to do multipart encoding here.
183 NotifyDone(net::URLRequestStatus( 238 NotifyDone(net::URLRequestStatus(
184 net::URLRequestStatus::FAILED, 239 net::URLRequestStatus::FAILED,
185 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 240 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
186 } 241 }
187 } 242 }
188 } 243 }
189 } 244 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698