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