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

Side by Side Diff: content/renderer/npapi/webplugin_impl.cc

Issue 1853793003: Remove content/renderer/npapi (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 8 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/renderer/npapi/webplugin_impl.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/debug/crash_logging.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/metrics/user_metrics_action.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "build/build_config.h"
20 #include "cc/blink/web_layer_impl.h"
21 #include "cc/layers/io_surface_layer.h"
22 #include "content/child/appcache/web_application_cache_host_impl.h"
23 #include "content/child/npapi/plugin_host.h"
24 #include "content/child/npapi/plugin_instance.h"
25 #include "content/child/npapi/webplugin_delegate_impl.h"
26 #include "content/child/npapi/webplugin_resource_client.h"
27 #include "content/common/view_messages.h"
28 #include "content/public/common/content_constants.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/renderer/content_renderer_client.h"
31 #include "content/renderer/npapi/webplugin_delegate_proxy.h"
32 #include "content/renderer/render_frame_impl.h"
33 #include "content/renderer/render_process.h"
34 #include "content/renderer/render_thread_impl.h"
35 #include "content/renderer/render_view_impl.h"
36 #include "net/base/escape.h"
37 #include "net/base/net_errors.h"
38 #include "net/http/http_response_headers.h"
39 #include "skia/ext/platform_canvas.h"
40 #include "third_party/WebKit/public/platform/WebCookieJar.h"
41 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
42 #include "third_party/WebKit/public/platform/WebData.h"
43 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
44 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
45 #include "third_party/WebKit/public/platform/WebURL.h"
46 #include "third_party/WebKit/public/platform/WebURLError.h"
47 #include "third_party/WebKit/public/platform/WebURLLoader.h"
48 #include "third_party/WebKit/public/platform/WebURLResponse.h"
49 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
50 #include "third_party/WebKit/public/web/WebDocument.h"
51 #include "third_party/WebKit/public/web/WebFrame.h"
52 #include "third_party/WebKit/public/web/WebInputEvent.h"
53 #include "third_party/WebKit/public/web/WebKit.h"
54 #include "third_party/WebKit/public/web/WebPluginContainer.h"
55 #include "third_party/WebKit/public/web/WebPluginParams.h"
56 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
57 #include "third_party/WebKit/public/web/WebView.h"
58 #include "ui/gfx/geometry/rect.h"
59 #include "url/gurl.h"
60 #include "url/url_util.h"
61
62 using blink::WebCanvas;
63 using blink::WebConsoleMessage;
64 using blink::WebCookieJar;
65 using blink::WebCursorInfo;
66 using blink::WebData;
67 using blink::WebDataSource;
68 using blink::WebFrame;
69 using blink::WebHTTPBody;
70 using blink::WebHTTPHeaderVisitor;
71 using blink::WebInputEvent;
72 using blink::WebInputEventResult;
73 using blink::WebKeyboardEvent;
74 using blink::WebMouseEvent;
75 using blink::WebPluginContainer;
76 using blink::WebPluginParams;
77 using blink::WebRect;
78 using blink::WebString;
79 using blink::WebURL;
80 using blink::WebURLError;
81 using blink::WebURLLoader;
82 using blink::WebURLLoaderOptions;
83 using blink::WebURLRequest;
84 using blink::WebURLResponse;
85 using blink::WebVector;
86 using blink::WebView;
87
88 namespace content {
89
90 // blink::WebPlugin ----------------------------------------------------------
91
92 bool WebPluginImpl::initialize(WebPluginContainer* container) {
93 if (!render_view_.get()) {
94 LOG(ERROR) << "No RenderView";
95 return false;
96 }
97
98 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
99 this, mime_type_, render_view_, render_frame_);
100
101 // Set the container before Initialize because the plugin may
102 // synchronously call NPN_GetValue to get its container, or make calls
103 // passing script objects that need to be tracked, during initialization.
104 SetContainer(container);
105
106 bool ok = plugin_delegate->Initialize(
107 plugin_url_, arg_names_, arg_values_, load_manually_);
108 if (!ok) {
109 plugin_delegate->PluginDestroyed();
110
111 blink::WebPlugin* replacement_plugin =
112 GetContentClient()->renderer()->CreatePluginReplacement(
113 render_frame_, file_path_);
114 if (!replacement_plugin) {
115 // Maintain invariant that container() returns null when initialize()
116 // returns false.
117 SetContainer(nullptr);
118 return false;
119 }
120
121 // The replacement plugin, if it exists, must never fail to initialize.
122 container->setPlugin(replacement_plugin);
123 CHECK(replacement_plugin->initialize(container));
124
125 DCHECK(container->plugin() == replacement_plugin);
126 DCHECK(replacement_plugin->container() == container);
127
128 // Since the container now owns the replacement plugin instead of this
129 // object, we must schedule ourselves for deletion. This also implicitly
130 // disables scripting while un-setting the container.
131 destroy();
132
133 return true;
134 }
135
136 delegate_ = plugin_delegate;
137
138 return true;
139 }
140
141 void WebPluginImpl::destroy() {
142 SetContainer(NULL);
143 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
144 }
145
146 void WebPluginImpl::updateAllLifecyclePhases() {
147 if (!container_)
148 return;
149
150 #if defined(OS_WIN)
151 // Force a geometry update if needed to allow plugins like media player
152 // which defer the initial geometry update to work. Do it now, rather
153 // than in paint, so that the paint rect invalidation is registered.
154 // Otherwise we may never get the paint call.
155 container_->reportGeometry();
156 #endif // OS_WIN
157 }
158
159 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
160 if (!delegate_ || !container_)
161 return;
162
163 // Note that |canvas| is only used when in windowless mode.
164 delegate_->Paint(canvas, paint_rect);
165 }
166
167 void WebPluginImpl::updateGeometry(const WebRect& window_rect,
168 const WebRect& clip_rect,
169 const WebRect& unobscured_rect,
170 const WebVector<WebRect>& cut_outs_rects,
171 bool is_visible) {
172 WebPluginGeometry new_geometry;
173 new_geometry.window_rect = window_rect;
174 new_geometry.clip_rect = clip_rect;
175 new_geometry.visible = is_visible;
176 new_geometry.rects_valid = true;
177 for (size_t i = 0; i < cut_outs_rects.size(); ++i)
178 new_geometry.cutout_rects.push_back(cut_outs_rects[i]);
179
180 // Only UpdateGeometry if either the window or clip rects have changed.
181 if (delegate_ && (first_geometry_update_ ||
182 new_geometry.window_rect != geometry_.window_rect ||
183 new_geometry.clip_rect != geometry_.clip_rect)) {
184 // Notify the plugin that its parameters have changed.
185 delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
186 }
187
188 #if defined(OS_WIN)
189 // Don't cache the geometry during the first geometry update. The first
190 // geometry update sequence is received when Widget::setParent is called.
191 // For plugins like media player which have a bug where they only honor
192 // the first geometry update, we have a quirk which ignores the first
193 // geometry update. To ensure that these plugins work correctly in cases
194 // where we receive only one geometry update from webkit, we also force
195 // a geometry update during paint which should go out correctly as the
196 // initial geometry update was not cached.
197 if (!first_geometry_update_)
198 geometry_ = new_geometry;
199 #else // OS_WIN
200 geometry_ = new_geometry;
201 #endif // OS_WIN
202 first_geometry_update_ = false;
203 }
204
205 void WebPluginImpl::updateFocus(bool focused, blink::WebFocusType focus_type) {
206 delegate_->SetFocus(focused);
207 }
208
209 void WebPluginImpl::updateVisibility(bool visible) {
210 }
211
212 bool WebPluginImpl::acceptsInputEvents() {
213 return true;
214 }
215
216 WebInputEventResult WebPluginImpl::handleInputEvent(
217 const WebInputEvent& event,
218 WebCursorInfo& cursor_info) {
219 // Swallow context menu events in order to suppress the default context menu.
220 if (event.type == WebInputEvent::ContextMenu)
221 return WebInputEventResult::HandledSuppressed;
222
223 WebCursor::CursorInfo web_cursor_info;
224 bool ret = delegate_->HandleInputEvent(event, &web_cursor_info);
225 cursor_info.type = web_cursor_info.type;
226 cursor_info.hotSpot = web_cursor_info.hotspot;
227 cursor_info.customImage = web_cursor_info.custom_image;
228 cursor_info.imageScaleFactor = web_cursor_info.image_scale_factor;
229 #if defined(OS_WIN)
230 cursor_info.externalHandle = web_cursor_info.external_handle;
231 #endif
232 return ret ? WebInputEventResult::HandledApplication
233 : WebInputEventResult::NotHandled;
234 }
235
236 bool WebPluginImpl::isPlaceholder() {
237 return false;
238 }
239
240 // -----------------------------------------------------------------------------
241
242 WebPluginImpl::WebPluginImpl(
243 WebFrame* webframe,
244 const WebPluginParams& params,
245 const base::FilePath& file_path,
246 const base::WeakPtr<RenderViewImpl>& render_view,
247 RenderFrameImpl* render_frame)
248 : render_frame_(render_frame),
249 render_view_(render_view),
250 webframe_(webframe),
251 delegate_(NULL),
252 container_(NULL),
253 plugin_url_(params.url),
254 load_manually_(params.loadManually),
255 first_geometry_update_(true),
256 ignore_response_error_(false),
257 file_path_(file_path),
258 mime_type_(base::ToLowerASCII(base::UTF16ToASCII(
259 base::StringPiece16(params.mimeType)))) {
260 DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
261
262 for (size_t i = 0; i < params.attributeNames.size(); ++i) {
263 arg_names_.push_back(params.attributeNames[i].utf8());
264 arg_values_.push_back(params.attributeValues[i].utf8());
265 }
266
267 // Set subresource URL for crash reporting.
268 base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec());
269 }
270
271 WebPluginImpl::~WebPluginImpl() {
272 }
273
274 GURL WebPluginImpl::CompleteURL(const char* url) {
275 if (!webframe_) {
276 NOTREACHED();
277 return GURL();
278 }
279 // TODO(darin): Is conversion from UTF8 correct here?
280 return webframe_->document().completeURL(WebString::fromUTF8(url));
281 }
282
283 bool WebPluginImpl::SetPostData(WebURLRequest* request,
284 const char* buf,
285 uint32_t length) {
286 std::vector<std::string> names;
287 std::vector<std::string> values;
288 std::vector<char> body;
289 bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body);
290
291 for (size_t i = 0; i < names.size(); ++i) {
292 request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
293 WebString::fromUTF8(values[i]));
294 }
295
296 WebString content_type_header = WebString::fromUTF8("Content-Type");
297 const WebString& content_type =
298 request->httpHeaderField(content_type_header);
299 if (content_type.isEmpty()) {
300 request->setHTTPHeaderField(
301 content_type_header,
302 WebString::fromUTF8("application/x-www-form-urlencoded"));
303 }
304
305 WebHTTPBody http_body;
306 if (body.size()) {
307 http_body.initialize();
308 http_body.appendData(WebData(&body[0], body.size()));
309 }
310 request->setHTTPBody(http_body);
311
312 return rv;
313 }
314
315 bool WebPluginImpl::IsValidUrl(const GURL& url, ReferrerValue referrer_flag) {
316 if (referrer_flag == PLUGIN_SRC &&
317 mime_type_ == kFlashPluginSwfMimeType &&
318 url.GetOrigin() != plugin_url_.GetOrigin()) {
319 // Do url check to make sure that there are no @, ;, \ chars in between url
320 // scheme and url path.
321 const char* url_to_check(url.spec().data());
322 url::Parsed parsed;
323 url::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
324 if (parsed.path.begin <= parsed.scheme.end())
325 return true;
326 std::string string_to_search;
327 string_to_search.assign(url_to_check + parsed.scheme.end(),
328 parsed.path.begin - parsed.scheme.end());
329 if (string_to_search.find("@") != std::string::npos ||
330 string_to_search.find(";") != std::string::npos ||
331 string_to_search.find("\\") != std::string::npos)
332 return false;
333 }
334
335 return true;
336 }
337
338 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
339 const char* url,
340 bool is_javascript_url,
341 bool popups_allowed,
342 const char* method,
343 const char* target,
344 const char* buf,
345 unsigned int len,
346 ReferrerValue referrer_flag) {
347 // If there is no target, there is nothing to do
348 if (!target)
349 return NOT_ROUTED;
350
351 // This could happen if the WebPluginContainer was already deleted.
352 if (!webframe_)
353 return NOT_ROUTED;
354
355 WebString target_str = WebString::fromUTF8(target);
356
357 // Take special action for JavaScript URLs
358 if (is_javascript_url) {
359 WebFrame* target_frame =
360 webframe_->view()->findFrameByName(target_str, webframe_);
361 // For security reasons, do not allow JavaScript on frames
362 // other than this frame.
363 if (target_frame != webframe_) {
364 // TODO(darin): Localize this message.
365 const char kMessage[] =
366 "Ignoring cross-frame javascript URL load requested by plugin.";
367 webframe_->addMessageToConsole(
368 WebConsoleMessage(WebConsoleMessage::LevelError,
369 WebString::fromUTF8(kMessage)));
370 return ROUTED;
371 }
372
373 // Route javascript calls back to the plugin.
374 return NOT_ROUTED;
375 }
376
377 // If we got this far, we're routing content to a target frame.
378 // Go fetch the URL.
379
380 GURL complete_url = CompleteURL(url);
381 // Remove when flash bug is fixed. http://crbug.com/40016.
382 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
383 return INVALID_URL;
384
385 if (strcmp(method, "GET") != 0) {
386 // We're only going to route HTTP/HTTPS requests
387 if (!complete_url.SchemeIsHTTPOrHTTPS())
388 return INVALID_URL;
389 }
390
391 WebURLRequest request(complete_url);
392 SetReferrer(&request, referrer_flag);
393
394 request.setHTTPMethod(WebString::fromUTF8(method));
395 request.setFirstPartyForCookies(
396 webframe_->document().firstPartyForCookies());
397 request.setHasUserGesture(popups_allowed);
398 // ServiceWorker is disabled for NPAPI.
399 request.setSkipServiceWorker(true);
400 if (len > 0) {
401 if (!SetPostData(&request, buf, len)) {
402 // Uhoh - we're in trouble. There isn't a good way
403 // to recover at this point. Break out.
404 NOTREACHED();
405 return ROUTED;
406 }
407 }
408
409 container_->loadFrameRequest(request, target_str);
410 return ROUTED;
411 }
412
413 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) {
414 // Proxy resolving doesn't work in single-process mode.
415 return false;
416 }
417
418 void WebPluginImpl::SetCookie(const GURL& url,
419 const GURL& first_party_for_cookies,
420 const std::string& cookie) {
421 if (!render_view_.get())
422 return;
423
424 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
425 if (!cookie_jar) {
426 DLOG(WARNING) << "No cookie jar!";
427 return;
428 }
429
430 cookie_jar->setCookie(
431 url, first_party_for_cookies, WebString::fromUTF8(cookie));
432 }
433
434 std::string WebPluginImpl::GetCookies(const GURL& url,
435 const GURL& first_party_for_cookies) {
436 if (!render_view_.get())
437 return std::string();
438
439 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
440 if (!cookie_jar) {
441 DLOG(WARNING) << "No cookie jar!";
442 return std::string();
443 }
444
445 return base::UTF16ToUTF8(base::StringPiece16(
446 cookie_jar->cookies(url, first_party_for_cookies)));
447 }
448
449 #if defined(OS_MACOSX)
450 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
451 gfx::GpuPreference gpu_preference) {
452 return NULL;
453 }
454
455 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
456 }
457
458 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32_t width,
459 int32_t height,
460 uint32_t surface_id) {
461 next_io_surface_allocated_ = true;
462 next_io_surface_width_ = width;
463 next_io_surface_height_ = height;
464 next_io_surface_id_ = surface_id;
465 }
466
467 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
468 if (!container_)
469 return;
470 // Deferring the call to setBackingIOSurfaceId is an attempt to
471 // work around garbage occasionally showing up in the plugin's
472 // area during live resizing of Core Animation plugins. The
473 // assumption was that by the time this was called, the plugin
474 // process would have populated the newly allocated IOSurface. It
475 // is not 100% clear at this point why any garbage is getting
476 // through. More investigation is needed. http://crbug.com/105346
477 if (next_io_surface_allocated_) {
478 if (next_io_surface_id_) {
479 if (!io_surface_layer_.get()) {
480 io_surface_layer_ = cc::IOSurfaceLayer::Create();
481 web_layer_.reset(new cc_blink::WebLayerImpl(io_surface_layer_));
482 container_->setWebLayer(web_layer_.get());
483 }
484 io_surface_layer_->SetIOSurfaceProperties(
485 next_io_surface_id_,
486 gfx::Size(next_io_surface_width_, next_io_surface_height_));
487 } else {
488 container_->setWebLayer(NULL);
489 web_layer_.reset();
490 io_surface_layer_ = NULL;
491 }
492 next_io_surface_allocated_ = false;
493 } else {
494 if (io_surface_layer_.get())
495 io_surface_layer_->SetNeedsDisplay();
496 }
497 }
498 #endif
499
500 void WebPluginImpl::Invalidate() {
501 if (container_)
502 container_->invalidate();
503 }
504
505 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
506 if (container_)
507 container_->invalidateRect(rect);
508 }
509
510 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
511 if (!container)
512 TearDownPluginInstance(NULL);
513 container_ = container;
514 }
515
516 unsigned long WebPluginImpl::GetNextResourceId() {
517 if (!webframe_)
518 return 0;
519 WebView* view = webframe_->view();
520 if (!view)
521 return 0;
522 return view->createUniqueIdentifierForRequest();
523 }
524
525 void WebPluginImpl::CancelDocumentLoad() {
526 if (webframe_) {
527 ignore_response_error_ = true;
528 webframe_->stopLoading();
529 }
530 }
531
532 void WebPluginImpl::DidStartLoading() {
533 if (render_view_.get()) {
534 // TODO(darin): Make is_loading_ be a counter!
535 render_view_->DidStartLoading();
536 }
537 }
538
539 void WebPluginImpl::DidStopLoading() {
540 if (render_view_.get()) {
541 // TODO(darin): Make is_loading_ be a counter!
542 render_view_->DidStopLoading();
543 }
544 }
545
546 bool WebPluginImpl::IsOffTheRecord() {
547 return false;
548 }
549
550 bool WebPluginImpl::ReinitializePluginForResponse(
551 WebURLLoader* loader) {
552 WebFrame* webframe = webframe_;
553 if (!webframe)
554 return false;
555
556 WebView* webview = webframe->view();
557 if (!webview)
558 return false;
559
560 WebPluginContainer* container_widget = container_;
561
562 // Destroy the current plugin instance.
563 TearDownPluginInstance(loader);
564
565 container_ = container_widget;
566 webframe_ = webframe;
567
568 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
569 this, mime_type_, render_view_, render_frame_);
570
571 bool ok = plugin_delegate && plugin_delegate->Initialize(
572 plugin_url_, arg_names_, arg_values_, load_manually_);
573
574 if (!ok) {
575 container_ = NULL;
576 // TODO(iyengar) Should we delete the current plugin instance here?
577 return false;
578 }
579
580 delegate_ = plugin_delegate;
581
582 // Force a geometry update to occur to ensure that the plugin becomes
583 // visible.
584 container_->reportGeometry();
585
586 // The plugin move sequences accumulated via DidMove are sent to the browser
587 // whenever the renderer paints. Force a paint here to ensure that changes
588 // to the plugin window are propagated to the browser.
589 container_->invalidate();
590 return true;
591 }
592
593 void WebPluginImpl::TearDownPluginInstance(
594 WebURLLoader* loader_to_ignore) {
595 // JavaScript garbage collection may cause plugin script object references to
596 // be retained long after the plugin is destroyed. Some plugins won't cope
597 // with their objects being released after they've been destroyed, and once
598 // we've actually unloaded the plugin the object's releaseobject() code may
599 // no longer be in memory. The container tracks the plugin's objects and lets
600 // us invalidate them, releasing the references to them held by the JavaScript
601 // runtime.
602 if (container_) {
603 container_->setWebLayer(NULL);
604 }
605
606 // Call PluginDestroyed() first to prevent the plugin from calling us back
607 // in the middle of tearing down the render tree.
608 if (delegate_) {
609 // The plugin may call into the browser and pass script objects even during
610 // teardown, so temporarily re-enable plugin script objects.
611 DCHECK(container_);
612
613 delegate_->PluginDestroyed();
614 delegate_ = NULL;
615 }
616
617 // This needs to be called now and not in the destructor since the
618 // webframe_ might not be valid anymore.
619 webframe_ = NULL;
620 }
621
622 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
623 ReferrerValue referrer_flag) {
624 switch (referrer_flag) {
625 case DOCUMENT_URL:
626 webframe_->setReferrerForRequest(*request, GURL());
627 break;
628
629 case PLUGIN_SRC:
630 webframe_->setReferrerForRequest(*request, plugin_url_);
631 break;
632
633 default:
634 break;
635 }
636 }
637
638 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/npapi/webplugin_impl.h ('k') | content/renderer/npapi/webplugin_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698