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.
5 #include "content/renderer/npapi/webplugin_impl.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 "cc/blink/web_layer_impl.h"
20 #include "cc/layers/io_surface_layer.h"
21 #include "content/child/appcache/web_application_cache_host_impl.h"
22 #include "content/child/multipart_response_delegate.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/WebCString.h"
41 #include "third_party/WebKit/public/platform/WebCookieJar.h"
42 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
43 #include "third_party/WebKit/public/platform/WebData.h"
44 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
45 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
46 #include "third_party/WebKit/public/platform/WebURL.h"
47 #include "third_party/WebKit/public/platform/WebURLError.h"
48 #include "third_party/WebKit/public/platform/WebURLLoader.h"
49 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
50 #include "third_party/WebKit/public/platform/WebURLResponse.h"
51 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
52 #include "third_party/WebKit/public/web/WebDocument.h"
53 #include "third_party/WebKit/public/web/WebFrame.h"
54 #include "third_party/WebKit/public/web/WebInputEvent.h"
55 #include "third_party/WebKit/public/web/WebKit.h"
56 #include "third_party/WebKit/public/web/WebPluginContainer.h"
57 #include "third_party/WebKit/public/web/WebPluginParams.h"
58 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
59 #include "third_party/WebKit/public/web/WebView.h"
60 #include "ui/gfx/geometry/rect.h"
62 #include "url/url_util.h"
64 using blink::WebCString
;
65 using blink::WebCanvas
;
66 using blink::WebConsoleMessage
;
67 using blink::WebCookieJar
;
68 using blink::WebCursorInfo
;
70 using blink::WebDataSource
;
71 using blink::WebFrame
;
72 using blink::WebHTTPBody
;
73 using blink::WebHTTPHeaderVisitor
;
74 using blink::WebInputEvent
;
75 using blink::WebKeyboardEvent
;
76 using blink::WebMouseEvent
;
77 using blink::WebPluginContainer
;
78 using blink::WebPluginParams
;
80 using blink::WebString
;
82 using blink::WebURLError
;
83 using blink::WebURLLoader
;
84 using blink::WebURLLoaderClient
;
85 using blink::WebURLLoaderOptions
;
86 using blink::WebURLRequest
;
87 using blink::WebURLResponse
;
88 using blink::WebVector
;
95 // This class handles individual multipart responses. It is instantiated when
96 // we receive HTTP status code 206 in the HTTP response. This indicates
97 // that the response could have multiple parts each separated by a boundary
98 // specified in the response header.
99 class MultiPartResponseClient
: public WebURLLoaderClient
{
101 explicit MultiPartResponseClient(WebPluginResourceClient
* resource_client
)
102 : byte_range_lower_bound_(0), resource_client_(resource_client
) {}
104 virtual void willSendRequest(
105 WebURLLoader
*, WebURLRequest
&, const WebURLResponse
&) {}
106 virtual void didSendData(
107 WebURLLoader
*, unsigned long long, unsigned long long) {}
109 // Called when the multipart parser encounters an embedded multipart
111 virtual void didReceiveResponse(
112 WebURLLoader
*, const WebURLResponse
& response
) {
113 int64 byte_range_upper_bound
, instance_size
;
114 if (!MultipartResponseDelegate::ReadContentRanges(
116 &byte_range_lower_bound_
,
117 &byte_range_upper_bound
,
123 // Receives individual part data from a multipart response.
124 virtual void didReceiveData(WebURLLoader
*,
127 int encoded_data_length
) {
129 // We should defer further loads on multipart resources on the same lines
130 // as regular resources requested by plugins to prevent reentrancy.
131 resource_client_
->DidReceiveData(
132 data
, data_length
, byte_range_lower_bound_
);
133 byte_range_lower_bound_
+= data_length
;
136 virtual void didFinishLoading(WebURLLoader
*,
138 int64_t total_encoded_data_length
) {}
139 virtual void didFail(WebURLLoader
*, const WebURLError
&) {}
142 // The lower bound of the byte range.
143 int64 byte_range_lower_bound_
;
144 // The handler for the data.
145 WebPluginResourceClient
* resource_client_
;
148 class HeaderFlattener
: public WebHTTPHeaderVisitor
{
150 explicit HeaderFlattener(std::string
* buf
) : buf_(buf
) {
153 virtual void visitHeader(const WebString
& name
, const WebString
& value
) {
154 // TODO(darin): Should we really exclude headers with an empty value?
155 if (!name
.isEmpty() && !value
.isEmpty()) {
156 buf_
->append(name
.utf8());
158 buf_
->append(value
.utf8());
167 std::string
GetAllHeaders(const WebURLResponse
& response
) {
168 // TODO(darin): It is possible for httpStatusText to be empty and still have
169 // an interesting response, so this check seems wrong.
171 const WebString
& status
= response
.httpStatusText();
172 if (status
.isEmpty())
175 // TODO(darin): Shouldn't we also report HTTP version numbers?
176 result
= base::StringPrintf("HTTP %d ", response
.httpStatusCode());
177 result
.append(status
.utf8());
180 HeaderFlattener
flattener(&result
);
181 response
.visitHTTPHeaderFields(&flattener
);
186 struct ResponseInfo
{
188 std::string mime_type
;
189 uint32 last_modified
;
190 uint32 expected_length
;
193 void GetResponseInfo(const WebURLResponse
& response
,
194 ResponseInfo
* response_info
) {
195 response_info
->url
= response
.url();
196 response_info
->mime_type
= response
.mimeType().utf8();
198 // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
199 response_info
->last_modified
=
200 static_cast<uint32
>(response
.lastModifiedDate());
202 // If the length comes in as -1, then it indicates that it was not
203 // read off the HTTP headers. We replicate Safari webkit behavior here,
204 // which is to set it to 0.
205 response_info
->expected_length
=
206 static_cast<uint32
>(std::max(response
.expectedContentLength(), 0LL));
208 WebString content_encoding
=
209 response
.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
210 if (!content_encoding
.isNull() &&
211 !base::EqualsASCII(base::StringPiece16(content_encoding
), "identity")) {
212 // Don't send the compressed content length to the plugin, which only
213 // cares about the decoded length.
214 response_info
->expected_length
= 0;
220 // blink::WebPlugin ----------------------------------------------------------
222 struct WebPluginImpl::ClientInfo
{
224 WebPluginResourceClient
* client
;
225 blink::WebURLRequest request
;
226 bool pending_failure_notification
;
227 linked_ptr
<blink::WebURLLoader
> loader
;
228 bool notify_redirects
;
229 bool is_plugin_src_load
;
233 bool WebPluginImpl::initialize(WebPluginContainer
* container
) {
234 if (!render_view_
.get()) {
235 LOG(ERROR
) << "No RenderView";
239 WebPluginDelegateProxy
* plugin_delegate
= new WebPluginDelegateProxy(
240 this, mime_type_
, render_view_
, render_frame_
);
242 // Store the plugin's unique identifier, used by the container to track its
244 npp_
= plugin_delegate
->GetPluginNPP();
246 // Set the container before Initialize because the plugin may
247 // synchronously call NPN_GetValue to get its container, or make calls
248 // passing script objects that need to be tracked, during initialization.
249 SetContainer(container
);
251 bool ok
= plugin_delegate
->Initialize(
252 plugin_url_
, arg_names_
, arg_values_
, load_manually_
);
254 plugin_delegate
->PluginDestroyed();
256 blink::WebPlugin
* replacement_plugin
=
257 GetContentClient()->renderer()->CreatePluginReplacement(
258 render_frame_
, file_path_
);
259 if (!replacement_plugin
)
262 // Disable scripting by this plugin before replacing it with the new
263 // one. This plugin also needs destroying, so use destroy(), which will
264 // implicitly disable scripting while un-setting the container.
267 // Inform the container of the replacement plugin, then initialize it.
268 container
->setPlugin(replacement_plugin
);
269 return replacement_plugin
->initialize(container
);
272 delegate_
= plugin_delegate
;
277 void WebPluginImpl::destroy() {
279 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
282 NPObject
* WebPluginImpl::scriptableObject() {
286 return delegate_
->GetPluginScriptableObject();
289 NPP
WebPluginImpl::pluginNPP() {
293 bool WebPluginImpl::getFormValue(blink::WebString
& value
) {
296 base::string16 form_value
;
297 if (!delegate_
->GetFormValue(&form_value
))
303 void WebPluginImpl::layoutIfNeeded() {
308 // Force a geometry update if needed to allow plugins like media player
309 // which defer the initial geometry update to work. Do it now, rather
310 // than in paint, so that the paint rect invalidation is registered.
311 // Otherwise we may never get the paint call.
312 container_
->reportGeometry();
316 void WebPluginImpl::paint(WebCanvas
* canvas
, const WebRect
& paint_rect
) {
317 if (!delegate_
|| !container_
)
320 // Note that |canvas| is only used when in windowless mode.
321 delegate_
->Paint(canvas
, paint_rect
);
324 void WebPluginImpl::updateGeometry(const WebRect
& window_rect
,
325 const WebRect
& clip_rect
,
326 const WebRect
& unobscured_rect
,
327 const WebVector
<WebRect
>& cut_outs_rects
,
329 WebPluginGeometry new_geometry
;
330 new_geometry
.window
= window_
;
331 new_geometry
.window_rect
= window_rect
;
332 new_geometry
.clip_rect
= clip_rect
;
333 new_geometry
.visible
= is_visible
;
334 new_geometry
.rects_valid
= true;
335 for (size_t i
= 0; i
< cut_outs_rects
.size(); ++i
)
336 new_geometry
.cutout_rects
.push_back(cut_outs_rects
[i
]);
338 // Only send DidMovePlugin if the geometry changed in some way.
339 if (window_
&& (first_geometry_update_
|| !new_geometry
.Equals(geometry_
))) {
340 render_frame_
->GetRenderWidget()->SchedulePluginMove(new_geometry
);
341 // We invalidate windowed plugins during the first geometry update to
342 // ensure that they get reparented to the wrapper window in the browser.
343 // This ensures that they become visible and are painted by the OS. This is
344 // required as some pages don't invalidate when the plugin is added.
345 if (first_geometry_update_
&& window_
) {
346 InvalidateRect(window_rect
);
350 // Only UpdateGeometry if either the window or clip rects have changed.
351 if (delegate_
&& (first_geometry_update_
||
352 new_geometry
.window_rect
!= geometry_
.window_rect
||
353 new_geometry
.clip_rect
!= geometry_
.clip_rect
)) {
354 // Notify the plugin that its parameters have changed.
355 delegate_
->UpdateGeometry(new_geometry
.window_rect
, new_geometry
.clip_rect
);
358 // Initiate a download on the plugin url. This should be done for the
359 // first update geometry sequence. We need to ensure that the plugin
360 // receives the geometry update before it starts receiving data.
361 if (first_geometry_update_
) {
362 // An empty url corresponds to an EMBED tag with no src attribute.
363 if (!load_manually_
&& plugin_url_
.is_valid()) {
364 // The Flash plugin hangs for a while if it receives data before
365 // receiving valid plugin geometry. By valid geometry we mean the
366 // geometry received by a call to setFrameRect in the Webkit
367 // layout code path. To workaround this issue we download the
368 // plugin source url on a timer.
369 base::ThreadTaskRunnerHandle::Get()->PostTask(
370 FROM_HERE
, base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl
,
371 weak_factory_
.GetWeakPtr()));
376 // Don't cache the geometry during the first geometry update. The first
377 // geometry update sequence is received when Widget::setParent is called.
378 // For plugins like media player which have a bug where they only honor
379 // the first geometry update, we have a quirk which ignores the first
380 // geometry update. To ensure that these plugins work correctly in cases
381 // where we receive only one geometry update from webkit, we also force
382 // a geometry update during paint which should go out correctly as the
383 // initial geometry update was not cached.
384 if (!first_geometry_update_
)
385 geometry_
= new_geometry
;
387 geometry_
= new_geometry
;
389 first_geometry_update_
= false;
392 void WebPluginImpl::updateFocus(bool focused
, blink::WebFocusType focus_type
) {
393 if (accepts_input_events_
)
394 delegate_
->SetFocus(focused
);
397 void WebPluginImpl::updateVisibility(bool visible
) {
401 WebPluginGeometry move
;
402 move
.window
= window_
;
403 move
.window_rect
= gfx::Rect();
404 move
.clip_rect
= gfx::Rect();
405 move
.rects_valid
= false;
406 move
.visible
= visible
;
408 render_frame_
->GetRenderWidget()->SchedulePluginMove(move
);
411 bool WebPluginImpl::acceptsInputEvents() {
412 return accepts_input_events_
;
415 bool WebPluginImpl::handleInputEvent(
416 const WebInputEvent
& event
, WebCursorInfo
& cursor_info
) {
417 // Swallow context menu events in order to suppress the default context menu.
418 if (event
.type
== WebInputEvent::ContextMenu
)
421 WebCursor::CursorInfo web_cursor_info
;
422 bool ret
= delegate_
->HandleInputEvent(event
, &web_cursor_info
);
423 cursor_info
.type
= web_cursor_info
.type
;
424 cursor_info
.hotSpot
= web_cursor_info
.hotspot
;
425 cursor_info
.customImage
= web_cursor_info
.custom_image
;
426 cursor_info
.imageScaleFactor
= web_cursor_info
.image_scale_factor
;
428 cursor_info
.externalHandle
= web_cursor_info
.external_handle
;
433 void WebPluginImpl::didReceiveResponse(const WebURLResponse
& response
) {
434 ignore_response_error_
= false;
436 ResponseInfo response_info
;
437 GetResponseInfo(response
, &response_info
);
439 delegate_
->DidReceiveManualResponse(
441 response_info
.mime_type
,
442 GetAllHeaders(response
),
443 response_info
.expected_length
,
444 response_info
.last_modified
);
447 void WebPluginImpl::didReceiveData(const char* data
, int data_length
) {
448 delegate_
->DidReceiveManualData(data
, data_length
);
451 void WebPluginImpl::didFinishLoading() {
452 delegate_
->DidFinishManualLoading();
455 void WebPluginImpl::didFailLoading(const WebURLError
& error
) {
456 if (!ignore_response_error_
)
457 delegate_
->DidManualLoadFail();
460 void WebPluginImpl::didFinishLoadingFrameRequest(
461 const WebURL
& url
, void* notify_data
) {
463 // We're converting a void* into an arbitrary int id. Though
464 // these types are the same size on all the platforms we support,
465 // the compiler may complain as though they are different, so to
466 // make the casting gods happy go through an intptr_t (the union
467 // of void* and int) rather than converting straight across.
468 delegate_
->DidFinishLoadWithReason(
469 url
, NPRES_DONE
, reinterpret_cast<intptr_t>(notify_data
));
473 void WebPluginImpl::didFailLoadingFrameRequest(
474 const WebURL
& url
, void* notify_data
, const WebURLError
& error
) {
479 error
.reason
== net::ERR_ABORTED
? NPRES_USER_BREAK
: NPRES_NETWORK_ERR
;
480 // See comment in didFinishLoadingFrameRequest about the cast here.
481 delegate_
->DidFinishLoadWithReason(
482 url
, reason
, reinterpret_cast<intptr_t>(notify_data
));
485 bool WebPluginImpl::isPlaceholder() {
489 WebPluginImpl::LoaderClient::LoaderClient(WebPluginImpl
* parent
)
492 void WebPluginImpl::LoaderClient::willSendRequest(
493 blink::WebURLLoader
* loader
, blink::WebURLRequest
& newRequest
,
494 const blink::WebURLResponse
& redirectResponse
) {
495 parent_
->willSendRequest(loader
, newRequest
, redirectResponse
);
498 void WebPluginImpl::LoaderClient::didSendData(
499 blink::WebURLLoader
* loader
, unsigned long long bytesSent
,
500 unsigned long long totalBytesToBeSent
) {
501 parent_
->didSendData(loader
, bytesSent
, totalBytesToBeSent
);
504 void WebPluginImpl::LoaderClient::didReceiveResponse(
505 blink::WebURLLoader
* loader
, const blink::WebURLResponse
& response
) {
506 parent_
->didReceiveResponse(loader
, response
);
509 void WebPluginImpl::LoaderClient::didDownloadData(
510 blink::WebURLLoader
* loader
, int dataLength
, int encodedDataLength
) {
513 void WebPluginImpl::LoaderClient::didReceiveData(
514 blink::WebURLLoader
* loader
, const char* data
,
515 int dataLength
, int encodedDataLength
) {
516 parent_
->didReceiveData(loader
, data
, dataLength
, encodedDataLength
);
519 void WebPluginImpl::LoaderClient::didReceiveCachedMetadata(
520 blink::WebURLLoader
* loader
, const char* data
, int dataLength
) {
523 void WebPluginImpl::LoaderClient::didFinishLoading(
524 blink::WebURLLoader
* loader
, double finishTime
,
525 int64_t total_encoded_data_length
) {
526 parent_
->didFinishLoading(loader
, finishTime
);
529 void WebPluginImpl::LoaderClient::didFail(
530 blink::WebURLLoader
* loader
, const blink::WebURLError
& error
) {
531 parent_
->didFail(loader
, error
);
534 // -----------------------------------------------------------------------------
536 WebPluginImpl::WebPluginImpl(
538 const WebPluginParams
& params
,
539 const base::FilePath
& file_path
,
540 const base::WeakPtr
<RenderViewImpl
>& render_view
,
541 RenderFrameImpl
* render_frame
)
542 : windowless_(false),
543 window_(gfx::kNullPluginWindow
),
544 accepts_input_events_(false),
545 render_frame_(render_frame
),
546 render_view_(render_view
),
551 plugin_url_(params
.url
),
552 load_manually_(params
.loadManually
),
553 first_geometry_update_(true),
554 ignore_response_error_(false),
555 file_path_(file_path
),
556 mime_type_(base::ToLowerASCII(base::UTF16ToASCII(
557 base::StringPiece16(params
.mimeType
)))),
558 loader_client_(this),
559 weak_factory_(this) {
560 DCHECK_EQ(params
.attributeNames
.size(), params
.attributeValues
.size());
562 for (size_t i
= 0; i
< params
.attributeNames
.size(); ++i
) {
563 arg_names_
.push_back(params
.attributeNames
[i
].utf8());
564 arg_values_
.push_back(params
.attributeValues
[i
].utf8());
567 // Set subresource URL for crash reporting.
568 base::debug::SetCrashKeyValue("subresource_url", plugin_url_
.spec());
571 WebPluginImpl::~WebPluginImpl() {
574 void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window
) {
576 DCHECK(!windowless_
);
578 #if defined(OS_MACOSX)
579 // TODO(kbr): remove. http://crbug.com/105344
581 // Lie to ourselves about being windowless even if we got a fake
582 // plugin window handle, so we continue to get input events.
584 accepts_input_events_
= true;
585 // We do not really need to notify the page delegate that a plugin
586 // window was created -- so don't.
588 accepts_input_events_
= false;
592 DCHECK(!window_
); // Make sure not called twice.
594 accepts_input_events_
= true;
598 void WebPluginImpl::SetAcceptsInputEvents(bool accepts
) {
599 accepts_input_events_
= accepts
;
602 void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window
) {
603 DCHECK_EQ(window
, window_
);
604 window_
= gfx::kNullPluginWindow
;
605 if (render_view_
.get())
606 render_frame_
->GetRenderWidget()->CleanupWindowInPluginMoves(window
);
609 GURL
WebPluginImpl::CompleteURL(const char* url
) {
614 // TODO(darin): Is conversion from UTF8 correct here?
615 return webframe_
->document().completeURL(WebString::fromUTF8(url
));
618 void WebPluginImpl::CancelResource(unsigned long id
) {
619 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
620 if (clients_
[i
].id
== id
) {
621 if (clients_
[i
].loader
.get()) {
622 clients_
[i
].loader
->setDefersLoading(false);
623 clients_
[i
].loader
->cancel();
631 bool WebPluginImpl::SetPostData(WebURLRequest
* request
,
634 std::vector
<std::string
> names
;
635 std::vector
<std::string
> values
;
636 std::vector
<char> body
;
637 bool rv
= PluginHost::SetPostData(buf
, length
, &names
, &values
, &body
);
639 for (size_t i
= 0; i
< names
.size(); ++i
) {
640 request
->addHTTPHeaderField(WebString::fromUTF8(names
[i
]),
641 WebString::fromUTF8(values
[i
]));
644 WebString content_type_header
= WebString::fromUTF8("Content-Type");
645 const WebString
& content_type
=
646 request
->httpHeaderField(content_type_header
);
647 if (content_type
.isEmpty()) {
648 request
->setHTTPHeaderField(
650 WebString::fromUTF8("application/x-www-form-urlencoded"));
653 WebHTTPBody http_body
;
655 http_body
.initialize();
656 http_body
.appendData(WebData(&body
[0], body
.size()));
658 request
->setHTTPBody(http_body
);
663 bool WebPluginImpl::IsValidUrl(const GURL
& url
, ReferrerValue referrer_flag
) {
664 if (referrer_flag
== PLUGIN_SRC
&&
665 mime_type_
== kFlashPluginSwfMimeType
&&
666 url
.GetOrigin() != plugin_url_
.GetOrigin()) {
667 // Do url check to make sure that there are no @, ;, \ chars in between url
668 // scheme and url path.
669 const char* url_to_check(url
.spec().data());
671 url::ParseStandardURL(url_to_check
, strlen(url_to_check
), &parsed
);
672 if (parsed
.path
.begin
<= parsed
.scheme
.end())
674 std::string string_to_search
;
675 string_to_search
.assign(url_to_check
+ parsed
.scheme
.end(),
676 parsed
.path
.begin
- parsed
.scheme
.end());
677 if (string_to_search
.find("@") != std::string::npos
||
678 string_to_search
.find(";") != std::string::npos
||
679 string_to_search
.find("\\") != std::string::npos
)
686 WebPluginImpl::RoutingStatus
WebPluginImpl::RouteToFrame(
688 bool is_javascript_url
,
695 ReferrerValue referrer_flag
) {
696 // If there is no target, there is nothing to do
700 // This could happen if the WebPluginContainer was already deleted.
704 WebString target_str
= WebString::fromUTF8(target
);
706 // Take special action for JavaScript URLs
707 if (is_javascript_url
) {
708 WebFrame
* target_frame
=
709 webframe_
->view()->findFrameByName(target_str
, webframe_
);
710 // For security reasons, do not allow JavaScript on frames
711 // other than this frame.
712 if (target_frame
!= webframe_
) {
713 // TODO(darin): Localize this message.
714 const char kMessage
[] =
715 "Ignoring cross-frame javascript URL load requested by plugin.";
716 webframe_
->addMessageToConsole(
717 WebConsoleMessage(WebConsoleMessage::LevelError
,
718 WebString::fromUTF8(kMessage
)));
722 // Route javascript calls back to the plugin.
726 // If we got this far, we're routing content to a target frame.
729 GURL complete_url
= CompleteURL(url
);
730 // Remove when flash bug is fixed. http://crbug.com/40016.
731 if (!WebPluginImpl::IsValidUrl(complete_url
, referrer_flag
))
734 if (strcmp(method
, "GET") != 0) {
735 // We're only going to route HTTP/HTTPS requests
736 if (!complete_url
.SchemeIsHTTPOrHTTPS())
740 WebURLRequest
request(complete_url
);
741 SetReferrer(&request
, referrer_flag
);
743 request
.setHTTPMethod(WebString::fromUTF8(method
));
744 request
.setFirstPartyForCookies(
745 webframe_
->document().firstPartyForCookies());
746 request
.setHasUserGesture(popups_allowed
);
747 // ServiceWorker is disabled for NPAPI.
748 request
.setSkipServiceWorker(true);
750 if (!SetPostData(&request
, buf
, len
)) {
751 // Uhoh - we're in trouble. There isn't a good way
752 // to recover at this point. Break out.
758 container_
->loadFrameRequest(
759 request
, target_str
, notify_id
!= 0, reinterpret_cast<void*>(notify_id
));
763 NPObject
* WebPluginImpl::GetWindowScriptNPObject() {
768 return webframe_
->windowObject();
771 NPObject
* WebPluginImpl::GetPluginElement() {
772 return container_
->scriptableObjectForElement();
775 bool WebPluginImpl::FindProxyForUrl(const GURL
& url
, std::string
* proxy_list
) {
776 // Proxy resolving doesn't work in single-process mode.
780 void WebPluginImpl::SetCookie(const GURL
& url
,
781 const GURL
& first_party_for_cookies
,
782 const std::string
& cookie
) {
783 if (!render_view_
.get())
786 WebCookieJar
* cookie_jar
= render_frame_
->cookie_jar();
788 DLOG(WARNING
) << "No cookie jar!";
792 cookie_jar
->setCookie(
793 url
, first_party_for_cookies
, WebString::fromUTF8(cookie
));
796 std::string
WebPluginImpl::GetCookies(const GURL
& url
,
797 const GURL
& first_party_for_cookies
) {
798 if (!render_view_
.get())
799 return std::string();
801 WebCookieJar
* cookie_jar
= render_frame_
->cookie_jar();
803 DLOG(WARNING
) << "No cookie jar!";
804 return std::string();
807 return base::UTF16ToUTF8(base::StringPiece16(
808 cookie_jar
->cookies(url
, first_party_for_cookies
)));
811 void WebPluginImpl::URLRedirectResponse(bool allow
, int resource_id
) {
812 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
813 if (clients_
[i
].id
== static_cast<unsigned long>(resource_id
)) {
814 if (clients_
[i
].loader
.get()) {
816 clients_
[i
].loader
->setDefersLoading(false);
818 clients_
[i
].loader
->cancel();
819 if (clients_
[i
].client
)
820 clients_
[i
].client
->DidFail(clients_
[i
].id
);
828 bool WebPluginImpl::CheckIfRunInsecureContent(const GURL
& url
) {
832 return webframe_
->checkIfRunInsecureContent(url
);
835 #if defined(OS_MACOSX)
836 WebPluginAcceleratedSurface
* WebPluginImpl::GetAcceleratedSurface(
837 gfx::GpuPreference gpu_preference
) {
841 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
844 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width
,
847 next_io_surface_allocated_
= true;
848 next_io_surface_width_
= width
;
849 next_io_surface_height_
= height
;
850 next_io_surface_id_
= surface_id
;
853 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
856 // Deferring the call to setBackingIOSurfaceId is an attempt to
857 // work around garbage occasionally showing up in the plugin's
858 // area during live resizing of Core Animation plugins. The
859 // assumption was that by the time this was called, the plugin
860 // process would have populated the newly allocated IOSurface. It
861 // is not 100% clear at this point why any garbage is getting
862 // through. More investigation is needed. http://crbug.com/105346
863 if (next_io_surface_allocated_
) {
864 if (next_io_surface_id_
) {
865 if (!io_surface_layer_
.get()) {
867 cc::IOSurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings());
868 web_layer_
.reset(new cc_blink::WebLayerImpl(io_surface_layer_
));
869 container_
->setWebLayer(web_layer_
.get());
871 io_surface_layer_
->SetIOSurfaceProperties(
873 gfx::Size(next_io_surface_width_
, next_io_surface_height_
));
875 container_
->setWebLayer(NULL
);
877 io_surface_layer_
= NULL
;
879 next_io_surface_allocated_
= false;
881 if (io_surface_layer_
.get())
882 io_surface_layer_
->SetNeedsDisplay();
887 void WebPluginImpl::Invalidate() {
889 container_
->invalidate();
892 void WebPluginImpl::InvalidateRect(const gfx::Rect
& rect
) {
894 container_
->invalidateRect(rect
);
897 void WebPluginImpl::OnDownloadPluginSrcUrl() {
898 HandleURLRequestInternal(
899 plugin_url_
.spec().c_str(), "GET", NULL
, NULL
, 0, 0, false, DOCUMENT_URL
,
903 WebPluginResourceClient
* WebPluginImpl::GetClientFromLoader(
904 WebURLLoader
* loader
) {
905 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
907 return client_info
->client
;
911 WebPluginImpl::ClientInfo
* WebPluginImpl::GetClientInfoFromLoader(
912 WebURLLoader
* loader
) {
913 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
914 if (clients_
[i
].loader
.get() == loader
)
922 void WebPluginImpl::willSendRequest(WebURLLoader
* loader
,
923 WebURLRequest
& request
,
924 const WebURLResponse
& response
) {
925 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedRedirect
926 // until kDirectNPAPIRequests is the default and we can remove this old path.
927 WebPluginImpl::ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
929 // Currently this check is just to catch an https -> http redirect when
930 // loading the main plugin src URL. Longer term, we could investigate
931 // firing mixed diplay or scripting issues for subresource loads
932 // initiated by plugins.
933 if (client_info
->is_plugin_src_load
&&
935 !webframe_
->checkIfRunInsecureContent(request
.url())) {
937 client_info
->client
->DidFail(client_info
->id
);
940 if (net::HttpResponseHeaders::IsRedirectResponseCode(
941 response
.httpStatusCode())) {
942 // If the plugin does not participate in url redirect notifications then
943 // just block cross origin 307 POST redirects.
944 if (!client_info
->notify_redirects
) {
945 if (response
.httpStatusCode() == 307 &&
946 base::LowerCaseEqualsASCII(request
.httpMethod().utf8(), "post")) {
947 GURL
original_request_url(response
.url());
948 GURL
response_url(request
.url());
949 if (original_request_url
.GetOrigin() != response_url
.GetOrigin()) {
950 loader
->setDefersLoading(true);
952 client_info
->client
->DidFail(client_info
->id
);
957 loader
->setDefersLoading(true);
960 client_info
->client
->WillSendRequest(request
.url(),
961 response
.httpStatusCode());
965 void WebPluginImpl::didSendData(WebURLLoader
* loader
,
966 unsigned long long bytes_sent
,
967 unsigned long long total_bytes_to_be_sent
) {
970 void WebPluginImpl::didReceiveResponse(WebURLLoader
* loader
,
971 const WebURLResponse
& response
) {
972 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
973 // until kDirectNPAPIRequests is the default and we can remove this old path.
974 static const int kHttpPartialResponseStatusCode
= 206;
975 static const int kHttpResponseSuccessStatusCode
= 200;
977 WebPluginResourceClient
* client
= GetClientFromLoader(loader
);
981 ResponseInfo response_info
;
982 GetResponseInfo(response
, &response_info
);
983 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
987 bool request_is_seekable
= true;
988 if (client
->IsMultiByteResponseExpected()) {
989 if (response
.httpStatusCode() == kHttpPartialResponseStatusCode
) {
990 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
993 if (HandleHttpMultipartResponse(response
, client
)) {
994 // Multiple ranges requested, data will be delivered by
995 // MultipartResponseDelegate.
996 client_info
->data_offset
= 0;
999 int64 upper_bound
= 0, instance_size
= 0;
1000 // Single range requested - go through original processing for
1001 // non-multipart requests, but update data offset.
1002 MultipartResponseDelegate::ReadContentRanges(response
,
1003 &client_info
->data_offset
,
1006 } else if (response
.httpStatusCode() == kHttpResponseSuccessStatusCode
) {
1007 RenderThreadImpl::current()->RecordAction(
1008 base::UserMetricsAction("Plugin_200ForByteRange"));
1009 // If the client issued a byte range request and the server responds with
1010 // HTTP 200 OK, it indicates that the server does not support byte range
1012 // We need to emulate Firefox behavior by doing the following:-
1013 // 1. Destroy the plugin instance in the plugin process. Ensure that
1014 // existing resource requests initiated for the plugin instance
1015 // continue to remain valid.
1016 // 2. Create a new plugin instance and notify it about the response
1018 if (!ReinitializePluginForResponse(loader
)) {
1023 // The server does not support byte range requests. No point in creating
1024 // seekable streams.
1025 request_is_seekable
= false;
1030 // Create a new resource client for this request.
1031 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
1032 if (clients_
[i
].loader
.get() == loader
) {
1033 WebPluginResourceClient
* resource_client
=
1034 delegate_
->CreateResourceClient(clients_
[i
].id
, plugin_url_
, 0);
1035 clients_
[i
].client
= resource_client
;
1036 client
= resource_client
;
1041 DCHECK(client
!= NULL
);
1045 // Calling into a plugin could result in reentrancy if the plugin yields
1046 // control to the OS like entering a modal loop etc. Prevent this by
1047 // stopping further loading until the plugin notifies us that it is ready to
1049 loader
->setDefersLoading(true);
1051 client
->DidReceiveResponse(
1052 response_info
.mime_type
,
1053 GetAllHeaders(response
),
1054 response_info
.expected_length
,
1055 response_info
.last_modified
,
1056 request_is_seekable
);
1058 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1059 // error codes in the stream header and as a result, was unaware of the
1060 // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1061 // destroy the stream and invoke the NPP_DestroyStream function on the
1062 // plugin if the HTTP request fails.
1063 const GURL
& url
= response
.url();
1064 if (url
.SchemeIs(url::kHttpScheme
) || url
.SchemeIs(url::kHttpsScheme
)) {
1065 if (response
.httpStatusCode() < 100 || response
.httpStatusCode() >= 400) {
1066 // The plugin instance could be in the process of deletion here.
1067 // Verify if the WebPluginResourceClient instance still exists before
1069 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
1071 client_info
->pending_failure_notification
= true;
1077 void WebPluginImpl::didReceiveData(WebURLLoader
* loader
,
1080 int encoded_data_length
) {
1081 WebPluginResourceClient
* client
= GetClientFromLoader(loader
);
1085 MultiPartResponseHandlerMap::iterator index
=
1086 multi_part_response_map_
.find(client
);
1087 if (index
!= multi_part_response_map_
.end()) {
1088 MultipartResponseDelegate
* multi_part_handler
= (*index
).second
;
1089 DCHECK(multi_part_handler
!= NULL
);
1090 multi_part_handler
->OnReceivedData(buffer
,
1092 encoded_data_length
);
1094 loader
->setDefersLoading(true);
1095 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
1096 client
->DidReceiveData(buffer
, data_length
, client_info
->data_offset
);
1097 client_info
->data_offset
+= data_length
;
1101 void WebPluginImpl::didFinishLoading(WebURLLoader
* loader
, double finishTime
) {
1102 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
1103 if (client_info
&& client_info
->client
) {
1104 MultiPartResponseHandlerMap::iterator index
=
1105 multi_part_response_map_
.find(client_info
->client
);
1106 if (index
!= multi_part_response_map_
.end()) {
1107 delete (*index
).second
;
1108 multi_part_response_map_
.erase(index
);
1111 loader
->setDefersLoading(true);
1112 WebPluginResourceClient
* resource_client
= client_info
->client
;
1113 // The ClientInfo can get deleted in the call to DidFinishLoading below.
1114 // It is not safe to access this structure after that.
1115 client_info
->client
= NULL
;
1116 resource_client
->DidFinishLoading(client_info
->id
);
1120 void WebPluginImpl::didFail(WebURLLoader
* loader
,
1121 const WebURLError
& error
) {
1122 ClientInfo
* client_info
= GetClientInfoFromLoader(loader
);
1123 if (client_info
&& client_info
->client
) {
1124 loader
->setDefersLoading(true);
1125 WebPluginResourceClient
* resource_client
= client_info
->client
;
1126 // The ClientInfo can get deleted in the call to DidFail below.
1127 // It is not safe to access this structure after that.
1128 client_info
->client
= NULL
;
1129 resource_client
->DidFail(client_info
->id
);
1133 void WebPluginImpl::RemoveClient(size_t i
) {
1134 clients_
.erase(clients_
.begin() + i
);
1137 void WebPluginImpl::RemoveClient(WebURLLoader
* loader
) {
1138 for (size_t i
= 0; i
< clients_
.size(); ++i
) {
1139 if (clients_
[i
].loader
.get() == loader
) {
1146 void WebPluginImpl::SetContainer(WebPluginContainer
* container
) {
1148 TearDownPluginInstance(NULL
);
1149 container_
= container
;
1151 container_
->allowScriptObjects();
1154 void WebPluginImpl::HandleURLRequest(const char* url
,
1160 bool popups_allowed
,
1161 bool notify_redirects
) {
1162 // GetURL/PostURL requests initiated explicitly by plugins should specify the
1163 // plugin SRC url as the referrer if it is available.
1164 HandleURLRequestInternal(
1165 url
, method
, target
, buf
, len
, notify_id
, popups_allowed
, PLUGIN_SRC
,
1166 notify_redirects
, false);
1169 void WebPluginImpl::HandleURLRequestInternal(const char* url
,
1175 bool popups_allowed
,
1176 ReferrerValue referrer_flag
,
1177 bool notify_redirects
,
1178 bool is_plugin_src_load
) {
1179 // For this request, we either route the output to a frame
1180 // because a target has been specified, or we handle the request
1181 // here, i.e. by executing the script if it is a javascript url
1182 // or by initiating a download on the URL, etc. There is one special
1183 // case in that the request is a javascript url and the target is "_self",
1184 // in which case we route the output to the plugin rather than routing it
1185 // to the plugin's frame.
1186 bool is_javascript_url
=
1187 url::FindAndCompareScheme(url
, strlen(url
), url::kJavaScriptScheme
, NULL
);
1188 RoutingStatus routing_status
= RouteToFrame(
1189 url
, is_javascript_url
, popups_allowed
, method
, target
, buf
, len
,
1190 notify_id
, referrer_flag
);
1191 if (routing_status
== ROUTED
)
1194 if (is_javascript_url
) {
1196 WebString result
= container_
->executeScriptURL(gurl
, popups_allowed
);
1198 // delegate_ could be NULL because executeScript caused the container to
1201 delegate_
->SendJavaScriptStream(
1202 gurl
, result
.utf8(), !result
.isNull(), notify_id
);
1208 unsigned long resource_id
= GetNextResourceId();
1212 GURL complete_url
= CompleteURL(url
);
1213 // Remove when flash bug is fixed. http://crbug.com/40016.
1214 if (!WebPluginImpl::IsValidUrl(complete_url
, referrer_flag
))
1217 // If the RouteToFrame call returned a failure then inform the result
1218 // back to the plugin asynchronously.
1219 if ((routing_status
== INVALID_URL
) ||
1220 (routing_status
== GENERAL_FAILURE
)) {
1221 WebPluginResourceClient
* resource_client
= delegate_
->CreateResourceClient(
1222 resource_id
, complete_url
, notify_id
);
1223 if (resource_client
)
1224 resource_client
->DidFail(resource_id
);
1228 // CreateResourceClient() sends a synchronous IPC message so it's possible
1229 // that TearDownPluginInstance() may have been called in the nested
1230 // message loop. If so, don't start the request.
1234 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1235 switches::kDisableDirectNPAPIRequests
)) {
1236 // We got here either because the plugin called GetURL/PostURL, or because
1237 // we're fetching the data for an embed tag. If we're in multi-process mode,
1238 // we want to fetch the data in the plugin process as the renderer won't be
1239 // able to request any origin when site isolation is in place. So bounce
1240 // this request back to the plugin process which will use ResourceDispatcher
1241 // to fetch the url.
1243 // TODO(jam): any better way of getting this? Can't find a way to get
1244 // frame()->loader()->outgoingReferrer() which
1245 // WebFrameImpl::setReferrerForRequest does.
1246 WebURLRequest
request(complete_url
);
1247 SetReferrer(&request
, referrer_flag
);
1249 GURL(request
.httpHeaderField(WebString::fromUTF8("Referer"))),
1250 request
.referrerPolicy());
1252 GURL first_party_for_cookies
= webframe_
->document().firstPartyForCookies();
1253 delegate_
->FetchURL(resource_id
, notify_id
, complete_url
,
1254 first_party_for_cookies
, method
, buf
, len
, referrer
,
1255 notify_redirects
, is_plugin_src_load
, 0,
1256 render_frame_
->GetRoutingID(),
1257 render_view_
->GetRoutingID());
1259 WebPluginResourceClient
* resource_client
= delegate_
->CreateResourceClient(
1260 resource_id
, complete_url
, notify_id
);
1261 if (!resource_client
)
1263 InitiateHTTPRequest(resource_id
, resource_client
, complete_url
, method
, buf
,
1264 len
, NULL
, referrer_flag
, notify_redirects
,
1265 is_plugin_src_load
);
1269 unsigned long WebPluginImpl::GetNextResourceId() {
1272 WebView
* view
= webframe_
->view();
1275 return view
->createUniqueIdentifierForRequest();
1278 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id
,
1279 WebPluginResourceClient
* client
,
1284 const char* range_info
,
1285 ReferrerValue referrer_flag
,
1286 bool notify_redirects
,
1287 bool is_plugin_src_load
) {
1294 info
.id
= resource_id
;
1295 info
.client
= client
;
1296 info
.request
.initialize();
1297 info
.request
.setURL(url
);
1298 info
.request
.setFirstPartyForCookies(
1299 webframe_
->document().firstPartyForCookies());
1300 info
.request
.setRequestorProcessID(delegate_
->GetProcessId());
1301 // TODO(mkwst): Is this a request for a plugin object itself
1302 // (RequestContextObject), or a request that the plugin makes
1303 // (RequestContextPlugin)?
1304 info
.request
.setRequestContext(WebURLRequest::RequestContextPlugin
);
1305 info
.request
.setHTTPMethod(WebString::fromUTF8(method
));
1306 // ServiceWorker is disabled for NPAPI.
1307 info
.request
.setSkipServiceWorker(true);
1308 info
.pending_failure_notification
= false;
1309 info
.notify_redirects
= notify_redirects
;
1310 info
.is_plugin_src_load
= is_plugin_src_load
;
1311 info
.data_offset
= 0;
1314 info
.request
.addHTTPHeaderField(WebString::fromUTF8("Range"),
1315 WebString::fromUTF8(range_info
));
1318 if (strcmp(method
, "POST") == 0) {
1319 // Adds headers or form data to a request. This must be called before
1320 // we initiate the actual request.
1321 SetPostData(&info
.request
, buf
, buf_len
);
1324 SetReferrer(&info
.request
, referrer_flag
);
1326 WebURLLoaderOptions options
;
1327 options
.allowCredentials
= true;
1328 options
.crossOriginRequestPolicy
=
1329 WebURLLoaderOptions::CrossOriginRequestPolicyAllow
;
1330 info
.loader
.reset(webframe_
->createAssociatedURLLoader(options
));
1331 if (!info
.loader
.get())
1333 info
.loader
->loadAsynchronously(info
.request
, &loader_client_
);
1335 clients_
.push_back(info
);
1339 void WebPluginImpl::CancelDocumentLoad() {
1341 ignore_response_error_
= true;
1342 webframe_
->stopLoading();
1346 void WebPluginImpl::InitiateHTTPRangeRequest(
1347 const char* url
, const char* range_info
, int range_request_id
) {
1348 unsigned long resource_id
= GetNextResourceId();
1352 GURL complete_url
= CompleteURL(url
);
1353 // Remove when flash bug is fixed. http://crbug.com/40016.
1354 if (!WebPluginImpl::IsValidUrl(complete_url
,
1355 load_manually_
? NO_REFERRER
: PLUGIN_SRC
))
1358 WebPluginResourceClient
* resource_client
=
1359 delegate_
->CreateSeekableResourceClient(resource_id
, range_request_id
);
1360 InitiateHTTPRequest(
1361 resource_id
, resource_client
, complete_url
, "GET", NULL
, 0, range_info
,
1362 load_manually_
? NO_REFERRER
: PLUGIN_SRC
, false, false);
1365 void WebPluginImpl::DidStartLoading() {
1366 if (render_view_
.get()) {
1367 // TODO(darin): Make is_loading_ be a counter!
1368 render_view_
->DidStartLoading();
1372 void WebPluginImpl::DidStopLoading() {
1373 if (render_view_
.get()) {
1374 // TODO(darin): Make is_loading_ be a counter!
1375 render_view_
->DidStopLoading();
1379 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id
,
1381 std::vector
<ClientInfo
>::iterator client_index
= clients_
.begin();
1382 while (client_index
!= clients_
.end()) {
1383 ClientInfo
& client_info
= *client_index
;
1385 if (client_info
.id
== resource_id
) {
1386 client_info
.loader
->setDefersLoading(defer
);
1388 // If we determined that the request had failed via the HTTP headers
1389 // in the response then we send out a failure notification to the
1390 // plugin process, as certain plugins don't handle HTTP failure codes
1392 if (!defer
&& client_info
.client
&&
1393 client_info
.pending_failure_notification
) {
1394 // The ClientInfo and the iterator can become invalid due to the call
1395 // to DidFail below.
1396 WebPluginResourceClient
* resource_client
= client_info
.client
;
1397 client_info
.loader
->cancel();
1398 clients_
.erase(client_index
++);
1399 resource_client
->DidFail(resource_id
);
1407 bool WebPluginImpl::IsOffTheRecord() {
1411 bool WebPluginImpl::HandleHttpMultipartResponse(
1412 const WebURLResponse
& response
, WebPluginResourceClient
* client
) {
1413 std::string multipart_boundary
;
1414 if (!MultipartResponseDelegate::ReadMultipartBoundary(
1415 response
, &multipart_boundary
)) {
1421 MultiPartResponseClient
* multi_part_response_client
=
1422 new MultiPartResponseClient(client
);
1424 MultipartResponseDelegate
* multi_part_response_handler
=
1425 new MultipartResponseDelegate(multi_part_response_client
, NULL
,
1427 multipart_boundary
);
1428 multi_part_response_map_
[client
] = multi_part_response_handler
;
1432 bool WebPluginImpl::ReinitializePluginForResponse(
1433 WebURLLoader
* loader
) {
1434 WebFrame
* webframe
= webframe_
;
1438 WebView
* webview
= webframe
->view();
1442 WebPluginContainer
* container_widget
= container_
;
1444 // Destroy the current plugin instance.
1445 TearDownPluginInstance(loader
);
1447 container_
= container_widget
;
1448 webframe_
= webframe
;
1450 WebPluginDelegateProxy
* plugin_delegate
= new WebPluginDelegateProxy(
1451 this, mime_type_
, render_view_
, render_frame_
);
1453 // Store the plugin's unique identifier, used by the container to track its
1454 // script objects, and enable script objects (since Initialize may use them
1455 // even if it fails).
1456 npp_
= plugin_delegate
->GetPluginNPP();
1457 container_
->allowScriptObjects();
1459 bool ok
= plugin_delegate
&& plugin_delegate
->Initialize(
1460 plugin_url_
, arg_names_
, arg_values_
, load_manually_
);
1463 container_
->clearScriptObjects();
1465 // TODO(iyengar) Should we delete the current plugin instance here?
1469 delegate_
= plugin_delegate
;
1471 // Force a geometry update to occur to ensure that the plugin becomes
1473 container_
->reportGeometry();
1475 // The plugin move sequences accumulated via DidMove are sent to the browser
1476 // whenever the renderer paints. Force a paint here to ensure that changes
1477 // to the plugin window are propagated to the browser.
1478 container_
->invalidate();
1482 void WebPluginImpl::TearDownPluginInstance(
1483 WebURLLoader
* loader_to_ignore
) {
1484 // JavaScript garbage collection may cause plugin script object references to
1485 // be retained long after the plugin is destroyed. Some plugins won't cope
1486 // with their objects being released after they've been destroyed, and once
1487 // we've actually unloaded the plugin the object's releaseobject() code may
1488 // no longer be in memory. The container tracks the plugin's objects and lets
1489 // us invalidate them, releasing the references to them held by the JavaScript
1492 container_
->clearScriptObjects();
1493 container_
->setWebLayer(NULL
);
1496 // Call PluginDestroyed() first to prevent the plugin from calling us back
1497 // in the middle of tearing down the render tree.
1499 // The plugin may call into the browser and pass script objects even during
1500 // teardown, so temporarily re-enable plugin script objects.
1502 container_
->allowScriptObjects();
1504 delegate_
->PluginDestroyed();
1507 // Invalidate any script objects created during teardown here, before the
1508 // plugin might actually be unloaded.
1509 container_
->clearScriptObjects();
1512 // Cancel any pending requests because otherwise this deleted object will
1513 // be called by the ResourceDispatcher.
1514 std::vector
<ClientInfo
>::iterator client_index
= clients_
.begin();
1515 while (client_index
!= clients_
.end()) {
1516 ClientInfo
& client_info
= *client_index
;
1518 if (loader_to_ignore
== client_info
.loader
) {
1523 if (client_info
.loader
.get())
1524 client_info
.loader
->cancel();
1526 client_index
= clients_
.erase(client_index
);
1529 // This needs to be called now and not in the destructor since the
1530 // webframe_ might not be valid anymore.
1532 weak_factory_
.InvalidateWeakPtrs();
1535 void WebPluginImpl::SetReferrer(blink::WebURLRequest
* request
,
1536 ReferrerValue referrer_flag
) {
1537 switch (referrer_flag
) {
1539 webframe_
->setReferrerForRequest(*request
, GURL());
1543 webframe_
->setReferrerForRequest(*request
, plugin_url_
);
1551 } // namespace content