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

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

Powered by Google App Engine
This is Rietveld 408576698