OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/browser/loader/intercepting_resource_handler.h" | 5 #include "content/browser/loader/intercepting_resource_handler.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/ptr_util.h" |
8 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "content/browser/loader/null_resource_controller.h" |
| 11 #include "content/browser/loader/resource_controller.h" |
9 #include "content/public/common/resource_response.h" | 12 #include "content/public/common/resource_response.h" |
10 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
11 #include "net/url_request/url_request.h" | 14 #include "net/url_request/url_request.h" |
12 | 15 |
13 namespace content { | 16 namespace content { |
14 | 17 |
| 18 class InterceptingResourceHandler::Controller : public ResourceController { |
| 19 public: |
| 20 explicit Controller(InterceptingResourceHandler* mime_handler) |
| 21 : intercepting_handler_(mime_handler) {} |
| 22 |
| 23 void Resume() override { |
| 24 DCHECK(!used_); |
| 25 used_ = true; |
| 26 intercepting_handler_->ResumeInternal(); |
| 27 } |
| 28 |
| 29 void Cancel() override { |
| 30 DCHECK(!used_); |
| 31 used_ = true; |
| 32 intercepting_handler_->Cancel(); |
| 33 } |
| 34 |
| 35 void CancelAndIgnore() override { |
| 36 DCHECK(!used_); |
| 37 used_ = true; |
| 38 intercepting_handler_->CancelAndIgnore(); |
| 39 } |
| 40 |
| 41 void CancelWithError(int error_code) override { |
| 42 DCHECK(!used_); |
| 43 used_ = true; |
| 44 intercepting_handler_->CancelWithError(error_code); |
| 45 } |
| 46 |
| 47 private: |
| 48 InterceptingResourceHandler* intercepting_handler_; |
| 49 bool used_ = false; |
| 50 |
| 51 DISALLOW_COPY_AND_ASSIGN(Controller); |
| 52 }; |
| 53 |
15 InterceptingResourceHandler::InterceptingResourceHandler( | 54 InterceptingResourceHandler::InterceptingResourceHandler( |
16 std::unique_ptr<ResourceHandler> next_handler, | 55 std::unique_ptr<ResourceHandler> next_handler, |
17 net::URLRequest* request) | 56 net::URLRequest* request) |
18 : LayeredResourceHandler(request, std::move(next_handler)) { | 57 : LayeredResourceHandler(request, std::move(next_handler)) { |
19 next_handler_->SetController(this); | |
20 } | 58 } |
21 | 59 |
22 InterceptingResourceHandler::~InterceptingResourceHandler() {} | 60 InterceptingResourceHandler::~InterceptingResourceHandler() {} |
23 | 61 |
24 void InterceptingResourceHandler::SetController( | 62 void InterceptingResourceHandler::OnResponseStarted( |
25 ResourceController* controller) { | 63 ResourceResponse* response, |
26 if (state_ == State::PASS_THROUGH) | 64 std::unique_ptr<ResourceController> controller) { |
27 return LayeredResourceHandler::SetController(controller); | |
28 ResourceHandler::SetController(controller); | |
29 } | |
30 | |
31 bool InterceptingResourceHandler::OnResponseStarted(ResourceResponse* response, | |
32 bool* defer) { | |
33 // If there's no need to switch handlers, just start acting as a blind | 65 // If there's no need to switch handlers, just start acting as a blind |
34 // pass-through ResourceHandler. | 66 // pass-through ResourceHandler. |
35 if (!new_handler_) { | 67 if (!new_handler_) { |
36 state_ = State::PASS_THROUGH; | 68 state_ = State::PASS_THROUGH; |
37 next_handler_->SetController(controller()); | 69 next_handler_->OnResponseStarted(response, std::move(controller)); |
38 return next_handler_->OnResponseStarted(response, defer); | 70 return; |
39 } | 71 } |
40 | 72 |
41 DCHECK_EQ(state_, State::STARTING); | 73 DCHECK_EQ(state_, State::STARTING); |
42 // Otherwise, switch handlers. First, inform the original ResourceHandler | |
43 // that this will be handled entirely by the new ResourceHandler. | |
44 bool defer_ignored = false; | |
45 if (!next_handler_->OnResponseStarted(response, &defer_ignored)) | |
46 return false; | |
47 | |
48 // Although deferring OnResponseStarted is legal, the only downstream handler | |
49 // which does so is CrossSiteResourceHandler. Cross-site transitions should | |
50 // not trigger when switching handlers. | |
51 DCHECK(!defer_ignored); | |
52 | 74 |
53 // TODO(yhirano): Retaining ownership from a raw pointer is bad. | 75 // TODO(yhirano): Retaining ownership from a raw pointer is bad. |
54 response_ = response; | 76 response_ = response; |
| 77 |
| 78 // Otherwise, switch handlers. First, inform the original ResourceHandler |
| 79 // that this will be handled entirely by the new ResourceHandler. |
| 80 set_controller(std::move(controller)); |
55 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; | 81 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; |
56 return DoLoop(defer); | 82 next_handler_->OnResponseStarted(response, |
| 83 base::MakeUnique<Controller>(this)); |
| 84 return; |
57 } | 85 } |
58 | 86 |
59 bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 87 bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
60 int* buf_size, | 88 int* buf_size, |
61 int min_size) { | 89 int min_size) { |
62 if (state_ == State::PASS_THROUGH) | 90 if (state_ == State::PASS_THROUGH) |
63 return next_handler_->OnWillRead(buf, buf_size, min_size); | 91 return next_handler_->OnWillRead(buf, buf_size, min_size); |
64 | 92 |
65 DCHECK_EQ(State::STARTING, state_); | 93 DCHECK_EQ(State::STARTING, state_); |
66 DCHECK_EQ(-1, min_size); | 94 DCHECK_EQ(-1, min_size); |
67 | 95 |
68 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) | 96 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) |
69 return false; | 97 return false; |
70 | 98 |
71 first_read_buffer_ = *buf; | 99 first_read_buffer_ = *buf; |
72 first_read_buffer_size_ = *buf_size; | 100 first_read_buffer_size_ = *buf_size; |
73 first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); | 101 first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); |
74 *buf = first_read_buffer_double_; | 102 *buf = first_read_buffer_double_; |
75 return true; | 103 return true; |
76 } | 104 } |
77 | 105 |
78 bool InterceptingResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 106 void InterceptingResourceHandler::OnReadCompleted( |
| 107 int bytes_read, |
| 108 std::unique_ptr<ResourceController> controller) { |
| 109 DCHECK(!has_controller()); |
| 110 |
79 DCHECK_GE(bytes_read, 0); | 111 DCHECK_GE(bytes_read, 0); |
80 if (state_ == State::PASS_THROUGH) { | 112 if (state_ == State::PASS_THROUGH) { |
81 if (first_read_buffer_double_) { | 113 if (first_read_buffer_double_) { |
82 // |first_read_buffer_double_| was allocated and the user wrote data to | 114 // |first_read_buffer_double_| was allocated and the user wrote data to |
83 // the buffer, but switching has not been done after all. | 115 // the buffer, but switching has not been done after all. |
84 memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(), | 116 memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(), |
85 bytes_read); | 117 bytes_read); |
86 first_read_buffer_ = nullptr; | 118 first_read_buffer_ = nullptr; |
87 first_read_buffer_double_ = nullptr; | 119 first_read_buffer_double_ = nullptr; |
88 } | 120 } |
89 return next_handler_->OnReadCompleted(bytes_read, defer); | 121 next_handler_->OnReadCompleted(bytes_read, std::move(controller)); |
| 122 return; |
90 } | 123 } |
91 | 124 |
92 DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_); | 125 DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_); |
93 first_read_buffer_bytes_read_ = bytes_read; | 126 first_read_buffer_bytes_read_ = bytes_read; |
94 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER; | 127 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER; |
95 return DoLoop(defer); | 128 set_controller(std::move(controller)); |
| 129 DoLoop(); |
96 } | 130 } |
97 | 131 |
98 void InterceptingResourceHandler::OnResponseCompleted( | 132 void InterceptingResourceHandler::OnResponseCompleted( |
99 const net::URLRequestStatus& status, | 133 const net::URLRequestStatus& status, |
100 bool* defer) { | 134 std::unique_ptr<ResourceController> controller) { |
101 if (state_ == State::PASS_THROUGH) { | 135 if (state_ == State::PASS_THROUGH) { |
102 LayeredResourceHandler::OnResponseCompleted(status, defer); | 136 LayeredResourceHandler::OnResponseCompleted(status, std::move(controller)); |
103 return; | 137 return; |
104 } | 138 } |
105 if (!new_handler_) { | 139 if (!new_handler_) { |
106 // Therer is only one ResourceHandler in this InterceptingResourceHandler. | 140 // Therer is only one ResourceHandler in this InterceptingResourceHandler. |
107 state_ = State::PASS_THROUGH; | 141 state_ = State::PASS_THROUGH; |
108 first_read_buffer_double_ = nullptr; | 142 first_read_buffer_double_ = nullptr; |
109 next_handler_->SetController(controller()); | 143 next_handler_->OnResponseCompleted(status, std::move(controller)); |
110 next_handler_->OnResponseCompleted(status, defer); | |
111 return; | 144 return; |
112 } | 145 } |
113 | 146 |
114 // There are two ResourceHandlers in this InterceptingResourceHandler. | 147 // There are two ResourceHandlers in this InterceptingResourceHandler. |
115 // |next_handler_| is the old handler and |new_handler_| is the new handler. | 148 // |next_handler_| is the old handler and |new_handler_| is the new handler. |
116 // As written in the class comment, this class assumes that the old handler | 149 // As written in the class comment, this class assumes that the old handler |
117 // will not set |*defer| in OnResponseCompleted. | 150 // will immediately call Resume() in OnResponseCompleted. |
118 next_handler_->SetController(controller()); | 151 bool was_resumed = false; |
119 next_handler_->OnResponseCompleted(status, defer); | 152 next_handler_->OnResponseCompleted( |
120 DCHECK(!*defer); | 153 status, base::MakeUnique<NullResourceController>(&was_resumed)); |
| 154 DCHECK(was_resumed); |
121 | 155 |
122 state_ = State::PASS_THROUGH; | 156 state_ = State::PASS_THROUGH; |
123 first_read_buffer_double_ = nullptr; | 157 first_read_buffer_double_ = nullptr; |
124 new_handler_->SetController(controller()); | |
125 next_handler_ = std::move(new_handler_); | 158 next_handler_ = std::move(new_handler_); |
126 next_handler_->OnResponseCompleted(status, defer); | 159 next_handler_->OnResponseCompleted(status, std::move(controller)); |
127 } | 160 } |
128 | 161 |
129 void InterceptingResourceHandler::Cancel() { | 162 void InterceptingResourceHandler::ResumeInternal() { |
130 DCHECK_NE(State::PASS_THROUGH, state_); | 163 DCHECK(has_controller()); |
131 controller()->Cancel(); | |
132 } | |
133 | |
134 void InterceptingResourceHandler::CancelAndIgnore() { | |
135 DCHECK_NE(State::PASS_THROUGH, state_); | |
136 controller()->CancelAndIgnore(); | |
137 } | |
138 | |
139 void InterceptingResourceHandler::CancelWithError(int error_code) { | |
140 DCHECK_NE(State::PASS_THROUGH, state_); | |
141 controller()->CancelWithError(error_code); | |
142 } | |
143 | |
144 void InterceptingResourceHandler::Resume() { | |
145 DCHECK_NE(State::PASS_THROUGH, state_); | |
146 if (state_ == State::STARTING || | 164 if (state_ == State::STARTING || |
147 state_ == State::WAITING_FOR_ON_READ_COMPLETED) { | 165 state_ == State::WAITING_FOR_ON_READ_COMPLETED || |
| 166 state_ == State::PASS_THROUGH) { |
148 // Uninteresting Resume: just delegate to the original resource controller. | 167 // Uninteresting Resume: just delegate to the original resource controller. |
149 controller()->Resume(); | 168 Resume(); |
150 return; | |
151 } | |
152 bool defer = false; | |
153 if (!DoLoop(&defer)) { | |
154 controller()->Cancel(); | |
155 return; | 169 return; |
156 } | 170 } |
157 | 171 |
158 if (!defer) | 172 DoLoop(); |
159 controller()->Resume(); | |
160 } | 173 } |
161 | 174 |
162 void InterceptingResourceHandler::UseNewHandler( | 175 void InterceptingResourceHandler::UseNewHandler( |
163 std::unique_ptr<ResourceHandler> new_handler, | 176 std::unique_ptr<ResourceHandler> new_handler, |
164 const std::string& payload_for_old_handler) { | 177 const std::string& payload_for_old_handler) { |
165 new_handler_ = std::move(new_handler); | 178 new_handler_ = std::move(new_handler); |
166 new_handler_->SetController(this); | 179 new_handler_->SetDelegate(delegate()); |
167 payload_for_old_handler_ = payload_for_old_handler; | 180 payload_for_old_handler_ = payload_for_old_handler; |
168 } | 181 } |
169 | 182 |
170 bool InterceptingResourceHandler::DoLoop(bool* defer) { | 183 void InterceptingResourceHandler::DoLoop() { |
171 bool result = true; | 184 switch (state_) { |
172 do { | 185 case State::STARTING: |
173 switch (state_) { | 186 case State::WAITING_FOR_ON_READ_COMPLETED: |
174 case State::STARTING: | 187 case State::PASS_THROUGH: |
175 case State::WAITING_FOR_ON_READ_COMPLETED: | 188 NOTREACHED(); |
176 case State::PASS_THROUGH: | 189 break; |
177 NOTREACHED(); | 190 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: |
178 break; | 191 SendOnResponseStartedToNewHandler(); |
179 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: | 192 break; |
180 result = SendOnResponseStartedToNewHandler(defer); | 193 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER: |
181 break; | 194 if (first_read_buffer_double_) { |
182 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER: | 195 // OnWillRead has been called, so copying the data from |
183 if (first_read_buffer_double_) { | 196 // |first_read_buffer_double_| to |first_read_buffer_| will be needed |
184 // OnWillRead has been called, so copying the data from | 197 // when OnReadCompleted is called. |
185 // |first_read_buffer_double_| to |first_read_buffer_| will be needed | 198 state_ = State::WAITING_FOR_ON_READ_COMPLETED; |
186 // when OnReadCompleted is called. | 199 ResumeInternal(); |
187 state_ = State::WAITING_FOR_ON_READ_COMPLETED; | 200 } else { |
188 } else { | 201 // OnWillRead has not been called, so no special handling will be |
189 // OnWillRead has not been called, so no special handling will be | 202 // needed from now on. |
190 // needed from now on. | 203 state_ = State::PASS_THROUGH; |
191 state_ = State::PASS_THROUGH; | 204 ResumeInternal(); |
192 next_handler_->SetController(controller()); | 205 } |
193 } | 206 break; |
194 break; | 207 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: |
195 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: | 208 SendPayloadToOldHandler(); |
196 result = SendPayloadToOldHandler(defer); | 209 break; |
197 break; | 210 case State::SENDING_BUFFER_TO_NEW_HANDLER: |
198 case State::SENDING_BUFFER_TO_NEW_HANDLER: | 211 SendFirstReadBufferToNewHandler(); |
199 result = SendFirstReadBufferToNewHandler(defer); | 212 break; |
200 break; | 213 } |
201 } | |
202 } while (result && !*defer && | |
203 state_ != State::WAITING_FOR_ON_READ_COMPLETED && | |
204 state_ != State::PASS_THROUGH); | |
205 return result; | |
206 } | 214 } |
207 | 215 |
208 bool InterceptingResourceHandler::SendPayloadToOldHandler(bool* defer) { | 216 void InterceptingResourceHandler::SendPayloadToOldHandler() { |
209 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); | 217 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); |
210 while (payload_bytes_written_ < payload_for_old_handler_.size()) { | 218 if (payload_bytes_written_ == payload_for_old_handler_.size()) { |
211 scoped_refptr<net::IOBuffer> buffer; | 219 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); |
212 int size = 0; | 220 if (payload_for_old_handler_.empty()) { |
213 if (first_read_buffer_) { | 221 // If there is no payload, just finalize the request on the old handler. |
214 // |first_read_buffer_| is a buffer gotten from |next_handler_| via | 222 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); |
215 // OnWillRead. Use the buffer. | 223 } |
216 buffer = first_read_buffer_; | 224 bool was_resumed = false; |
217 size = first_read_buffer_size_; | 225 next_handler_->OnResponseCompleted( |
| 226 status, base::MakeUnique<NullResourceController>(&was_resumed)); |
| 227 DCHECK(was_resumed); |
218 | 228 |
219 first_read_buffer_ = nullptr; | 229 next_handler_ = std::move(new_handler_); |
220 first_read_buffer_size_ = 0; | 230 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; |
221 } else { | 231 next_handler_->OnWillStart(request()->url(), |
222 if (!next_handler_->OnWillRead(&buffer, &size, -1)) | 232 base::MakeUnique<Controller>(this)); |
223 return false; | 233 return; |
224 } | |
225 | |
226 size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - | |
227 payload_bytes_written_)); | |
228 memcpy(buffer->data(), | |
229 payload_for_old_handler_.data() + payload_bytes_written_, size); | |
230 if (!next_handler_->OnReadCompleted(size, defer)) | |
231 return false; | |
232 payload_bytes_written_ += size; | |
233 if (*defer) | |
234 return true; | |
235 } | 234 } |
236 | 235 |
237 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); | 236 scoped_refptr<net::IOBuffer> buffer; |
238 if (payload_for_old_handler_.empty()) { | 237 int size = 0; |
239 // If there is no payload, just finalize the request on the old handler. | 238 if (first_read_buffer_) { |
240 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); | 239 // |first_read_buffer_| is a buffer gotten from |next_handler_| via |
| 240 // OnWillRead. Use the buffer. |
| 241 buffer = first_read_buffer_; |
| 242 size = first_read_buffer_size_; |
| 243 |
| 244 first_read_buffer_ = nullptr; |
| 245 first_read_buffer_size_ = 0; |
| 246 } else { |
| 247 if (!next_handler_->OnWillRead(&buffer, &size, -1)) { |
| 248 Cancel(); |
| 249 return; |
| 250 } |
241 } | 251 } |
242 next_handler_->OnResponseCompleted(status, defer); | |
243 DCHECK(!*defer); | |
244 | 252 |
245 next_handler_ = std::move(new_handler_); | 253 size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - |
246 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; | 254 payload_bytes_written_)); |
247 return next_handler_->OnWillStart(request()->url(), defer); | 255 memcpy(buffer->data(), |
| 256 payload_for_old_handler_.data() + payload_bytes_written_, size); |
| 257 payload_bytes_written_ += size; |
| 258 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); |
248 } | 259 } |
249 | 260 |
250 bool InterceptingResourceHandler::SendOnResponseStartedToNewHandler( | 261 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() { |
251 bool* defer) { | |
252 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; | 262 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; |
253 return next_handler_->OnResponseStarted(response_.get(), defer); | 263 next_handler_->OnResponseStarted(response_.get(), |
| 264 base::MakeUnique<Controller>(this)); |
254 } | 265 } |
255 | 266 |
256 bool InterceptingResourceHandler::SendFirstReadBufferToNewHandler(bool* defer) { | 267 void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() { |
257 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); | 268 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); |
258 | 269 |
259 while (first_read_buffer_bytes_written_ < first_read_buffer_bytes_read_) { | 270 if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) { |
260 scoped_refptr<net::IOBuffer> buf; | 271 state_ = State::PASS_THROUGH; |
261 int size = 0; | 272 first_read_buffer_double_ = nullptr; |
262 if (!next_handler_->OnWillRead(&buf, &size, -1)) | 273 ResumeInternal(); |
263 return false; | 274 return; |
264 size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - | |
265 first_read_buffer_bytes_written_)); | |
266 memcpy(buf->data(), | |
267 first_read_buffer_double_->data() + first_read_buffer_bytes_written_, | |
268 size); | |
269 if (!next_handler_->OnReadCompleted(size, defer)) | |
270 return false; | |
271 first_read_buffer_bytes_written_ += size; | |
272 if (*defer) | |
273 return true; | |
274 } | 275 } |
275 | 276 |
276 state_ = State::PASS_THROUGH; | 277 scoped_refptr<net::IOBuffer> buf; |
277 first_read_buffer_double_ = nullptr; | 278 int size = 0; |
278 next_handler_->SetController(controller()); | 279 if (!next_handler_->OnWillRead(&buf, &size, -1)) { |
279 return true; | 280 Cancel(); |
| 281 return; |
| 282 } |
| 283 size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - |
| 284 first_read_buffer_bytes_written_)); |
| 285 memcpy(buf->data(), |
| 286 first_read_buffer_double_->data() + first_read_buffer_bytes_written_, |
| 287 size); |
| 288 first_read_buffer_bytes_written_ += size; |
| 289 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); |
280 } | 290 } |
281 | 291 |
282 } // namespace content | 292 } // namespace content |
OLD | NEW |