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

Side by Side Diff: webkit/plugins/npapi/webplugin_impl.cc

Issue 19761007: Move NPAPI implementation out of webkit/plugins/npapi and into content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix mac Created 7 years, 5 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 | Annotate | Revision Log
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 "webkit/plugins/npapi/webplugin_impl.h"
6
7 #include "base/bind.h"
8 #include "base/debug/crash_logging.h"
9 #include "base/logging.h"
10 #include "base/memory/linked_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "cc/layers/io_surface_layer.h"
16 #include "net/base/escape.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_response_headers.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/public/platform/WebCString.h"
21 #include "third_party/WebKit/public/platform/WebCookieJar.h"
22 #include "third_party/WebKit/public/platform/WebData.h"
23 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
24 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
25 #include "third_party/WebKit/public/platform/WebURL.h"
26 #include "third_party/WebKit/public/platform/WebURLError.h"
27 #include "third_party/WebKit/public/platform/WebURLLoader.h"
28 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
29 #include "third_party/WebKit/public/platform/WebURLResponse.h"
30 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
31 #include "third_party/WebKit/public/web/WebCursorInfo.h"
32 #include "third_party/WebKit/public/web/WebDocument.h"
33 #include "third_party/WebKit/public/web/WebFrame.h"
34 #include "third_party/WebKit/public/web/WebInputEvent.h"
35 #include "third_party/WebKit/public/web/WebKit.h"
36 #include "third_party/WebKit/public/web/WebPluginContainer.h"
37 #include "third_party/WebKit/public/web/WebPluginParams.h"
38 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
39 #include "third_party/WebKit/public/web/WebView.h"
40 #include "ui/gfx/rect.h"
41 #include "url/gurl.h"
42 #include "url/url_util.h"
43 #include "webkit/glue/multipart_response_delegate.h"
44 #include "webkit/plugins/npapi/plugin_host.h"
45 #include "webkit/plugins/npapi/plugin_instance.h"
46 #include "webkit/plugins/npapi/webplugin_delegate.h"
47 #include "webkit/plugins/npapi/webplugin_page_delegate.h"
48 #include "webkit/plugins/plugin_constants.h"
49 #include "webkit/renderer/appcache/web_application_cache_host_impl.h"
50 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
51
52 using appcache::WebApplicationCacheHostImpl;
53 using WebKit::WebCanvas;
54 using WebKit::WebConsoleMessage;
55 using WebKit::WebCookieJar;
56 using WebKit::WebCString;
57 using WebKit::WebCursorInfo;
58 using WebKit::WebData;
59 using WebKit::WebDataSource;
60 using WebKit::WebFrame;
61 using WebKit::WebHTTPBody;
62 using WebKit::WebHTTPHeaderVisitor;
63 using WebKit::WebInputEvent;
64 using WebKit::WebKeyboardEvent;
65 using WebKit::WebMouseEvent;
66 using WebKit::WebPluginContainer;
67 using WebKit::WebPluginParams;
68 using WebKit::WebRect;
69 using WebKit::WebString;
70 using WebKit::WebURL;
71 using WebKit::WebURLError;
72 using WebKit::WebURLLoader;
73 using WebKit::WebURLLoaderClient;
74 using WebKit::WebURLLoaderOptions;
75 using WebKit::WebURLRequest;
76 using WebKit::WebURLResponse;
77 using WebKit::WebVector;
78 using WebKit::WebView;
79 using webkit_glue::MultipartResponseDelegate;
80
81 namespace webkit {
82 namespace npapi {
83
84 namespace {
85
86 // This class handles individual multipart responses. It is instantiated when
87 // we receive HTTP status code 206 in the HTTP response. This indicates
88 // that the response could have multiple parts each separated by a boundary
89 // specified in the response header.
90 class MultiPartResponseClient : public WebURLLoaderClient {
91 public:
92 explicit MultiPartResponseClient(WebPluginResourceClient* resource_client)
93 : resource_client_(resource_client) {
94 Clear();
95 }
96
97 virtual void willSendRequest(
98 WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
99 virtual void didSendData(
100 WebURLLoader*, unsigned long long, unsigned long long) {}
101
102 // Called when the multipart parser encounters an embedded multipart
103 // response.
104 virtual void didReceiveResponse(
105 WebURLLoader*, const WebURLResponse& response) {
106 int64 instance_size;
107 if (!MultipartResponseDelegate::ReadContentRanges(
108 response,
109 &byte_range_lower_bound_,
110 &byte_range_upper_bound_,
111 &instance_size)) {
112 NOTREACHED();
113 return;
114 }
115
116 resource_response_ = response;
117 }
118
119 // Receives individual part data from a multipart response.
120 virtual void didReceiveData(WebURLLoader*,
121 const char* data,
122 int data_length,
123 int encoded_data_length) {
124 // TODO(ananta)
125 // We should defer further loads on multipart resources on the same lines
126 // as regular resources requested by plugins to prevent reentrancy.
127 resource_client_->DidReceiveData(
128 data, data_length, byte_range_lower_bound_);
129 byte_range_lower_bound_ += data_length;
130 }
131
132 virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
133 virtual void didFail(WebURLLoader*, const WebURLError&) {}
134
135 void Clear() {
136 resource_response_.reset();
137 byte_range_lower_bound_ = 0;
138 byte_range_upper_bound_ = 0;
139 }
140
141 private:
142 WebURLResponse resource_response_;
143 // The lower bound of the byte range.
144 int64 byte_range_lower_bound_;
145 // The upper bound of the byte range.
146 int64 byte_range_upper_bound_;
147 // The handler for the data.
148 WebPluginResourceClient* resource_client_;
149 };
150
151 class HeaderFlattener : public WebHTTPHeaderVisitor {
152 public:
153 explicit HeaderFlattener(std::string* buf) : buf_(buf) {
154 }
155
156 virtual void visitHeader(const WebString& name, const WebString& value) {
157 // TODO(darin): Should we really exclude headers with an empty value?
158 if (!name.isEmpty() && !value.isEmpty()) {
159 buf_->append(name.utf8());
160 buf_->append(": ");
161 buf_->append(value.utf8());
162 buf_->append("\n");
163 }
164 }
165
166 private:
167 std::string* buf_;
168 };
169
170 std::string GetAllHeaders(const WebURLResponse& response) {
171 // TODO(darin): It is possible for httpStatusText to be empty and still have
172 // an interesting response, so this check seems wrong.
173 std::string result;
174 const WebString& status = response.httpStatusText();
175 if (status.isEmpty())
176 return result;
177
178 // TODO(darin): Shouldn't we also report HTTP version numbers?
179 result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
180 result.append(status.utf8());
181 result.append("\n");
182
183 HeaderFlattener flattener(&result);
184 response.visitHTTPHeaderFields(&flattener);
185
186 return result;
187 }
188
189 struct ResponseInfo {
190 GURL url;
191 std::string mime_type;
192 uint32 last_modified;
193 uint32 expected_length;
194 };
195
196 void GetResponseInfo(const WebURLResponse& response,
197 ResponseInfo* response_info) {
198 response_info->url = response.url();
199 response_info->mime_type = response.mimeType().utf8();
200
201 // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
202 response_info->last_modified =
203 static_cast<uint32>(response.lastModifiedDate());
204
205 // If the length comes in as -1, then it indicates that it was not
206 // read off the HTTP headers. We replicate Safari webkit behavior here,
207 // which is to set it to 0.
208 response_info->expected_length =
209 static_cast<uint32>(std::max(response.expectedContentLength(), 0LL));
210
211 WebString content_encoding =
212 response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
213 if (!content_encoding.isNull() &&
214 !EqualsASCII(content_encoding, "identity")) {
215 // Don't send the compressed content length to the plugin, which only
216 // cares about the decoded length.
217 response_info->expected_length = 0;
218 }
219 }
220
221 } // namespace
222
223 // WebKit::WebPlugin ----------------------------------------------------------
224
225 struct WebPluginImpl::ClientInfo {
226 unsigned long id;
227 WebPluginResourceClient* client;
228 WebKit::WebURLRequest request;
229 bool pending_failure_notification;
230 linked_ptr<WebKit::WebURLLoader> loader;
231 bool notify_redirects;
232 bool is_plugin_src_load;
233 int64 data_offset;
234 };
235
236 bool WebPluginImpl::initialize(WebPluginContainer* container) {
237 if (!page_delegate_.get()) {
238 LOG(ERROR) << "No page delegate";
239 return false;
240 }
241
242 WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate(
243 file_path_, mime_type_);
244 if (!plugin_delegate)
245 return false;
246
247 // Store the plugin's unique identifier, used by the container to track its
248 // script objects.
249 npp_ = plugin_delegate->GetPluginNPP();
250
251 // Set the container before Initialize because the plugin may
252 // synchronously call NPN_GetValue to get its container, or make calls
253 // passing script objects that need to be tracked, during initialization.
254 SetContainer(container);
255
256 bool ok = plugin_delegate->Initialize(
257 plugin_url_, arg_names_, arg_values_, this, load_manually_);
258 if (!ok) {
259 LOG(ERROR) << "Couldn't initialize plug-in";
260 plugin_delegate->PluginDestroyed();
261
262 WebKit::WebPlugin* replacement_plugin =
263 page_delegate_->CreatePluginReplacement(file_path_);
264 if (!replacement_plugin)
265 return false;
266
267 // Disable scripting by this plugin before replacing it with the new
268 // one. This plugin also needs destroying, so use destroy(), which will
269 // implicitly disable scripting while un-setting the container.
270 destroy();
271
272 // Inform the container of the replacement plugin, then initialize it.
273 container->setPlugin(replacement_plugin);
274 return replacement_plugin->initialize(container);
275 }
276
277 delegate_ = plugin_delegate;
278
279 return true;
280 }
281
282 void WebPluginImpl::destroy() {
283 SetContainer(NULL);
284 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
285 }
286
287 NPObject* WebPluginImpl::scriptableObject() {
288 if (!delegate_)
289 return NULL;
290
291 return delegate_->GetPluginScriptableObject();
292 }
293
294 NPP WebPluginImpl::pluginNPP() {
295 return npp_;
296 }
297
298 bool WebPluginImpl::getFormValue(WebKit::WebString& value) {
299 if (!delegate_)
300 return false;
301 base::string16 form_value;
302 if (!delegate_->GetFormValue(&form_value))
303 return false;
304 value = form_value;
305 return true;
306 }
307
308 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
309 if (!delegate_ || !container_)
310 return;
311
312 #if defined(OS_WIN)
313 // Force a geometry update if needed to allow plugins like media player
314 // which defer the initial geometry update to work.
315 container_->reportGeometry();
316 #endif // OS_WIN
317
318 // Note that |canvas| is only used when in windowless mode.
319 delegate_->Paint(canvas, paint_rect);
320 }
321
322 void WebPluginImpl::updateGeometry(
323 const WebRect& window_rect, const WebRect& clip_rect,
324 const WebVector<WebRect>& cutout_rects, bool is_visible) {
325 WebPluginGeometry new_geometry;
326 new_geometry.window = window_;
327 new_geometry.window_rect = window_rect;
328 new_geometry.clip_rect = clip_rect;
329 new_geometry.visible = is_visible;
330 new_geometry.rects_valid = true;
331 for (size_t i = 0; i < cutout_rects.size(); ++i)
332 new_geometry.cutout_rects.push_back(cutout_rects[i]);
333
334 // Only send DidMovePlugin if the geometry changed in some way.
335 if (window_ && page_delegate_.get() &&
336 (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
337 page_delegate_->DidMovePlugin(new_geometry);
338 // We invalidate windowed plugins during the first geometry update to
339 // ensure that they get reparented to the wrapper window in the browser.
340 // This ensures that they become visible and are painted by the OS. This is
341 // required as some pages don't invalidate when the plugin is added.
342 if (first_geometry_update_ && window_) {
343 InvalidateRect(window_rect);
344 }
345 }
346
347 // Only UpdateGeometry if either the window or clip rects have changed.
348 if (delegate_ && (first_geometry_update_ ||
349 new_geometry.window_rect != geometry_.window_rect ||
350 new_geometry.clip_rect != geometry_.clip_rect)) {
351 // Notify the plugin that its parameters have changed.
352 delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
353 }
354
355 // Initiate a download on the plugin url. This should be done for the
356 // first update geometry sequence. We need to ensure that the plugin
357 // receives the geometry update before it starts receiving data.
358 if (first_geometry_update_) {
359 // An empty url corresponds to an EMBED tag with no src attribute.
360 if (!load_manually_ && plugin_url_.is_valid()) {
361 // The Flash plugin hangs for a while if it receives data before
362 // receiving valid plugin geometry. By valid geometry we mean the
363 // geometry received by a call to setFrameRect in the Webkit
364 // layout code path. To workaround this issue we download the
365 // plugin source url on a timer.
366 base::MessageLoop::current()->PostTask(
367 FROM_HERE,
368 base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl,
369 weak_factory_.GetWeakPtr()));
370 }
371 }
372
373 #if defined(OS_WIN)
374 // Don't cache the geometry during the first geometry update. The first
375 // geometry update sequence is received when Widget::setParent is called.
376 // For plugins like media player which have a bug where they only honor
377 // the first geometry update, we have a quirk which ignores the first
378 // geometry update. To ensure that these plugins work correctly in cases
379 // where we receive only one geometry update from webkit, we also force
380 // a geometry update during paint which should go out correctly as the
381 // initial geometry update was not cached.
382 if (!first_geometry_update_)
383 geometry_ = new_geometry;
384 #else // OS_WIN
385 geometry_ = new_geometry;
386 #endif // OS_WIN
387 first_geometry_update_ = false;
388 }
389
390 void WebPluginImpl::updateFocus(bool focused) {
391 if (accepts_input_events_)
392 delegate_->SetFocus(focused);
393 }
394
395 void WebPluginImpl::updateVisibility(bool visible) {
396 if (!window_ || !page_delegate_.get())
397 return;
398
399 WebPluginGeometry move;
400 move.window = window_;
401 move.window_rect = gfx::Rect();
402 move.clip_rect = gfx::Rect();
403 move.rects_valid = false;
404 move.visible = visible;
405
406 page_delegate_->DidMovePlugin(move);
407 }
408
409 bool WebPluginImpl::acceptsInputEvents() {
410 return accepts_input_events_;
411 }
412
413 bool WebPluginImpl::handleInputEvent(
414 const WebInputEvent& event, WebCursorInfo& cursor_info) {
415 // Swallow context menu events in order to suppress the default context menu.
416 if (event.type == WebInputEvent::ContextMenu)
417 return true;
418
419 WebCursor::CursorInfo web_cursor_info;
420 bool ret = delegate_->HandleInputEvent(event, &web_cursor_info);
421 cursor_info.type = web_cursor_info.type;
422 cursor_info.hotSpot = web_cursor_info.hotspot;
423 cursor_info.customImage = web_cursor_info.custom_image;
424 cursor_info.imageScaleFactor = web_cursor_info.image_scale_factor;
425 #if defined(OS_WIN)
426 cursor_info.externalHandle = web_cursor_info.external_handle;
427 #endif
428 return ret;
429 }
430
431 void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
432 ignore_response_error_ = false;
433
434 ResponseInfo response_info;
435 GetResponseInfo(response, &response_info);
436
437 delegate_->DidReceiveManualResponse(
438 response_info.url,
439 response_info.mime_type,
440 GetAllHeaders(response),
441 response_info.expected_length,
442 response_info.last_modified);
443 }
444
445 void WebPluginImpl::didReceiveData(const char* data, int data_length) {
446 delegate_->DidReceiveManualData(data, data_length);
447 }
448
449 void WebPluginImpl::didFinishLoading() {
450 delegate_->DidFinishManualLoading();
451 }
452
453 void WebPluginImpl::didFailLoading(const WebURLError& error) {
454 if (!ignore_response_error_)
455 delegate_->DidManualLoadFail();
456 }
457
458 void WebPluginImpl::didFinishLoadingFrameRequest(
459 const WebURL& url, void* notify_data) {
460 if (delegate_) {
461 // We're converting a void* into an arbitrary int id. Though
462 // these types are the same size on all the platforms we support,
463 // the compiler may complain as though they are different, so to
464 // make the casting gods happy go through an intptr_t (the union
465 // of void* and int) rather than converting straight across.
466 delegate_->DidFinishLoadWithReason(
467 url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data));
468 }
469 }
470
471 void WebPluginImpl::didFailLoadingFrameRequest(
472 const WebURL& url, void* notify_data, const WebURLError& error) {
473 if (!delegate_)
474 return;
475
476 NPReason reason =
477 error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR;
478 // See comment in didFinishLoadingFrameRequest about the cast here.
479 delegate_->DidFinishLoadWithReason(
480 url, reason, reinterpret_cast<intptr_t>(notify_data));
481 }
482
483 bool WebPluginImpl::isPlaceholder() {
484 return false;
485 }
486
487 // -----------------------------------------------------------------------------
488
489 WebPluginImpl::WebPluginImpl(
490 WebFrame* webframe,
491 const WebPluginParams& params,
492 const base::FilePath& file_path,
493 const base::WeakPtr<WebPluginPageDelegate>& page_delegate)
494 : windowless_(false),
495 window_(gfx::kNullPluginWindow),
496 accepts_input_events_(false),
497 page_delegate_(page_delegate),
498 webframe_(webframe),
499 delegate_(NULL),
500 container_(NULL),
501 npp_(NULL),
502 plugin_url_(params.url),
503 load_manually_(params.loadManually),
504 first_geometry_update_(true),
505 ignore_response_error_(false),
506 file_path_(file_path),
507 mime_type_(UTF16ToASCII(params.mimeType)),
508 weak_factory_(this) {
509 DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
510 StringToLowerASCII(&mime_type_);
511
512 for (size_t i = 0; i < params.attributeNames.size(); ++i) {
513 arg_names_.push_back(params.attributeNames[i].utf8());
514 arg_values_.push_back(params.attributeValues[i].utf8());
515 }
516
517 // Set subresource URL for crash reporting.
518 base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec());
519 }
520
521 WebPluginImpl::~WebPluginImpl() {
522 }
523
524 void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
525 if (window) {
526 DCHECK(!windowless_);
527 window_ = window;
528 #if defined(OS_MACOSX)
529 // TODO(kbr): remove. http://crbug.com/105344
530
531 // Lie to ourselves about being windowless even if we got a fake
532 // plugin window handle, so we continue to get input events.
533 windowless_ = true;
534 accepts_input_events_ = true;
535 // We do not really need to notify the page delegate that a plugin
536 // window was created -- so don't.
537 #else
538 accepts_input_events_ = false;
539 if (page_delegate_.get()) {
540 // Tell the view delegate that the plugin window was created, so that it
541 // can create necessary container widgets.
542 page_delegate_->CreatedPluginWindow(window);
543 }
544 #endif
545 } else {
546 DCHECK(!window_); // Make sure not called twice.
547 windowless_ = true;
548 accepts_input_events_ = true;
549 }
550 }
551
552 void WebPluginImpl::SetAcceptsInputEvents(bool accepts) {
553 accepts_input_events_ = accepts;
554 }
555
556 void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) {
557 DCHECK_EQ(window, window_);
558 window_ = gfx::kNullPluginWindow;
559 if (page_delegate_.get())
560 page_delegate_->WillDestroyPluginWindow(window);
561 }
562
563 GURL WebPluginImpl::CompleteURL(const char* url) {
564 if (!webframe_) {
565 NOTREACHED();
566 return GURL();
567 }
568 // TODO(darin): Is conversion from UTF8 correct here?
569 return webframe_->document().completeURL(WebString::fromUTF8(url));
570 }
571
572 void WebPluginImpl::CancelResource(unsigned long id) {
573 for (size_t i = 0; i < clients_.size(); ++i) {
574 if (clients_[i].id == id) {
575 if (clients_[i].loader.get()) {
576 clients_[i].loader->setDefersLoading(false);
577 clients_[i].loader->cancel();
578 RemoveClient(i);
579 }
580 return;
581 }
582 }
583 }
584
585 bool WebPluginImpl::SetPostData(WebURLRequest* request,
586 const char *buf,
587 uint32 length) {
588 std::vector<std::string> names;
589 std::vector<std::string> values;
590 std::vector<char> body;
591 bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body);
592
593 for (size_t i = 0; i < names.size(); ++i) {
594 request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
595 WebString::fromUTF8(values[i]));
596 }
597
598 WebString content_type_header = WebString::fromUTF8("Content-Type");
599 const WebString& content_type =
600 request->httpHeaderField(content_type_header);
601 if (content_type.isEmpty()) {
602 request->setHTTPHeaderField(
603 content_type_header,
604 WebString::fromUTF8("application/x-www-form-urlencoded"));
605 }
606
607 WebHTTPBody http_body;
608 if (body.size()) {
609 http_body.initialize();
610 http_body.appendData(WebData(&body[0], body.size()));
611 }
612 request->setHTTPBody(http_body);
613
614 return rv;
615 }
616
617 WebPluginDelegate* WebPluginImpl::delegate() {
618 return delegate_;
619 }
620
621 bool WebPluginImpl::IsValidUrl(const GURL& url, Referrer referrer_flag) {
622 if (referrer_flag == PLUGIN_SRC &&
623 mime_type_ == kFlashPluginSwfMimeType &&
624 url.GetOrigin() != plugin_url_.GetOrigin()) {
625 // Do url check to make sure that there are no @, ;, \ chars in between url
626 // scheme and url path.
627 const char* url_to_check(url.spec().data());
628 url_parse::Parsed parsed;
629 url_parse::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
630 if (parsed.path.begin <= parsed.scheme.end())
631 return true;
632 std::string string_to_search;
633 string_to_search.assign(url_to_check + parsed.scheme.end(),
634 parsed.path.begin - parsed.scheme.end());
635 if (string_to_search.find("@") != std::string::npos ||
636 string_to_search.find(";") != std::string::npos ||
637 string_to_search.find("\\") != std::string::npos)
638 return false;
639 }
640
641 return true;
642 }
643
644 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
645 const char* url,
646 bool is_javascript_url,
647 bool popups_allowed,
648 const char* method,
649 const char* target,
650 const char* buf,
651 unsigned int len,
652 int notify_id,
653 Referrer referrer_flag) {
654 // If there is no target, there is nothing to do
655 if (!target)
656 return NOT_ROUTED;
657
658 // This could happen if the WebPluginContainer was already deleted.
659 if (!webframe_)
660 return NOT_ROUTED;
661
662 WebString target_str = WebString::fromUTF8(target);
663
664 // Take special action for JavaScript URLs
665 if (is_javascript_url) {
666 WebFrame* target_frame =
667 webframe_->view()->findFrameByName(target_str, webframe_);
668 // For security reasons, do not allow JavaScript on frames
669 // other than this frame.
670 if (target_frame != webframe_) {
671 // TODO(darin): Localize this message.
672 const char kMessage[] =
673 "Ignoring cross-frame javascript URL load requested by plugin.";
674 webframe_->addMessageToConsole(
675 WebConsoleMessage(WebConsoleMessage::LevelError,
676 WebString::fromUTF8(kMessage)));
677 return ROUTED;
678 }
679
680 // Route javascript calls back to the plugin.
681 return NOT_ROUTED;
682 }
683
684 // If we got this far, we're routing content to a target frame.
685 // Go fetch the URL.
686
687 GURL complete_url = CompleteURL(url);
688 // Remove when flash bug is fixed. http://crbug.com/40016.
689 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
690 return INVALID_URL;
691
692 if (strcmp(method, "GET") != 0) {
693 // We're only going to route HTTP/HTTPS requests
694 if (!(complete_url.SchemeIs("http") || complete_url.SchemeIs("https")))
695 return INVALID_URL;
696 }
697
698 WebURLRequest request(complete_url);
699 SetReferrer(&request, referrer_flag);
700
701 request.setHTTPMethod(WebString::fromUTF8(method));
702 request.setFirstPartyForCookies(
703 webframe_->document().firstPartyForCookies());
704 request.setHasUserGesture(popups_allowed);
705 if (len > 0) {
706 if (!SetPostData(&request, buf, len)) {
707 // Uhoh - we're in trouble. There isn't a good way
708 // to recover at this point. Break out.
709 NOTREACHED();
710 return ROUTED;
711 }
712 }
713
714 container_->loadFrameRequest(
715 request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
716 return ROUTED;
717 }
718
719 NPObject* WebPluginImpl::GetWindowScriptNPObject() {
720 if (!webframe_) {
721 NOTREACHED();
722 return NULL;
723 }
724 return webframe_->windowObject();
725 }
726
727 NPObject* WebPluginImpl::GetPluginElement() {
728 return container_->scriptableObjectForElement();
729 }
730
731 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) {
732 // Proxy resolving doesn't work in single-process mode.
733 return false;
734 }
735
736 void WebPluginImpl::SetCookie(const GURL& url,
737 const GURL& first_party_for_cookies,
738 const std::string& cookie) {
739 if (!page_delegate_.get())
740 return;
741
742 WebCookieJar* cookie_jar = page_delegate_->GetCookieJar();
743 if (!cookie_jar) {
744 DLOG(WARNING) << "No cookie jar!";
745 return;
746 }
747
748 cookie_jar->setCookie(
749 url, first_party_for_cookies, WebString::fromUTF8(cookie));
750 }
751
752 std::string WebPluginImpl::GetCookies(const GURL& url,
753 const GURL& first_party_for_cookies) {
754 if (!page_delegate_.get())
755 return std::string();
756
757 WebCookieJar* cookie_jar = page_delegate_->GetCookieJar();
758 if (!cookie_jar) {
759 DLOG(WARNING) << "No cookie jar!";
760 return std::string();
761 }
762
763 return UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies));
764 }
765
766 void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
767 for (size_t i = 0; i < clients_.size(); ++i) {
768 if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
769 if (clients_[i].loader.get()) {
770 if (allow) {
771 clients_[i].loader->setDefersLoading(false);
772 } else {
773 clients_[i].loader->cancel();
774 if (clients_[i].client)
775 clients_[i].client->DidFail(clients_[i].id);
776 }
777 }
778 break;
779 }
780 }
781 }
782
783 #if defined(OS_MACOSX)
784 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
785 gfx::GpuPreference gpu_preference) {
786 return NULL;
787 }
788
789 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
790 }
791
792 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width,
793 int32 height,
794 uint32 surface_id) {
795 next_io_surface_allocated_ = true;
796 next_io_surface_width_ = width;
797 next_io_surface_height_ = height;
798 next_io_surface_id_ = surface_id;
799 }
800
801 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
802 if (!container_)
803 return;
804 // Deferring the call to setBackingIOSurfaceId is an attempt to
805 // work around garbage occasionally showing up in the plugin's
806 // area during live resizing of Core Animation plugins. The
807 // assumption was that by the time this was called, the plugin
808 // process would have populated the newly allocated IOSurface. It
809 // is not 100% clear at this point why any garbage is getting
810 // through. More investigation is needed. http://crbug.com/105346
811 if (next_io_surface_allocated_) {
812 if (next_io_surface_id_) {
813 if (!io_surface_layer_.get()) {
814 io_surface_layer_ = cc::IOSurfaceLayer::Create();
815 web_layer_.reset(new webkit::WebLayerImpl(io_surface_layer_));
816 container_->setWebLayer(web_layer_.get());
817 }
818 io_surface_layer_->SetIOSurfaceProperties(
819 next_io_surface_id_,
820 gfx::Size(next_io_surface_width_, next_io_surface_height_));
821 } else {
822 container_->setWebLayer(NULL);
823 web_layer_.reset();
824 io_surface_layer_ = NULL;
825 }
826 next_io_surface_allocated_ = false;
827 } else {
828 if (io_surface_layer_.get())
829 io_surface_layer_->SetNeedsDisplay();
830 }
831 }
832 #endif
833
834 void WebPluginImpl::Invalidate() {
835 if (container_)
836 container_->invalidate();
837 }
838
839 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
840 if (container_)
841 container_->invalidateRect(rect);
842 }
843
844 void WebPluginImpl::OnDownloadPluginSrcUrl() {
845 HandleURLRequestInternal(
846 plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
847 false, true);
848 }
849
850 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
851 WebURLLoader* loader) {
852 ClientInfo* client_info = GetClientInfoFromLoader(loader);
853 if (client_info)
854 return client_info->client;
855 return NULL;
856 }
857
858 WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
859 WebURLLoader* loader) {
860 for (size_t i = 0; i < clients_.size(); ++i) {
861 if (clients_[i].loader.get() == loader)
862 return &clients_[i];
863 }
864
865 NOTREACHED();
866 return 0;
867 }
868
869 void WebPluginImpl::willSendRequest(WebURLLoader* loader,
870 WebURLRequest& request,
871 const WebURLResponse& response) {
872 WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
873 if (client_info) {
874 // Currently this check is just to catch an https -> http redirect when
875 // loading the main plugin src URL. Longer term, we could investigate
876 // firing mixed diplay or scripting issues for subresource loads
877 // initiated by plug-ins.
878 if (client_info->is_plugin_src_load &&
879 webframe_ &&
880 !webframe_->checkIfRunInsecureContent(request.url())) {
881 loader->cancel();
882 client_info->client->DidFail(client_info->id);
883 return;
884 }
885 if (net::HttpResponseHeaders::IsRedirectResponseCode(
886 response.httpStatusCode())) {
887 // If the plugin does not participate in url redirect notifications then
888 // just block cross origin 307 POST redirects.
889 if (!client_info->notify_redirects) {
890 if (response.httpStatusCode() == 307 &&
891 LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
892 GURL original_request_url(response.url());
893 GURL response_url(request.url());
894 if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
895 loader->setDefersLoading(true);
896 loader->cancel();
897 client_info->client->DidFail(client_info->id);
898 return;
899 }
900 }
901 } else {
902 loader->setDefersLoading(true);
903 }
904 }
905 client_info->client->WillSendRequest(request.url(),
906 response.httpStatusCode());
907 }
908 }
909
910 void WebPluginImpl::didSendData(WebURLLoader* loader,
911 unsigned long long bytes_sent,
912 unsigned long long total_bytes_to_be_sent) {
913 }
914
915 void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
916 const WebURLResponse& response) {
917 static const int kHttpPartialResponseStatusCode = 206;
918 static const int kHttpResponseSuccessStatusCode = 200;
919
920 WebPluginResourceClient* client = GetClientFromLoader(loader);
921 if (!client)
922 return;
923
924 ResponseInfo response_info;
925 GetResponseInfo(response, &response_info);
926 ClientInfo* client_info = GetClientInfoFromLoader(loader);
927 if (!client_info)
928 return;
929
930 bool request_is_seekable = true;
931 if (client->IsMultiByteResponseExpected()) {
932 if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
933 ClientInfo* client_info = GetClientInfoFromLoader(loader);
934 if (!client_info)
935 return;
936 if (HandleHttpMultipartResponse(response, client)) {
937 // Multiple ranges requested, data will be delivered by
938 // MultipartResponseDelegate.
939 client_info->data_offset = 0;
940 return;
941 }
942 int64 upper_bound = 0, instance_size = 0;
943 // Single range requested - go through original processing for
944 // non-multipart requests, but update data offset.
945 MultipartResponseDelegate::ReadContentRanges(response,
946 &client_info->data_offset,
947 &upper_bound,
948 &instance_size);
949 } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
950 // If the client issued a byte range request and the server responds with
951 // HTTP 200 OK, it indicates that the server does not support byte range
952 // requests.
953 // We need to emulate Firefox behavior by doing the following:-
954 // 1. Destroy the plugin instance in the plugin process. Ensure that
955 // existing resource requests initiated for the plugin instance
956 // continue to remain valid.
957 // 2. Create a new plugin instance and notify it about the response
958 // received here.
959 if (!ReinitializePluginForResponse(loader)) {
960 NOTREACHED();
961 return;
962 }
963
964 // The server does not support byte range requests. No point in creating
965 // seekable streams.
966 request_is_seekable = false;
967
968 delete client;
969 client = NULL;
970
971 // Create a new resource client for this request.
972 for (size_t i = 0; i < clients_.size(); ++i) {
973 if (clients_[i].loader.get() == loader) {
974 WebPluginResourceClient* resource_client =
975 delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
976 clients_[i].client = resource_client;
977 client = resource_client;
978 break;
979 }
980 }
981
982 DCHECK(client != NULL);
983 }
984 }
985
986 // Calling into a plugin could result in reentrancy if the plugin yields
987 // control to the OS like entering a modal loop etc. Prevent this by
988 // stopping further loading until the plugin notifies us that it is ready to
989 // accept data
990 loader->setDefersLoading(true);
991
992 client->DidReceiveResponse(
993 response_info.mime_type,
994 GetAllHeaders(response),
995 response_info.expected_length,
996 response_info.last_modified,
997 request_is_seekable);
998
999 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1000 // error codes in the stream header and as a result, was unaware of the
1001 // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1002 // destroy the stream and invoke the NPP_DestroyStream function on the
1003 // plugin if the HTTP request fails.
1004 const GURL& url = response.url();
1005 if (url.SchemeIs("http") || url.SchemeIs("https")) {
1006 if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
1007 // The plugin instance could be in the process of deletion here.
1008 // Verify if the WebPluginResourceClient instance still exists before
1009 // use.
1010 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1011 if (client_info) {
1012 client_info->pending_failure_notification = true;
1013 }
1014 }
1015 }
1016 }
1017
1018 void WebPluginImpl::didReceiveData(WebURLLoader* loader,
1019 const char *buffer,
1020 int data_length,
1021 int encoded_data_length) {
1022 WebPluginResourceClient* client = GetClientFromLoader(loader);
1023 if (!client)
1024 return;
1025
1026 MultiPartResponseHandlerMap::iterator index =
1027 multi_part_response_map_.find(client);
1028 if (index != multi_part_response_map_.end()) {
1029 MultipartResponseDelegate* multi_part_handler = (*index).second;
1030 DCHECK(multi_part_handler != NULL);
1031 multi_part_handler->OnReceivedData(buffer,
1032 data_length,
1033 encoded_data_length);
1034 } else {
1035 loader->setDefersLoading(true);
1036 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1037 client->DidReceiveData(buffer, data_length, client_info->data_offset);
1038 client_info->data_offset += data_length;
1039 }
1040 }
1041
1042 void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
1043 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1044 if (client_info && client_info->client) {
1045 MultiPartResponseHandlerMap::iterator index =
1046 multi_part_response_map_.find(client_info->client);
1047 if (index != multi_part_response_map_.end()) {
1048 delete (*index).second;
1049 multi_part_response_map_.erase(index);
1050 if (page_delegate_.get())
1051 page_delegate_->DidStopLoadingForPlugin();
1052 }
1053 loader->setDefersLoading(true);
1054 WebPluginResourceClient* resource_client = client_info->client;
1055 // The ClientInfo can get deleted in the call to DidFinishLoading below.
1056 // It is not safe to access this structure after that.
1057 client_info->client = NULL;
1058 resource_client->DidFinishLoading(client_info->id);
1059 }
1060 }
1061
1062 void WebPluginImpl::didFail(WebURLLoader* loader,
1063 const WebURLError& error) {
1064 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1065 if (client_info && client_info->client) {
1066 loader->setDefersLoading(true);
1067 WebPluginResourceClient* resource_client = client_info->client;
1068 // The ClientInfo can get deleted in the call to DidFail below.
1069 // It is not safe to access this structure after that.
1070 client_info->client = NULL;
1071 resource_client->DidFail(client_info->id);
1072 }
1073 }
1074
1075 void WebPluginImpl::RemoveClient(size_t i) {
1076 clients_.erase(clients_.begin() + i);
1077 }
1078
1079 void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
1080 for (size_t i = 0; i < clients_.size(); ++i) {
1081 if (clients_[i].loader.get() == loader) {
1082 RemoveClient(i);
1083 return;
1084 }
1085 }
1086 }
1087
1088 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
1089 if (!container)
1090 TearDownPluginInstance(NULL);
1091 container_ = container;
1092 if (container_)
1093 container_->allowScriptObjects();
1094 }
1095
1096 void WebPluginImpl::HandleURLRequest(const char* url,
1097 const char* method,
1098 const char* target,
1099 const char* buf,
1100 unsigned int len,
1101 int notify_id,
1102 bool popups_allowed,
1103 bool notify_redirects) {
1104 // GetURL/PostURL requests initiated explicitly by plugins should specify the
1105 // plugin SRC url as the referrer if it is available.
1106 HandleURLRequestInternal(
1107 url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
1108 notify_redirects, false);
1109 }
1110
1111 void WebPluginImpl::HandleURLRequestInternal(const char* url,
1112 const char* method,
1113 const char* target,
1114 const char* buf,
1115 unsigned int len,
1116 int notify_id,
1117 bool popups_allowed,
1118 Referrer referrer_flag,
1119 bool notify_redirects,
1120 bool is_plugin_src_load) {
1121 // For this request, we either route the output to a frame
1122 // because a target has been specified, or we handle the request
1123 // here, i.e. by executing the script if it is a javascript url
1124 // or by initiating a download on the URL, etc. There is one special
1125 // case in that the request is a javascript url and the target is "_self",
1126 // in which case we route the output to the plugin rather than routing it
1127 // to the plugin's frame.
1128 bool is_javascript_url = url_util::FindAndCompareScheme(
1129 url, strlen(url), "javascript", NULL);
1130 RoutingStatus routing_status = RouteToFrame(
1131 url, is_javascript_url, popups_allowed, method, target, buf, len,
1132 notify_id, referrer_flag);
1133 if (routing_status == ROUTED)
1134 return;
1135
1136 if (is_javascript_url) {
1137 GURL gurl(url);
1138 WebString result = container_->executeScriptURL(gurl, popups_allowed);
1139
1140 // delegate_ could be NULL because executeScript caused the container to
1141 // be deleted.
1142 if (delegate_) {
1143 delegate_->SendJavaScriptStream(
1144 gurl, result.utf8(), !result.isNull(), notify_id);
1145 }
1146
1147 return;
1148 }
1149
1150 unsigned long resource_id = GetNextResourceId();
1151 if (!resource_id)
1152 return;
1153
1154 GURL complete_url = CompleteURL(url);
1155 // Remove when flash bug is fixed. http://crbug.com/40016.
1156 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
1157 return;
1158
1159 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1160 resource_id, complete_url, notify_id);
1161 if (!resource_client)
1162 return;
1163
1164 // If the RouteToFrame call returned a failure then inform the result
1165 // back to the plugin asynchronously.
1166 if ((routing_status == INVALID_URL) ||
1167 (routing_status == GENERAL_FAILURE)) {
1168 resource_client->DidFail(resource_id);
1169 return;
1170 }
1171
1172 // CreateResourceClient() sends a synchronous IPC message so it's possible
1173 // that TearDownPluginInstance() may have been called in the nested
1174 // message loop. If so, don't start the request.
1175 if (!delegate_)
1176 return;
1177
1178 InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
1179 len, NULL, referrer_flag, notify_redirects,
1180 is_plugin_src_load);
1181 }
1182
1183 unsigned long WebPluginImpl::GetNextResourceId() {
1184 if (!webframe_)
1185 return 0;
1186 WebView* view = webframe_->view();
1187 if (!view)
1188 return 0;
1189 return view->createUniqueIdentifierForRequest();
1190 }
1191
1192 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
1193 WebPluginResourceClient* client,
1194 const GURL& url,
1195 const char* method,
1196 const char* buf,
1197 int buf_len,
1198 const char* range_info,
1199 Referrer referrer_flag,
1200 bool notify_redirects,
1201 bool is_plugin_src_load) {
1202 if (!client) {
1203 NOTREACHED();
1204 return false;
1205 }
1206
1207 ClientInfo info;
1208 info.id = resource_id;
1209 info.client = client;
1210 info.request.initialize();
1211 info.request.setURL(url);
1212 info.request.setFirstPartyForCookies(
1213 webframe_->document().firstPartyForCookies());
1214 info.request.setRequestorProcessID(delegate_->GetProcessId());
1215 info.request.setTargetType(WebURLRequest::TargetIsObject);
1216 info.request.setHTTPMethod(WebString::fromUTF8(method));
1217 info.pending_failure_notification = false;
1218 info.notify_redirects = notify_redirects;
1219 info.is_plugin_src_load = is_plugin_src_load;
1220 info.data_offset = 0;
1221
1222 if (range_info) {
1223 info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
1224 WebString::fromUTF8(range_info));
1225 }
1226
1227 if (strcmp(method, "POST") == 0) {
1228 // Adds headers or form data to a request. This must be called before
1229 // we initiate the actual request.
1230 SetPostData(&info.request, buf, buf_len);
1231 }
1232
1233 SetReferrer(&info.request, referrer_flag);
1234
1235 WebURLLoaderOptions options;
1236 options.allowCredentials = true;
1237 options.crossOriginRequestPolicy =
1238 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
1239 info.loader.reset(webframe_->createAssociatedURLLoader(options));
1240 if (!info.loader.get())
1241 return false;
1242 info.loader->loadAsynchronously(info.request, this);
1243
1244 clients_.push_back(info);
1245 return true;
1246 }
1247
1248 void WebPluginImpl::CancelDocumentLoad() {
1249 if (webframe_) {
1250 ignore_response_error_ = true;
1251 webframe_->stopLoading();
1252 }
1253 }
1254
1255 void WebPluginImpl::InitiateHTTPRangeRequest(
1256 const char* url, const char* range_info, int range_request_id) {
1257 unsigned long resource_id = GetNextResourceId();
1258 if (!resource_id)
1259 return;
1260
1261 GURL complete_url = CompleteURL(url);
1262 // Remove when flash bug is fixed. http://crbug.com/40016.
1263 if (!WebPluginImpl::IsValidUrl(complete_url,
1264 load_manually_ ? NO_REFERRER : PLUGIN_SRC))
1265 return;
1266
1267 WebPluginResourceClient* resource_client =
1268 delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
1269 InitiateHTTPRequest(
1270 resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
1271 load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
1272 }
1273
1274 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
1275 bool defer) {
1276 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1277 while (client_index != clients_.end()) {
1278 ClientInfo& client_info = *client_index;
1279
1280 if (client_info.id == resource_id) {
1281 client_info.loader->setDefersLoading(defer);
1282
1283 // If we determined that the request had failed via the HTTP headers
1284 // in the response then we send out a failure notification to the
1285 // plugin process, as certain plugins don't handle HTTP failure codes
1286 // correctly.
1287 if (!defer && client_info.client &&
1288 client_info.pending_failure_notification) {
1289 // The ClientInfo and the iterator can become invalid due to the call
1290 // to DidFail below.
1291 WebPluginResourceClient* resource_client = client_info.client;
1292 client_info.loader->cancel();
1293 clients_.erase(client_index++);
1294 resource_client->DidFail(resource_id);
1295 }
1296 break;
1297 }
1298 client_index++;
1299 }
1300 }
1301
1302 bool WebPluginImpl::IsOffTheRecord() {
1303 return false;
1304 }
1305
1306 bool WebPluginImpl::HandleHttpMultipartResponse(
1307 const WebURLResponse& response, WebPluginResourceClient* client) {
1308 std::string multipart_boundary;
1309 if (!MultipartResponseDelegate::ReadMultipartBoundary(
1310 response, &multipart_boundary)) {
1311 return false;
1312 }
1313
1314 if (page_delegate_.get())
1315 page_delegate_->DidStartLoadingForPlugin();
1316
1317 MultiPartResponseClient* multi_part_response_client =
1318 new MultiPartResponseClient(client);
1319
1320 MultipartResponseDelegate* multi_part_response_handler =
1321 new MultipartResponseDelegate(multi_part_response_client, NULL,
1322 response,
1323 multipart_boundary);
1324 multi_part_response_map_[client] = multi_part_response_handler;
1325 return true;
1326 }
1327
1328 bool WebPluginImpl::ReinitializePluginForResponse(
1329 WebURLLoader* loader) {
1330 WebFrame* webframe = webframe_;
1331 if (!webframe)
1332 return false;
1333
1334 WebView* webview = webframe->view();
1335 if (!webview)
1336 return false;
1337
1338 WebPluginContainer* container_widget = container_;
1339
1340 // Destroy the current plugin instance.
1341 TearDownPluginInstance(loader);
1342
1343 container_ = container_widget;
1344 webframe_ = webframe;
1345
1346 WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate(
1347 file_path_, mime_type_);
1348
1349 // Store the plugin's unique identifier, used by the container to track its
1350 // script objects, and enable script objects (since Initialize may use them
1351 // even if it fails).
1352 npp_ = plugin_delegate->GetPluginNPP();
1353 container_->allowScriptObjects();
1354
1355 bool ok = plugin_delegate && plugin_delegate->Initialize(
1356 plugin_url_, arg_names_, arg_values_, this, load_manually_);
1357
1358 if (!ok) {
1359 container_->clearScriptObjects();
1360 container_ = NULL;
1361 // TODO(iyengar) Should we delete the current plugin instance here?
1362 return false;
1363 }
1364
1365 delegate_ = plugin_delegate;
1366
1367 // Force a geometry update to occur to ensure that the plugin becomes
1368 // visible.
1369 container_->reportGeometry();
1370
1371 // The plugin move sequences accumulated via DidMove are sent to the browser
1372 // whenever the renderer paints. Force a paint here to ensure that changes
1373 // to the plugin window are propagated to the browser.
1374 container_->invalidate();
1375 return true;
1376 }
1377
1378 void WebPluginImpl::TearDownPluginInstance(
1379 WebURLLoader* loader_to_ignore) {
1380 // JavaScript garbage collection may cause plugin script object references to
1381 // be retained long after the plugin is destroyed. Some plugins won't cope
1382 // with their objects being released after they've been destroyed, and once
1383 // we've actually unloaded the plugin the object's releaseobject() code may
1384 // no longer be in memory. The container tracks the plugin's objects and lets
1385 // us invalidate them, releasing the references to them held by the JavaScript
1386 // runtime.
1387 if (container_) {
1388 container_->clearScriptObjects();
1389 container_->setWebLayer(NULL);
1390 }
1391
1392 // Call PluginDestroyed() first to prevent the plugin from calling us back
1393 // in the middle of tearing down the render tree.
1394 if (delegate_) {
1395 // The plugin may call into the browser and pass script objects even during
1396 // teardown, so temporarily re-enable plugin script objects.
1397 DCHECK(container_);
1398 container_->allowScriptObjects();
1399
1400 delegate_->PluginDestroyed();
1401 delegate_ = NULL;
1402
1403 // Invalidate any script objects created during teardown here, before the
1404 // plugin might actually be unloaded.
1405 container_->clearScriptObjects();
1406 }
1407
1408 // Cancel any pending requests because otherwise this deleted object will
1409 // be called by the ResourceDispatcher.
1410 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1411 while (client_index != clients_.end()) {
1412 ClientInfo& client_info = *client_index;
1413
1414 if (loader_to_ignore == client_info.loader) {
1415 client_index++;
1416 continue;
1417 }
1418
1419 if (client_info.loader.get())
1420 client_info.loader->cancel();
1421
1422 client_index = clients_.erase(client_index);
1423 }
1424
1425 // This needs to be called now and not in the destructor since the
1426 // webframe_ might not be valid anymore.
1427 webframe_ = NULL;
1428 weak_factory_.InvalidateWeakPtrs();
1429 }
1430
1431 void WebPluginImpl::SetReferrer(WebKit::WebURLRequest* request,
1432 Referrer referrer_flag) {
1433 switch (referrer_flag) {
1434 case DOCUMENT_URL:
1435 webframe_->setReferrerForRequest(*request, GURL());
1436 break;
1437
1438 case PLUGIN_SRC:
1439 webframe_->setReferrerForRequest(*request, plugin_url_);
1440 break;
1441
1442 default:
1443 break;
1444 }
1445 }
1446
1447 } // namespace npapi
1448 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698