Re-enable blink_perf.canvas on Windows
[chromium-blink-merge.git] / content / renderer / npapi / webplugin_impl.cc
blob558cd47c58b9a3e7089581ec1214205a377df39a
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/npapi/webplugin_impl.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/debug/crash_logging.h"
10 #include "base/logging.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/user_metrics_action.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "cc/blink/web_layer_impl.h"
18 #include "cc/layers/io_surface_layer.h"
19 #include "content/child/appcache/web_application_cache_host_impl.h"
20 #include "content/child/multipart_response_delegate.h"
21 #include "content/child/npapi/plugin_host.h"
22 #include "content/child/npapi/plugin_instance.h"
23 #include "content/child/npapi/webplugin_delegate_impl.h"
24 #include "content/child/npapi/webplugin_resource_client.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/renderer/content_renderer_client.h"
29 #include "content/renderer/npapi/webplugin_delegate_proxy.h"
30 #include "content/renderer/render_frame_impl.h"
31 #include "content/renderer/render_process.h"
32 #include "content/renderer/render_thread_impl.h"
33 #include "content/renderer/render_view_impl.h"
34 #include "net/base/escape.h"
35 #include "net/base/net_errors.h"
36 #include "net/http/http_response_headers.h"
37 #include "skia/ext/platform_canvas.h"
38 #include "third_party/WebKit/public/platform/WebCString.h"
39 #include "third_party/WebKit/public/platform/WebCookieJar.h"
40 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
41 #include "third_party/WebKit/public/platform/WebData.h"
42 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
43 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
44 #include "third_party/WebKit/public/platform/WebURL.h"
45 #include "third_party/WebKit/public/platform/WebURLError.h"
46 #include "third_party/WebKit/public/platform/WebURLLoader.h"
47 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
48 #include "third_party/WebKit/public/platform/WebURLResponse.h"
49 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
50 #include "third_party/WebKit/public/web/WebDocument.h"
51 #include "third_party/WebKit/public/web/WebFrame.h"
52 #include "third_party/WebKit/public/web/WebInputEvent.h"
53 #include "third_party/WebKit/public/web/WebKit.h"
54 #include "third_party/WebKit/public/web/WebPluginContainer.h"
55 #include "third_party/WebKit/public/web/WebPluginParams.h"
56 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
57 #include "third_party/WebKit/public/web/WebView.h"
58 #include "ui/gfx/geometry/rect.h"
59 #include "url/gurl.h"
60 #include "url/url_util.h"
62 using blink::WebCString;
63 using blink::WebCanvas;
64 using blink::WebConsoleMessage;
65 using blink::WebCookieJar;
66 using blink::WebCursorInfo;
67 using blink::WebData;
68 using blink::WebDataSource;
69 using blink::WebFrame;
70 using blink::WebHTTPBody;
71 using blink::WebHTTPHeaderVisitor;
72 using blink::WebInputEvent;
73 using blink::WebKeyboardEvent;
74 using blink::WebMouseEvent;
75 using blink::WebPluginContainer;
76 using blink::WebPluginParams;
77 using blink::WebRect;
78 using blink::WebString;
79 using blink::WebURL;
80 using blink::WebURLError;
81 using blink::WebURLLoader;
82 using blink::WebURLLoaderClient;
83 using blink::WebURLLoaderOptions;
84 using blink::WebURLRequest;
85 using blink::WebURLResponse;
86 using blink::WebVector;
87 using blink::WebView;
89 namespace content {
91 namespace {
93 // This class handles individual multipart responses. It is instantiated when
94 // we receive HTTP status code 206 in the HTTP response. This indicates
95 // that the response could have multiple parts each separated by a boundary
96 // specified in the response header.
97 class MultiPartResponseClient : public WebURLLoaderClient {
98 public:
99 explicit MultiPartResponseClient(WebPluginResourceClient* resource_client)
100 : byte_range_lower_bound_(0), resource_client_(resource_client) {}
102 virtual void willSendRequest(
103 WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
104 virtual void didSendData(
105 WebURLLoader*, unsigned long long, unsigned long long) {}
107 // Called when the multipart parser encounters an embedded multipart
108 // response.
109 virtual void didReceiveResponse(
110 WebURLLoader*, const WebURLResponse& response) {
111 int64 byte_range_upper_bound, instance_size;
112 if (!MultipartResponseDelegate::ReadContentRanges(
113 response,
114 &byte_range_lower_bound_,
115 &byte_range_upper_bound,
116 &instance_size)) {
117 NOTREACHED();
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;
134 virtual void didFinishLoading(WebURLLoader*,
135 double finishTime,
136 int64_t total_encoded_data_length) {}
137 virtual void didFail(WebURLLoader*, const WebURLError&) {}
139 private:
140 // The lower bound of the byte range.
141 int64 byte_range_lower_bound_;
142 // The handler for the data.
143 WebPluginResourceClient* resource_client_;
146 class HeaderFlattener : public WebHTTPHeaderVisitor {
147 public:
148 explicit HeaderFlattener(std::string* buf) : buf_(buf) {
151 virtual void visitHeader(const WebString& name, const WebString& value) {
152 // TODO(darin): Should we really exclude headers with an empty value?
153 if (!name.isEmpty() && !value.isEmpty()) {
154 buf_->append(name.utf8());
155 buf_->append(": ");
156 buf_->append(value.utf8());
157 buf_->append("\n");
161 private:
162 std::string* buf_;
165 std::string GetAllHeaders(const WebURLResponse& response) {
166 // TODO(darin): It is possible for httpStatusText to be empty and still have
167 // an interesting response, so this check seems wrong.
168 std::string result;
169 const WebString& status = response.httpStatusText();
170 if (status.isEmpty())
171 return result;
173 // TODO(darin): Shouldn't we also report HTTP version numbers?
174 result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
175 result.append(status.utf8());
176 result.append("\n");
178 HeaderFlattener flattener(&result);
179 response.visitHTTPHeaderFields(&flattener);
181 return result;
184 struct ResponseInfo {
185 GURL url;
186 std::string mime_type;
187 uint32 last_modified;
188 uint32 expected_length;
191 void GetResponseInfo(const WebURLResponse& response,
192 ResponseInfo* response_info) {
193 response_info->url = response.url();
194 response_info->mime_type = response.mimeType().utf8();
196 // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
197 response_info->last_modified =
198 static_cast<uint32>(response.lastModifiedDate());
200 // If the length comes in as -1, then it indicates that it was not
201 // read off the HTTP headers. We replicate Safari webkit behavior here,
202 // which is to set it to 0.
203 response_info->expected_length =
204 static_cast<uint32>(std::max(response.expectedContentLength(), 0LL));
206 WebString content_encoding =
207 response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
208 if (!content_encoding.isNull() &&
209 !EqualsASCII(content_encoding, "identity")) {
210 // Don't send the compressed content length to the plugin, which only
211 // cares about the decoded length.
212 response_info->expected_length = 0;
216 } // namespace
218 // blink::WebPlugin ----------------------------------------------------------
220 struct WebPluginImpl::ClientInfo {
221 unsigned long id;
222 WebPluginResourceClient* client;
223 blink::WebURLRequest request;
224 bool pending_failure_notification;
225 linked_ptr<blink::WebURLLoader> loader;
226 bool notify_redirects;
227 bool is_plugin_src_load;
228 int64 data_offset;
231 bool WebPluginImpl::initialize(WebPluginContainer* container) {
232 if (!render_view_.get()) {
233 LOG(ERROR) << "No RenderView";
234 return false;
237 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
238 this, mime_type_, render_view_, render_frame_);
240 // Store the plugin's unique identifier, used by the container to track its
241 // script objects.
242 npp_ = plugin_delegate->GetPluginNPP();
244 // Set the container before Initialize because the plugin may
245 // synchronously call NPN_GetValue to get its container, or make calls
246 // passing script objects that need to be tracked, during initialization.
247 SetContainer(container);
249 bool ok = plugin_delegate->Initialize(
250 plugin_url_, arg_names_, arg_values_, load_manually_);
251 if (!ok) {
252 plugin_delegate->PluginDestroyed();
254 blink::WebPlugin* replacement_plugin =
255 GetContentClient()->renderer()->CreatePluginReplacement(
256 render_frame_, file_path_);
257 if (!replacement_plugin)
258 return false;
260 // Disable scripting by this plugin before replacing it with the new
261 // one. This plugin also needs destroying, so use destroy(), which will
262 // implicitly disable scripting while un-setting the container.
263 destroy();
265 // Inform the container of the replacement plugin, then initialize it.
266 container->setPlugin(replacement_plugin);
267 return replacement_plugin->initialize(container);
270 delegate_ = plugin_delegate;
272 return true;
275 void WebPluginImpl::destroy() {
276 SetContainer(NULL);
277 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
280 NPObject* WebPluginImpl::scriptableObject() {
281 if (!delegate_)
282 return NULL;
284 return delegate_->GetPluginScriptableObject();
287 NPP WebPluginImpl::pluginNPP() {
288 return npp_;
291 bool WebPluginImpl::getFormValue(blink::WebString& value) {
292 if (!delegate_)
293 return false;
294 base::string16 form_value;
295 if (!delegate_->GetFormValue(&form_value))
296 return false;
297 value = form_value;
298 return true;
301 void WebPluginImpl::layoutIfNeeded() {
302 if (!container_)
303 return;
305 #if defined(OS_WIN)
306 // Force a geometry update if needed to allow plugins like media player
307 // which defer the initial geometry update to work. Do it now, rather
308 // than in paint, so that the paint rect invalidation is registered.
309 // Otherwise we may never get the paint call.
310 container_->reportGeometry();
311 #endif // OS_WIN
314 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
315 if (!delegate_ || !container_)
316 return;
318 // Note that |canvas| is only used when in windowless mode.
319 delegate_->Paint(canvas, paint_rect);
322 void WebPluginImpl::updateGeometry(const WebRect& window_rect,
323 const WebRect& clip_rect,
324 const WebRect& unobscured_rect,
325 const WebVector<WebRect>& cut_outs_rects,
326 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 < cut_outs_rects.size(); ++i)
334 new_geometry.cutout_rects.push_back(cut_outs_rects[i]);
336 // Only send DidMovePlugin if the geometry changed in some way.
337 if (window_ && (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
338 render_frame_->GetRenderWidget()->SchedulePluginMove(new_geometry);
339 // We invalidate windowed plugins during the first geometry update to
340 // ensure that they get reparented to the wrapper window in the browser.
341 // This ensures that they become visible and are painted by the OS. This is
342 // required as some pages don't invalidate when the plugin is added.
343 if (first_geometry_update_ && window_) {
344 InvalidateRect(window_rect);
348 // Only UpdateGeometry if either the window or clip rects have changed.
349 if (delegate_ && (first_geometry_update_ ||
350 new_geometry.window_rect != geometry_.window_rect ||
351 new_geometry.clip_rect != geometry_.clip_rect)) {
352 // Notify the plugin that its parameters have changed.
353 delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
356 // Initiate a download on the plugin url. This should be done for the
357 // first update geometry sequence. We need to ensure that the plugin
358 // receives the geometry update before it starts receiving data.
359 if (first_geometry_update_) {
360 // An empty url corresponds to an EMBED tag with no src attribute.
361 if (!load_manually_ && plugin_url_.is_valid()) {
362 // The Flash plugin hangs for a while if it receives data before
363 // receiving valid plugin geometry. By valid geometry we mean the
364 // geometry received by a call to setFrameRect in the Webkit
365 // layout code path. To workaround this issue we download the
366 // plugin source url on a timer.
367 base::MessageLoop::current()->PostTask(
368 FROM_HERE,
369 base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl,
370 weak_factory_.GetWeakPtr()));
374 #if defined(OS_WIN)
375 // Don't cache the geometry during the first geometry update. The first
376 // geometry update sequence is received when Widget::setParent is called.
377 // For plugins like media player which have a bug where they only honor
378 // the first geometry update, we have a quirk which ignores the first
379 // geometry update. To ensure that these plugins work correctly in cases
380 // where we receive only one geometry update from webkit, we also force
381 // a geometry update during paint which should go out correctly as the
382 // initial geometry update was not cached.
383 if (!first_geometry_update_)
384 geometry_ = new_geometry;
385 #else // OS_WIN
386 geometry_ = new_geometry;
387 #endif // OS_WIN
388 first_geometry_update_ = false;
391 void WebPluginImpl::updateFocus(bool focused, blink::WebFocusType focus_type) {
392 if (accepts_input_events_)
393 delegate_->SetFocus(focused);
396 void WebPluginImpl::updateVisibility(bool visible) {
397 if (!window_)
398 return;
400 WebPluginGeometry move;
401 move.window = window_;
402 move.window_rect = gfx::Rect();
403 move.clip_rect = gfx::Rect();
404 move.rects_valid = false;
405 move.visible = visible;
407 render_frame_->GetRenderWidget()->SchedulePluginMove(move);
410 bool WebPluginImpl::acceptsInputEvents() {
411 return accepts_input_events_;
414 bool WebPluginImpl::handleInputEvent(
415 const WebInputEvent& event, WebCursorInfo& cursor_info) {
416 // Swallow context menu events in order to suppress the default context menu.
417 if (event.type == WebInputEvent::ContextMenu)
418 return true;
420 WebCursor::CursorInfo web_cursor_info;
421 bool ret = delegate_->HandleInputEvent(event, &web_cursor_info);
422 cursor_info.type = web_cursor_info.type;
423 cursor_info.hotSpot = web_cursor_info.hotspot;
424 cursor_info.customImage = web_cursor_info.custom_image;
425 cursor_info.imageScaleFactor = web_cursor_info.image_scale_factor;
426 #if defined(OS_WIN)
427 cursor_info.externalHandle = web_cursor_info.external_handle;
428 #endif
429 return ret;
432 void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
433 ignore_response_error_ = false;
435 ResponseInfo response_info;
436 GetResponseInfo(response, &response_info);
438 delegate_->DidReceiveManualResponse(
439 response_info.url,
440 response_info.mime_type,
441 GetAllHeaders(response),
442 response_info.expected_length,
443 response_info.last_modified);
446 void WebPluginImpl::didReceiveData(const char* data, int data_length) {
447 delegate_->DidReceiveManualData(data, data_length);
450 void WebPluginImpl::didFinishLoading() {
451 delegate_->DidFinishManualLoading();
454 void WebPluginImpl::didFailLoading(const WebURLError& error) {
455 if (!ignore_response_error_)
456 delegate_->DidManualLoadFail();
459 void WebPluginImpl::didFinishLoadingFrameRequest(
460 const WebURL& url, void* notify_data) {
461 if (delegate_) {
462 // We're converting a void* into an arbitrary int id. Though
463 // these types are the same size on all the platforms we support,
464 // the compiler may complain as though they are different, so to
465 // make the casting gods happy go through an intptr_t (the union
466 // of void* and int) rather than converting straight across.
467 delegate_->DidFinishLoadWithReason(
468 url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data));
472 void WebPluginImpl::didFailLoadingFrameRequest(
473 const WebURL& url, void* notify_data, const WebURLError& error) {
474 if (!delegate_)
475 return;
477 NPReason reason =
478 error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR;
479 // See comment in didFinishLoadingFrameRequest about the cast here.
480 delegate_->DidFinishLoadWithReason(
481 url, reason, reinterpret_cast<intptr_t>(notify_data));
484 bool WebPluginImpl::isPlaceholder() {
485 return false;
488 WebPluginImpl::LoaderClient::LoaderClient(WebPluginImpl* parent)
489 : parent_(parent) {}
491 void WebPluginImpl::LoaderClient::willSendRequest(
492 blink::WebURLLoader* loader, blink::WebURLRequest& newRequest,
493 const blink::WebURLResponse& redirectResponse) {
494 parent_->willSendRequest(loader, newRequest, redirectResponse);
497 void WebPluginImpl::LoaderClient::didSendData(
498 blink::WebURLLoader* loader, unsigned long long bytesSent,
499 unsigned long long totalBytesToBeSent) {
500 parent_->didSendData(loader, bytesSent, totalBytesToBeSent);
503 void WebPluginImpl::LoaderClient::didReceiveResponse(
504 blink::WebURLLoader* loader, const blink::WebURLResponse& response) {
505 parent_->didReceiveResponse(loader, response);
508 void WebPluginImpl::LoaderClient::didDownloadData(
509 blink::WebURLLoader* loader, int dataLength, int encodedDataLength) {
512 void WebPluginImpl::LoaderClient::didReceiveData(
513 blink::WebURLLoader* loader, const char* data,
514 int dataLength, int encodedDataLength) {
515 parent_->didReceiveData(loader, data, dataLength, encodedDataLength);
518 void WebPluginImpl::LoaderClient::didReceiveCachedMetadata(
519 blink::WebURLLoader* loader, const char* data, int dataLength) {
522 void WebPluginImpl::LoaderClient::didFinishLoading(
523 blink::WebURLLoader* loader, double finishTime,
524 int64_t total_encoded_data_length) {
525 parent_->didFinishLoading(loader, finishTime);
528 void WebPluginImpl::LoaderClient::didFail(
529 blink::WebURLLoader* loader, const blink::WebURLError& error) {
530 parent_->didFail(loader, error);
533 // -----------------------------------------------------------------------------
535 WebPluginImpl::WebPluginImpl(
536 WebFrame* webframe,
537 const WebPluginParams& params,
538 const base::FilePath& file_path,
539 const base::WeakPtr<RenderViewImpl>& render_view,
540 RenderFrameImpl* render_frame)
541 : windowless_(false),
542 window_(gfx::kNullPluginWindow),
543 accepts_input_events_(false),
544 render_frame_(render_frame),
545 render_view_(render_view),
546 webframe_(webframe),
547 delegate_(NULL),
548 container_(NULL),
549 npp_(NULL),
550 plugin_url_(params.url),
551 load_manually_(params.loadManually),
552 first_geometry_update_(true),
553 ignore_response_error_(false),
554 file_path_(file_path),
555 mime_type_(base::UTF16ToASCII(params.mimeType)),
556 loader_client_(this),
557 weak_factory_(this) {
558 DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
559 base::StringToLowerASCII(&mime_type_);
561 for (size_t i = 0; i < params.attributeNames.size(); ++i) {
562 arg_names_.push_back(params.attributeNames[i].utf8());
563 arg_values_.push_back(params.attributeValues[i].utf8());
566 // Set subresource URL for crash reporting.
567 base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec());
570 WebPluginImpl::~WebPluginImpl() {
573 void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
574 if (window) {
575 DCHECK(!windowless_);
576 window_ = window;
577 #if defined(OS_MACOSX)
578 // TODO(kbr): remove. http://crbug.com/105344
580 // Lie to ourselves about being windowless even if we got a fake
581 // plugin window handle, so we continue to get input events.
582 windowless_ = true;
583 accepts_input_events_ = true;
584 // We do not really need to notify the page delegate that a plugin
585 // window was created -- so don't.
586 #else
587 accepts_input_events_ = false;
589 #endif // OS_MACOSX
590 } else {
591 DCHECK(!window_); // Make sure not called twice.
592 windowless_ = true;
593 accepts_input_events_ = true;
597 void WebPluginImpl::SetAcceptsInputEvents(bool accepts) {
598 accepts_input_events_ = accepts;
601 void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) {
602 DCHECK_EQ(window, window_);
603 window_ = gfx::kNullPluginWindow;
604 if (render_view_.get())
605 render_frame_->GetRenderWidget()->CleanupWindowInPluginMoves(window);
608 GURL WebPluginImpl::CompleteURL(const char* url) {
609 if (!webframe_) {
610 NOTREACHED();
611 return GURL();
613 // TODO(darin): Is conversion from UTF8 correct here?
614 return webframe_->document().completeURL(WebString::fromUTF8(url));
617 void WebPluginImpl::CancelResource(unsigned long id) {
618 for (size_t i = 0; i < clients_.size(); ++i) {
619 if (clients_[i].id == id) {
620 if (clients_[i].loader.get()) {
621 clients_[i].loader->setDefersLoading(false);
622 clients_[i].loader->cancel();
623 RemoveClient(i);
625 return;
630 bool WebPluginImpl::SetPostData(WebURLRequest* request,
631 const char *buf,
632 uint32 length) {
633 std::vector<std::string> names;
634 std::vector<std::string> values;
635 std::vector<char> body;
636 bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body);
638 for (size_t i = 0; i < names.size(); ++i) {
639 request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
640 WebString::fromUTF8(values[i]));
643 WebString content_type_header = WebString::fromUTF8("Content-Type");
644 const WebString& content_type =
645 request->httpHeaderField(content_type_header);
646 if (content_type.isEmpty()) {
647 request->setHTTPHeaderField(
648 content_type_header,
649 WebString::fromUTF8("application/x-www-form-urlencoded"));
652 WebHTTPBody http_body;
653 if (body.size()) {
654 http_body.initialize();
655 http_body.appendData(WebData(&body[0], body.size()));
657 request->setHTTPBody(http_body);
659 return rv;
662 bool WebPluginImpl::IsValidUrl(const GURL& url, ReferrerValue referrer_flag) {
663 if (referrer_flag == PLUGIN_SRC &&
664 mime_type_ == kFlashPluginSwfMimeType &&
665 url.GetOrigin() != plugin_url_.GetOrigin()) {
666 // Do url check to make sure that there are no @, ;, \ chars in between url
667 // scheme and url path.
668 const char* url_to_check(url.spec().data());
669 url::Parsed parsed;
670 url::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
671 if (parsed.path.begin <= parsed.scheme.end())
672 return true;
673 std::string string_to_search;
674 string_to_search.assign(url_to_check + parsed.scheme.end(),
675 parsed.path.begin - parsed.scheme.end());
676 if (string_to_search.find("@") != std::string::npos ||
677 string_to_search.find(";") != std::string::npos ||
678 string_to_search.find("\\") != std::string::npos)
679 return false;
682 return true;
685 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
686 const char* url,
687 bool is_javascript_url,
688 bool popups_allowed,
689 const char* method,
690 const char* target,
691 const char* buf,
692 unsigned int len,
693 int notify_id,
694 ReferrerValue referrer_flag) {
695 // If there is no target, there is nothing to do
696 if (!target)
697 return NOT_ROUTED;
699 // This could happen if the WebPluginContainer was already deleted.
700 if (!webframe_)
701 return NOT_ROUTED;
703 WebString target_str = WebString::fromUTF8(target);
705 // Take special action for JavaScript URLs
706 if (is_javascript_url) {
707 WebFrame* target_frame =
708 webframe_->view()->findFrameByName(target_str, webframe_);
709 // For security reasons, do not allow JavaScript on frames
710 // other than this frame.
711 if (target_frame != webframe_) {
712 // TODO(darin): Localize this message.
713 const char kMessage[] =
714 "Ignoring cross-frame javascript URL load requested by plugin.";
715 webframe_->addMessageToConsole(
716 WebConsoleMessage(WebConsoleMessage::LevelError,
717 WebString::fromUTF8(kMessage)));
718 return ROUTED;
721 // Route javascript calls back to the plugin.
722 return NOT_ROUTED;
725 // If we got this far, we're routing content to a target frame.
726 // Go fetch the URL.
728 GURL complete_url = CompleteURL(url);
729 // Remove when flash bug is fixed. http://crbug.com/40016.
730 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
731 return INVALID_URL;
733 if (strcmp(method, "GET") != 0) {
734 // We're only going to route HTTP/HTTPS requests
735 if (!complete_url.SchemeIsHTTPOrHTTPS())
736 return INVALID_URL;
739 WebURLRequest request(complete_url);
740 SetReferrer(&request, referrer_flag);
742 request.setHTTPMethod(WebString::fromUTF8(method));
743 request.setFirstPartyForCookies(
744 webframe_->document().firstPartyForCookies());
745 request.setHasUserGesture(popups_allowed);
746 // ServiceWorker is disabled for NPAPI.
747 request.setSkipServiceWorker(true);
748 if (len > 0) {
749 if (!SetPostData(&request, buf, len)) {
750 // Uhoh - we're in trouble. There isn't a good way
751 // to recover at this point. Break out.
752 NOTREACHED();
753 return ROUTED;
757 container_->loadFrameRequest(
758 request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
759 return ROUTED;
762 NPObject* WebPluginImpl::GetWindowScriptNPObject() {
763 if (!webframe_) {
764 NOTREACHED();
765 return NULL;
767 return webframe_->windowObject();
770 NPObject* WebPluginImpl::GetPluginElement() {
771 return container_->scriptableObjectForElement();
774 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) {
775 // Proxy resolving doesn't work in single-process mode.
776 return false;
779 void WebPluginImpl::SetCookie(const GURL& url,
780 const GURL& first_party_for_cookies,
781 const std::string& cookie) {
782 if (!render_view_.get())
783 return;
785 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
786 if (!cookie_jar) {
787 DLOG(WARNING) << "No cookie jar!";
788 return;
791 cookie_jar->setCookie(
792 url, first_party_for_cookies, WebString::fromUTF8(cookie));
795 std::string WebPluginImpl::GetCookies(const GURL& url,
796 const GURL& first_party_for_cookies) {
797 if (!render_view_.get())
798 return std::string();
800 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
801 if (!cookie_jar) {
802 DLOG(WARNING) << "No cookie jar!";
803 return std::string();
806 return base::UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies));
809 void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
810 for (size_t i = 0; i < clients_.size(); ++i) {
811 if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
812 if (clients_[i].loader.get()) {
813 if (allow) {
814 clients_[i].loader->setDefersLoading(false);
815 } else {
816 clients_[i].loader->cancel();
817 if (clients_[i].client)
818 clients_[i].client->DidFail(clients_[i].id);
821 break;
826 bool WebPluginImpl::CheckIfRunInsecureContent(const GURL& url) {
827 if (!webframe_)
828 return true;
830 return webframe_->checkIfRunInsecureContent(url);
833 #if defined(OS_MACOSX)
834 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
835 gfx::GpuPreference gpu_preference) {
836 return NULL;
839 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
842 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width,
843 int32 height,
844 uint32 surface_id) {
845 next_io_surface_allocated_ = true;
846 next_io_surface_width_ = width;
847 next_io_surface_height_ = height;
848 next_io_surface_id_ = surface_id;
851 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
852 if (!container_)
853 return;
854 // Deferring the call to setBackingIOSurfaceId is an attempt to
855 // work around garbage occasionally showing up in the plugin's
856 // area during live resizing of Core Animation plugins. The
857 // assumption was that by the time this was called, the plugin
858 // process would have populated the newly allocated IOSurface. It
859 // is not 100% clear at this point why any garbage is getting
860 // through. More investigation is needed. http://crbug.com/105346
861 if (next_io_surface_allocated_) {
862 if (next_io_surface_id_) {
863 if (!io_surface_layer_.get()) {
864 io_surface_layer_ = cc::IOSurfaceLayer::Create();
865 web_layer_.reset(new cc_blink::WebLayerImpl(io_surface_layer_));
866 container_->setWebLayer(web_layer_.get());
868 io_surface_layer_->SetIOSurfaceProperties(
869 next_io_surface_id_,
870 gfx::Size(next_io_surface_width_, next_io_surface_height_));
871 } else {
872 container_->setWebLayer(NULL);
873 web_layer_.reset();
874 io_surface_layer_ = NULL;
876 next_io_surface_allocated_ = false;
877 } else {
878 if (io_surface_layer_.get())
879 io_surface_layer_->SetNeedsDisplay();
882 #endif
884 void WebPluginImpl::Invalidate() {
885 if (container_)
886 container_->invalidate();
889 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
890 if (container_)
891 container_->invalidateRect(rect);
894 void WebPluginImpl::OnDownloadPluginSrcUrl() {
895 HandleURLRequestInternal(
896 plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
897 false, true);
900 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
901 WebURLLoader* loader) {
902 ClientInfo* client_info = GetClientInfoFromLoader(loader);
903 if (client_info)
904 return client_info->client;
905 return NULL;
908 WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
909 WebURLLoader* loader) {
910 for (size_t i = 0; i < clients_.size(); ++i) {
911 if (clients_[i].loader.get() == loader)
912 return &clients_[i];
915 NOTREACHED();
916 return 0;
919 void WebPluginImpl::willSendRequest(WebURLLoader* loader,
920 WebURLRequest& request,
921 const WebURLResponse& response) {
922 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedRedirect
923 // until kDirectNPAPIRequests is the default and we can remove this old path.
924 WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
925 if (client_info) {
926 // Currently this check is just to catch an https -> http redirect when
927 // loading the main plugin src URL. Longer term, we could investigate
928 // firing mixed diplay or scripting issues for subresource loads
929 // initiated by plugins.
930 if (client_info->is_plugin_src_load &&
931 webframe_ &&
932 !webframe_->checkIfRunInsecureContent(request.url())) {
933 loader->cancel();
934 client_info->client->DidFail(client_info->id);
935 return;
937 if (net::HttpResponseHeaders::IsRedirectResponseCode(
938 response.httpStatusCode())) {
939 // If the plugin does not participate in url redirect notifications then
940 // just block cross origin 307 POST redirects.
941 if (!client_info->notify_redirects) {
942 if (response.httpStatusCode() == 307 &&
943 LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
944 GURL original_request_url(response.url());
945 GURL response_url(request.url());
946 if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
947 loader->setDefersLoading(true);
948 loader->cancel();
949 client_info->client->DidFail(client_info->id);
950 return;
953 } else {
954 loader->setDefersLoading(true);
957 client_info->client->WillSendRequest(request.url(),
958 response.httpStatusCode());
962 void WebPluginImpl::didSendData(WebURLLoader* loader,
963 unsigned long long bytes_sent,
964 unsigned long long total_bytes_to_be_sent) {
967 void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
968 const WebURLResponse& response) {
969 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
970 // until kDirectNPAPIRequests is the default and we can remove this old path.
971 static const int kHttpPartialResponseStatusCode = 206;
972 static const int kHttpResponseSuccessStatusCode = 200;
974 WebPluginResourceClient* client = GetClientFromLoader(loader);
975 if (!client)
976 return;
978 ResponseInfo response_info;
979 GetResponseInfo(response, &response_info);
980 ClientInfo* client_info = GetClientInfoFromLoader(loader);
981 if (!client_info)
982 return;
984 bool request_is_seekable = true;
985 if (client->IsMultiByteResponseExpected()) {
986 if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
987 ClientInfo* client_info = GetClientInfoFromLoader(loader);
988 if (!client_info)
989 return;
990 if (HandleHttpMultipartResponse(response, client)) {
991 // Multiple ranges requested, data will be delivered by
992 // MultipartResponseDelegate.
993 client_info->data_offset = 0;
994 return;
996 int64 upper_bound = 0, instance_size = 0;
997 // Single range requested - go through original processing for
998 // non-multipart requests, but update data offset.
999 MultipartResponseDelegate::ReadContentRanges(response,
1000 &client_info->data_offset,
1001 &upper_bound,
1002 &instance_size);
1003 } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
1004 RenderThreadImpl::current()->RecordAction(
1005 base::UserMetricsAction("Plugin_200ForByteRange"));
1006 // If the client issued a byte range request and the server responds with
1007 // HTTP 200 OK, it indicates that the server does not support byte range
1008 // requests.
1009 // We need to emulate Firefox behavior by doing the following:-
1010 // 1. Destroy the plugin instance in the plugin process. Ensure that
1011 // existing resource requests initiated for the plugin instance
1012 // continue to remain valid.
1013 // 2. Create a new plugin instance and notify it about the response
1014 // received here.
1015 if (!ReinitializePluginForResponse(loader)) {
1016 NOTREACHED();
1017 return;
1020 // The server does not support byte range requests. No point in creating
1021 // seekable streams.
1022 request_is_seekable = false;
1024 delete client;
1025 client = NULL;
1027 // Create a new resource client for this request.
1028 for (size_t i = 0; i < clients_.size(); ++i) {
1029 if (clients_[i].loader.get() == loader) {
1030 WebPluginResourceClient* resource_client =
1031 delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
1032 clients_[i].client = resource_client;
1033 client = resource_client;
1034 break;
1038 DCHECK(client != NULL);
1042 // Calling into a plugin could result in reentrancy if the plugin yields
1043 // control to the OS like entering a modal loop etc. Prevent this by
1044 // stopping further loading until the plugin notifies us that it is ready to
1045 // accept data
1046 loader->setDefersLoading(true);
1048 client->DidReceiveResponse(
1049 response_info.mime_type,
1050 GetAllHeaders(response),
1051 response_info.expected_length,
1052 response_info.last_modified,
1053 request_is_seekable);
1055 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1056 // error codes in the stream header and as a result, was unaware of the
1057 // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1058 // destroy the stream and invoke the NPP_DestroyStream function on the
1059 // plugin if the HTTP request fails.
1060 const GURL& url = response.url();
1061 if (url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme)) {
1062 if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
1063 // The plugin instance could be in the process of deletion here.
1064 // Verify if the WebPluginResourceClient instance still exists before
1065 // use.
1066 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1067 if (client_info) {
1068 client_info->pending_failure_notification = true;
1074 void WebPluginImpl::didReceiveData(WebURLLoader* loader,
1075 const char *buffer,
1076 int data_length,
1077 int encoded_data_length) {
1078 WebPluginResourceClient* client = GetClientFromLoader(loader);
1079 if (!client)
1080 return;
1082 MultiPartResponseHandlerMap::iterator index =
1083 multi_part_response_map_.find(client);
1084 if (index != multi_part_response_map_.end()) {
1085 MultipartResponseDelegate* multi_part_handler = (*index).second;
1086 DCHECK(multi_part_handler != NULL);
1087 multi_part_handler->OnReceivedData(buffer,
1088 data_length,
1089 encoded_data_length);
1090 } else {
1091 loader->setDefersLoading(true);
1092 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1093 client->DidReceiveData(buffer, data_length, client_info->data_offset);
1094 client_info->data_offset += data_length;
1098 void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
1099 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1100 if (client_info && client_info->client) {
1101 MultiPartResponseHandlerMap::iterator index =
1102 multi_part_response_map_.find(client_info->client);
1103 if (index != multi_part_response_map_.end()) {
1104 delete (*index).second;
1105 multi_part_response_map_.erase(index);
1106 DidStopLoading();
1108 loader->setDefersLoading(true);
1109 WebPluginResourceClient* resource_client = client_info->client;
1110 // The ClientInfo can get deleted in the call to DidFinishLoading below.
1111 // It is not safe to access this structure after that.
1112 client_info->client = NULL;
1113 resource_client->DidFinishLoading(client_info->id);
1117 void WebPluginImpl::didFail(WebURLLoader* loader,
1118 const WebURLError& error) {
1119 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1120 if (client_info && client_info->client) {
1121 loader->setDefersLoading(true);
1122 WebPluginResourceClient* resource_client = client_info->client;
1123 // The ClientInfo can get deleted in the call to DidFail below.
1124 // It is not safe to access this structure after that.
1125 client_info->client = NULL;
1126 resource_client->DidFail(client_info->id);
1130 void WebPluginImpl::RemoveClient(size_t i) {
1131 clients_.erase(clients_.begin() + i);
1134 void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
1135 for (size_t i = 0; i < clients_.size(); ++i) {
1136 if (clients_[i].loader.get() == loader) {
1137 RemoveClient(i);
1138 return;
1143 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
1144 if (!container)
1145 TearDownPluginInstance(NULL);
1146 container_ = container;
1147 if (container_)
1148 container_->allowScriptObjects();
1151 void WebPluginImpl::HandleURLRequest(const char* url,
1152 const char* method,
1153 const char* target,
1154 const char* buf,
1155 unsigned int len,
1156 int notify_id,
1157 bool popups_allowed,
1158 bool notify_redirects) {
1159 // GetURL/PostURL requests initiated explicitly by plugins should specify the
1160 // plugin SRC url as the referrer if it is available.
1161 HandleURLRequestInternal(
1162 url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
1163 notify_redirects, false);
1166 void WebPluginImpl::HandleURLRequestInternal(const char* url,
1167 const char* method,
1168 const char* target,
1169 const char* buf,
1170 unsigned int len,
1171 int notify_id,
1172 bool popups_allowed,
1173 ReferrerValue referrer_flag,
1174 bool notify_redirects,
1175 bool is_plugin_src_load) {
1176 // For this request, we either route the output to a frame
1177 // because a target has been specified, or we handle the request
1178 // here, i.e. by executing the script if it is a javascript url
1179 // or by initiating a download on the URL, etc. There is one special
1180 // case in that the request is a javascript url and the target is "_self",
1181 // in which case we route the output to the plugin rather than routing it
1182 // to the plugin's frame.
1183 bool is_javascript_url =
1184 url::FindAndCompareScheme(url, strlen(url), url::kJavaScriptScheme, NULL);
1185 RoutingStatus routing_status = RouteToFrame(
1186 url, is_javascript_url, popups_allowed, method, target, buf, len,
1187 notify_id, referrer_flag);
1188 if (routing_status == ROUTED)
1189 return;
1191 if (is_javascript_url) {
1192 GURL gurl(url);
1193 WebString result = container_->executeScriptURL(gurl, popups_allowed);
1195 // delegate_ could be NULL because executeScript caused the container to
1196 // be deleted.
1197 if (delegate_) {
1198 delegate_->SendJavaScriptStream(
1199 gurl, result.utf8(), !result.isNull(), notify_id);
1202 return;
1205 unsigned long resource_id = GetNextResourceId();
1206 if (!resource_id)
1207 return;
1209 GURL complete_url = CompleteURL(url);
1210 // Remove when flash bug is fixed. http://crbug.com/40016.
1211 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
1212 return;
1214 // If the RouteToFrame call returned a failure then inform the result
1215 // back to the plugin asynchronously.
1216 if ((routing_status == INVALID_URL) ||
1217 (routing_status == GENERAL_FAILURE)) {
1218 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1219 resource_id, complete_url, notify_id);
1220 if (resource_client)
1221 resource_client->DidFail(resource_id);
1222 return;
1225 // CreateResourceClient() sends a synchronous IPC message so it's possible
1226 // that TearDownPluginInstance() may have been called in the nested
1227 // message loop. If so, don't start the request.
1228 if (!delegate_)
1229 return;
1231 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1232 switches::kDisableDirectNPAPIRequests)) {
1233 // We got here either because the plugin called GetURL/PostURL, or because
1234 // we're fetching the data for an embed tag. If we're in multi-process mode,
1235 // we want to fetch the data in the plugin process as the renderer won't be
1236 // able to request any origin when site isolation is in place. So bounce
1237 // this request back to the plugin process which will use ResourceDispatcher
1238 // to fetch the url.
1240 // TODO(jam): any better way of getting this? Can't find a way to get
1241 // frame()->loader()->outgoingReferrer() which
1242 // WebFrameImpl::setReferrerForRequest does.
1243 WebURLRequest request(complete_url);
1244 SetReferrer(&request, referrer_flag);
1245 Referrer referrer(
1246 GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
1247 request.referrerPolicy());
1249 GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
1250 delegate_->FetchURL(resource_id, notify_id, complete_url,
1251 first_party_for_cookies, method, buf, len, referrer,
1252 notify_redirects, is_plugin_src_load, 0,
1253 render_frame_->GetRoutingID(),
1254 render_view_->GetRoutingID());
1255 } else {
1256 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1257 resource_id, complete_url, notify_id);
1258 if (!resource_client)
1259 return;
1260 InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
1261 len, NULL, referrer_flag, notify_redirects,
1262 is_plugin_src_load);
1266 unsigned long WebPluginImpl::GetNextResourceId() {
1267 if (!webframe_)
1268 return 0;
1269 WebView* view = webframe_->view();
1270 if (!view)
1271 return 0;
1272 return view->createUniqueIdentifierForRequest();
1275 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
1276 WebPluginResourceClient* client,
1277 const GURL& url,
1278 const char* method,
1279 const char* buf,
1280 int buf_len,
1281 const char* range_info,
1282 ReferrerValue referrer_flag,
1283 bool notify_redirects,
1284 bool is_plugin_src_load) {
1285 if (!client) {
1286 NOTREACHED();
1287 return false;
1290 ClientInfo info;
1291 info.id = resource_id;
1292 info.client = client;
1293 info.request.initialize();
1294 info.request.setURL(url);
1295 info.request.setFirstPartyForCookies(
1296 webframe_->document().firstPartyForCookies());
1297 info.request.setRequestorProcessID(delegate_->GetProcessId());
1298 // TODO(mkwst): Is this a request for a plugin object itself
1299 // (RequestContextObject), or a request that the plugin makes
1300 // (RequestContextPlugin)?
1301 info.request.setRequestContext(WebURLRequest::RequestContextPlugin);
1302 info.request.setHTTPMethod(WebString::fromUTF8(method));
1303 // ServiceWorker is disabled for NPAPI.
1304 info.request.setSkipServiceWorker(true);
1305 info.pending_failure_notification = false;
1306 info.notify_redirects = notify_redirects;
1307 info.is_plugin_src_load = is_plugin_src_load;
1308 info.data_offset = 0;
1310 if (range_info) {
1311 info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
1312 WebString::fromUTF8(range_info));
1315 if (strcmp(method, "POST") == 0) {
1316 // Adds headers or form data to a request. This must be called before
1317 // we initiate the actual request.
1318 SetPostData(&info.request, buf, buf_len);
1321 SetReferrer(&info.request, referrer_flag);
1323 WebURLLoaderOptions options;
1324 options.allowCredentials = true;
1325 options.crossOriginRequestPolicy =
1326 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
1327 info.loader.reset(webframe_->createAssociatedURLLoader(options));
1328 if (!info.loader.get())
1329 return false;
1330 info.loader->loadAsynchronously(info.request, &loader_client_);
1332 clients_.push_back(info);
1333 return true;
1336 void WebPluginImpl::CancelDocumentLoad() {
1337 if (webframe_) {
1338 ignore_response_error_ = true;
1339 webframe_->stopLoading();
1343 void WebPluginImpl::InitiateHTTPRangeRequest(
1344 const char* url, const char* range_info, int range_request_id) {
1345 unsigned long resource_id = GetNextResourceId();
1346 if (!resource_id)
1347 return;
1349 GURL complete_url = CompleteURL(url);
1350 // Remove when flash bug is fixed. http://crbug.com/40016.
1351 if (!WebPluginImpl::IsValidUrl(complete_url,
1352 load_manually_ ? NO_REFERRER : PLUGIN_SRC))
1353 return;
1355 WebPluginResourceClient* resource_client =
1356 delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
1357 InitiateHTTPRequest(
1358 resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
1359 load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
1362 void WebPluginImpl::DidStartLoading() {
1363 if (render_view_.get()) {
1364 // TODO(darin): Make is_loading_ be a counter!
1365 render_view_->DidStartLoading();
1369 void WebPluginImpl::DidStopLoading() {
1370 if (render_view_.get()) {
1371 // TODO(darin): Make is_loading_ be a counter!
1372 render_view_->DidStopLoading();
1376 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
1377 bool defer) {
1378 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1379 while (client_index != clients_.end()) {
1380 ClientInfo& client_info = *client_index;
1382 if (client_info.id == resource_id) {
1383 client_info.loader->setDefersLoading(defer);
1385 // If we determined that the request had failed via the HTTP headers
1386 // in the response then we send out a failure notification to the
1387 // plugin process, as certain plugins don't handle HTTP failure codes
1388 // correctly.
1389 if (!defer && client_info.client &&
1390 client_info.pending_failure_notification) {
1391 // The ClientInfo and the iterator can become invalid due to the call
1392 // to DidFail below.
1393 WebPluginResourceClient* resource_client = client_info.client;
1394 client_info.loader->cancel();
1395 clients_.erase(client_index++);
1396 resource_client->DidFail(resource_id);
1398 break;
1400 client_index++;
1404 bool WebPluginImpl::IsOffTheRecord() {
1405 return false;
1408 bool WebPluginImpl::HandleHttpMultipartResponse(
1409 const WebURLResponse& response, WebPluginResourceClient* client) {
1410 std::string multipart_boundary;
1411 if (!MultipartResponseDelegate::ReadMultipartBoundary(
1412 response, &multipart_boundary)) {
1413 return false;
1416 DidStartLoading();
1418 MultiPartResponseClient* multi_part_response_client =
1419 new MultiPartResponseClient(client);
1421 MultipartResponseDelegate* multi_part_response_handler =
1422 new MultipartResponseDelegate(multi_part_response_client, NULL,
1423 response,
1424 multipart_boundary);
1425 multi_part_response_map_[client] = multi_part_response_handler;
1426 return true;
1429 bool WebPluginImpl::ReinitializePluginForResponse(
1430 WebURLLoader* loader) {
1431 WebFrame* webframe = webframe_;
1432 if (!webframe)
1433 return false;
1435 WebView* webview = webframe->view();
1436 if (!webview)
1437 return false;
1439 WebPluginContainer* container_widget = container_;
1441 // Destroy the current plugin instance.
1442 TearDownPluginInstance(loader);
1444 container_ = container_widget;
1445 webframe_ = webframe;
1447 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
1448 this, mime_type_, render_view_, render_frame_);
1450 // Store the plugin's unique identifier, used by the container to track its
1451 // script objects, and enable script objects (since Initialize may use them
1452 // even if it fails).
1453 npp_ = plugin_delegate->GetPluginNPP();
1454 container_->allowScriptObjects();
1456 bool ok = plugin_delegate && plugin_delegate->Initialize(
1457 plugin_url_, arg_names_, arg_values_, load_manually_);
1459 if (!ok) {
1460 container_->clearScriptObjects();
1461 container_ = NULL;
1462 // TODO(iyengar) Should we delete the current plugin instance here?
1463 return false;
1466 delegate_ = plugin_delegate;
1468 // Force a geometry update to occur to ensure that the plugin becomes
1469 // visible.
1470 container_->reportGeometry();
1472 // The plugin move sequences accumulated via DidMove are sent to the browser
1473 // whenever the renderer paints. Force a paint here to ensure that changes
1474 // to the plugin window are propagated to the browser.
1475 container_->invalidate();
1476 return true;
1479 void WebPluginImpl::TearDownPluginInstance(
1480 WebURLLoader* loader_to_ignore) {
1481 // JavaScript garbage collection may cause plugin script object references to
1482 // be retained long after the plugin is destroyed. Some plugins won't cope
1483 // with their objects being released after they've been destroyed, and once
1484 // we've actually unloaded the plugin the object's releaseobject() code may
1485 // no longer be in memory. The container tracks the plugin's objects and lets
1486 // us invalidate them, releasing the references to them held by the JavaScript
1487 // runtime.
1488 if (container_) {
1489 container_->clearScriptObjects();
1490 container_->setWebLayer(NULL);
1493 // Call PluginDestroyed() first to prevent the plugin from calling us back
1494 // in the middle of tearing down the render tree.
1495 if (delegate_) {
1496 // The plugin may call into the browser and pass script objects even during
1497 // teardown, so temporarily re-enable plugin script objects.
1498 DCHECK(container_);
1499 container_->allowScriptObjects();
1501 delegate_->PluginDestroyed();
1502 delegate_ = NULL;
1504 // Invalidate any script objects created during teardown here, before the
1505 // plugin might actually be unloaded.
1506 container_->clearScriptObjects();
1509 // Cancel any pending requests because otherwise this deleted object will
1510 // be called by the ResourceDispatcher.
1511 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1512 while (client_index != clients_.end()) {
1513 ClientInfo& client_info = *client_index;
1515 if (loader_to_ignore == client_info.loader) {
1516 client_index++;
1517 continue;
1520 if (client_info.loader.get())
1521 client_info.loader->cancel();
1523 client_index = clients_.erase(client_index);
1526 // This needs to be called now and not in the destructor since the
1527 // webframe_ might not be valid anymore.
1528 webframe_ = NULL;
1529 weak_factory_.InvalidateWeakPtrs();
1532 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
1533 ReferrerValue referrer_flag) {
1534 switch (referrer_flag) {
1535 case DOCUMENT_URL:
1536 webframe_->setReferrerForRequest(*request, GURL());
1537 break;
1539 case PLUGIN_SRC:
1540 webframe_->setReferrerForRequest(*request, plugin_url_);
1541 break;
1543 default:
1544 break;
1548 } // namespace content