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

Side by Side Diff: content/child/npapi/plugin_url_fetcher.cc

Issue 1426923007: Remove PluginLoadObserver and related logic, it was only used for NPAPI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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
« no previous file with comments | « content/child/npapi/plugin_url_fetcher.h ('k') | content/child/npapi/webplugin.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/child/npapi/plugin_url_fetcher.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "content/child/child_thread_impl.h"
9 #include "content/child/multipart_response_delegate.h"
10 #include "content/child/npapi/plugin_host.h"
11 #include "content/child/npapi/plugin_instance.h"
12 #include "content/child/npapi/plugin_stream_url.h"
13 #include "content/child/npapi/webplugin.h"
14 #include "content/child/npapi/webplugin_resource_client.h"
15 #include "content/child/plugin_messages.h"
16 #include "content/child/request_extra_data.h"
17 #include "content/child/request_info.h"
18 #include "content/child/resource_dispatcher.h"
19 #include "content/child/web_url_loader_impl.h"
20 #include "content/common/resource_request_body.h"
21 #include "content/common/service_worker/service_worker_types.h"
22 #include "content/public/common/resource_response_info.h"
23 #include "net/base/load_flags.h"
24 #include "net/base/net_errors.h"
25 #include "net/http/http_response_headers.h"
26 #include "net/url_request/redirect_info.h"
27 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
28 #include "third_party/WebKit/public/platform/WebURLResponse.h"
29
30 namespace content {
31 namespace {
32
33 // This class handles individual multipart responses. It is instantiated when
34 // we receive HTTP status code 206 in the HTTP response. This indicates
35 // that the response could have multiple parts each separated by a boundary
36 // specified in the response header.
37 // TODO(jam): this is similar to MultiPartResponseClient in webplugin_impl.cc,
38 // we should remove that other class once we switch to loading from the plugin
39 // process by default.
40 class MultiPartResponseClient : public blink::WebURLLoaderClient {
41 public:
42 explicit MultiPartResponseClient(PluginStreamUrl* plugin_stream)
43 : byte_range_lower_bound_(0), plugin_stream_(plugin_stream) {}
44
45 // blink::WebURLLoaderClient implementation:
46 void didReceiveResponse(blink::WebURLLoader* loader,
47 const blink::WebURLResponse& response) override {
48 int64 byte_range_upper_bound, instance_size;
49 if (!MultipartResponseDelegate::ReadContentRanges(response,
50 &byte_range_lower_bound_,
51 &byte_range_upper_bound,
52 &instance_size)) {
53 NOTREACHED();
54 }
55 }
56 void didReceiveData(blink::WebURLLoader* loader,
57 const char* data,
58 int data_length,
59 int encoded_data_length) override {
60 // TODO(ananta)
61 // We should defer further loads on multipart resources on the same lines
62 // as regular resources requested by plugins to prevent reentrancy.
63 int64 data_offset = byte_range_lower_bound_;
64 byte_range_lower_bound_ += data_length;
65 plugin_stream_->DidReceiveData(data, data_length, data_offset);
66 // DANGER: this instance may be deleted at this point.
67 }
68
69 private:
70 // The lower bound of the byte range.
71 int64 byte_range_lower_bound_;
72 // The handler for the data.
73 PluginStreamUrl* plugin_stream_;
74 };
75
76 } // namespace
77
78 PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
79 const GURL& url,
80 const GURL& first_party_for_cookies,
81 const std::string& method,
82 const char* buf,
83 unsigned int len,
84 const Referrer& referrer,
85 const std::string& range,
86 bool notify_redirects,
87 bool is_plugin_src_load,
88 int origin_pid,
89 int render_frame_id,
90 int render_view_id,
91 unsigned long resource_id,
92 bool copy_stream_data)
93 : plugin_stream_(plugin_stream),
94 url_(url),
95 first_party_for_cookies_(first_party_for_cookies),
96 referrer_(referrer),
97 notify_redirects_(notify_redirects),
98 is_plugin_src_load_(is_plugin_src_load),
99 origin_pid_(origin_pid),
100 render_frame_id_(render_frame_id),
101 render_view_id_(render_view_id),
102 resource_id_(resource_id),
103 copy_stream_data_(copy_stream_data),
104 data_offset_(0),
105 pending_failure_notification_(false),
106 request_id_(-1),
107 weak_factory_(this) {
108 RequestInfo request_info;
109 request_info.method = method;
110 request_info.url = url;
111 request_info.first_party_for_cookies = first_party_for_cookies;
112 request_info.referrer = referrer;
113 request_info.load_flags = net::LOAD_NORMAL;
114 request_info.requestor_pid = origin_pid;
115 request_info.request_type = RESOURCE_TYPE_OBJECT;
116 request_info.routing_id = render_view_id;
117 // ServiceWorker is disabled for NPAPI.
118 request_info.skip_service_worker = true;
119
120 RequestExtraData extra_data;
121 extra_data.set_render_frame_id(render_frame_id);
122 extra_data.set_is_main_frame(false);
123 request_info.extra_data = &extra_data;
124
125 std::vector<char> body;
126 if (method == "POST") {
127 bool content_type_found = false;
128 std::vector<std::string> names;
129 std::vector<std::string> values;
130 PluginHost::SetPostData(buf, len, &names, &values, &body);
131 for (size_t i = 0; i < names.size(); ++i) {
132 if (!request_info.headers.empty())
133 request_info.headers += "\r\n";
134 request_info.headers += names[i] + ": " + values[i];
135 if (base::LowerCaseEqualsASCII(names[i], "content-type"))
136 content_type_found = true;
137 }
138
139 if (!content_type_found) {
140 if (!request_info.headers.empty())
141 request_info.headers += "\r\n";
142 request_info.headers += "Content-Type: application/x-www-form-urlencoded";
143 }
144 } else {
145 if (!range.empty())
146 request_info.headers = std::string("Range: ") + range;
147 }
148
149 scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
150 if (!body.empty())
151 request_body->AppendBytes(&body[0], body.size());
152
153 request_id_ = ChildThreadImpl::current()->resource_dispatcher()->StartAsync(
154 request_info, request_body.get(), this);
155
156 // TODO(jam): range requests
157 }
158
159 PluginURLFetcher::~PluginURLFetcher() {
160 if (request_id_ >= 0) {
161 ChildThreadImpl::current()->resource_dispatcher()->RemovePendingRequest(
162 request_id_);
163 }
164 }
165
166 void PluginURLFetcher::Cancel() {
167 ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
168
169 // Due to races and nested event loops, PluginURLFetcher may still receive
170 // events from the bridge before being destroyed. Do not forward additional
171 // events back to the plugin, via either |plugin_stream_| or
172 // |multipart_delegate_| which has its own pointer via
173 // MultiPartResponseClient.
174 if (multipart_delegate_)
175 multipart_delegate_->Cancel();
176 plugin_stream_ = NULL;
177 }
178
179 void PluginURLFetcher::URLRedirectResponse(bool allow) {
180 if (!plugin_stream_)
181 return;
182
183 if (allow) {
184 ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
185 request_id_, false);
186 } else {
187 ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
188 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
189 }
190 }
191
192 void PluginURLFetcher::OnUploadProgress(uint64 position, uint64 size) {
193 }
194
195 bool PluginURLFetcher::OnReceivedRedirect(
196 const net::RedirectInfo& redirect_info,
197 const ResourceResponseInfo& info) {
198 if (!plugin_stream_)
199 return false;
200
201 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::willSendRequest until
202 // kDirectNPAPIRequests is the default and we can remove the old path there.
203
204 // Currently this check is just to catch an https -> http redirect when
205 // loading the main plugin src URL. Longer term, we could investigate
206 // firing mixed diplay or scripting issues for subresource loads
207 // initiated by plugins.
208 if (is_plugin_src_load_ &&
209 !plugin_stream_->instance()->webplugin()->CheckIfRunInsecureContent(
210 redirect_info.new_url)) {
211 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
212 return false;
213 }
214
215 GURL old_url = url_;
216 url_ = redirect_info.new_url;
217 first_party_for_cookies_ = redirect_info.new_first_party_for_cookies;
218
219 // If the plugin does not participate in url redirect notifications then just
220 // block cross origin 307 POST redirects.
221 if (!notify_redirects_) {
222 if (redirect_info.status_code == 307 &&
223 redirect_info.new_method == "POST" &&
224 old_url.GetOrigin() != url_.GetOrigin()) {
225 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
226 return false;
227 }
228 } else {
229 // Pause the request while we ask the plugin what to do about the redirect.
230 ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
231 request_id_, true);
232 plugin_stream_->WillSendRequest(url_, redirect_info.status_code);
233 }
234
235 return true;
236 }
237
238 void PluginURLFetcher::OnReceivedResponse(const ResourceResponseInfo& info) {
239 if (!plugin_stream_)
240 return;
241
242 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::didReceiveResponse
243 // GetAllHeaders, and GetResponseInfo until kDirectNPAPIRequests is the
244 // default and we can remove the old path there.
245
246 bool request_is_seekable = true;
247 DCHECK(!multipart_delegate_.get());
248 if (plugin_stream_->seekable()) {
249 int response_code = info.headers->response_code();
250 if (response_code == 206) {
251 blink::WebURLResponse response;
252 response.initialize();
253 WebURLLoaderImpl::PopulateURLResponse(url_, info, &response,
254 false /* report_security_info */);
255
256 std::string multipart_boundary;
257 if (MultipartResponseDelegate::ReadMultipartBoundary(
258 response, &multipart_boundary)) {
259 plugin_stream_->instance()->webplugin()->DidStartLoading();
260
261 MultiPartResponseClient* multi_part_response_client =
262 new MultiPartResponseClient(plugin_stream_);
263
264 multipart_delegate_.reset(new MultipartResponseDelegate(
265 multi_part_response_client, NULL, response, multipart_boundary));
266
267 // Multiple ranges requested, data will be delivered by
268 // MultipartResponseDelegate.
269 data_offset_ = 0;
270 return;
271 }
272
273 int64 upper_bound = 0, instance_size = 0;
274 // Single range requested - go through original processing for
275 // non-multipart requests, but update data offset.
276 MultipartResponseDelegate::ReadContentRanges(
277 response, &data_offset_, &upper_bound, &instance_size);
278 } else if (response_code == 200) {
279 // TODO: should we handle this case? We used to but it's not clear that we
280 // still need to. This was bug 5403, fixed in r7139.
281 }
282 }
283
284 // If the length comes in as -1, then it indicates that it was not
285 // read off the HTTP headers. We replicate Safari webkit behavior here,
286 // which is to set it to 0.
287 int expected_length = std::max(static_cast<int>(info.content_length), 0);
288
289 base::Time temp;
290 uint32 last_modified = 0;
291 std::string headers;
292 if (info.headers.get()) { // NULL for data: urls.
293 if (info.headers->GetLastModifiedValue(&temp))
294 last_modified = static_cast<uint32>(temp.ToDoubleT());
295
296 // TODO(darin): Shouldn't we also report HTTP version numbers?
297 int response_code = info.headers->response_code();
298 headers = base::StringPrintf("HTTP %d ", response_code);
299 headers += info.headers->GetStatusText();
300 headers += "\n";
301
302 void* iter = NULL;
303 std::string name, value;
304 while (info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
305 // TODO(darin): Should we really exclude headers with an empty value?
306 if (!name.empty() && !value.empty())
307 headers += name + ": " + value + "\n";
308 }
309
310 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
311 // error codes in the stream header and as a result, was unaware of the fate
312 // of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF destroy
313 // the stream and invoke the NPP_DestroyStream function on the plugin if the
314 // HTTPrequest fails.
315 if ((url_.SchemeIs(url::kHttpScheme) || url_.SchemeIs(url::kHttpsScheme)) &&
316 (response_code < 100 || response_code >= 400)) {
317 pending_failure_notification_ = true;
318 }
319 }
320
321 plugin_stream_->DidReceiveResponse(info.mime_type,
322 headers,
323 expected_length,
324 last_modified,
325 request_is_seekable);
326 }
327
328 void PluginURLFetcher::OnDownloadedData(int len,
329 int encoded_data_length) {
330 }
331
332 void PluginURLFetcher::OnReceivedData(scoped_ptr<ReceivedData> data) {
333 const char* payload = data->payload();
334 int data_length = data->length();
335 int encoded_data_length = data->encoded_length();
336 if (!plugin_stream_)
337 return;
338
339 if (multipart_delegate_) {
340 multipart_delegate_->OnReceivedData(payload, data_length,
341 encoded_data_length);
342 } else {
343 int64 offset = data_offset_;
344 data_offset_ += data_length;
345
346 if (copy_stream_data_) {
347 // QuickTime writes to this memory, and since we got it from
348 // ResourceDispatcher it's not mapped for write access in this process.
349 // http://crbug.com/308466.
350 scoped_ptr<char[]> data_copy(new char[data_length]);
351 memcpy(data_copy.get(), payload, data_length);
352 plugin_stream_->DidReceiveData(data_copy.get(), data_length, offset);
353 } else {
354 plugin_stream_->DidReceiveData(payload, data_length, offset);
355 }
356 // DANGER: this instance may be deleted at this point.
357 }
358 }
359
360 void PluginURLFetcher::OnCompletedRequest(
361 int error_code,
362 bool was_ignored_by_handler,
363 bool stale_copy_in_cache,
364 const std::string& security_info,
365 const base::TimeTicks& completion_time,
366 int64 total_transfer_size) {
367 if (!plugin_stream_)
368 return;
369
370 if (multipart_delegate_) {
371 multipart_delegate_->OnCompletedRequest();
372 multipart_delegate_.reset();
373 }
374
375 if (error_code == net::OK) {
376 plugin_stream_->DidFinishLoading(resource_id_);
377 } else {
378 plugin_stream_->DidFail(resource_id_);
379 }
380 }
381
382 void PluginURLFetcher::OnReceivedCompletedResponse(
383 const content::ResourceResponseInfo& info,
384 scoped_ptr<ReceivedData> data,
385 int error_code,
386 bool was_ignored_by_handler,
387 bool stale_copy_in_cache,
388 const std::string& security_info,
389 const base::TimeTicks& completion_time,
390 int64 total_transfer_size) {
391 // |this| can be deleted on each callback. |weak_this| is placed here to
392 // detect the deletion.
393 base::WeakPtr<PluginURLFetcher> weak_this = weak_factory_.GetWeakPtr();
394 OnReceivedResponse(info);
395
396 if (!weak_this)
397 return;
398 if (data)
399 OnReceivedData(data.Pass());
400
401 if (!weak_this)
402 return;
403 OnCompletedRequest(error_code, was_ignored_by_handler, stale_copy_in_cache,
404 security_info, completion_time, total_transfer_size);
405 }
406 } // namespace content
OLDNEW
« no previous file with comments | « content/child/npapi/plugin_url_fetcher.h ('k') | content/child/npapi/webplugin.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698