Fix a couple bugs in the settings_page_header wrt breadcrumbs.
[chromium-blink-merge.git] / content / renderer / npapi / webplugin_impl.cc
blob127c5743ddd8df6877c4389c04c880a4cb635ca1
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/location.h"
11 #include "base/logging.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/metrics/user_metrics_action.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "cc/blink/web_layer_impl.h"
20 #include "cc/layers/io_surface_layer.h"
21 #include "content/child/appcache/web_application_cache_host_impl.h"
22 #include "content/child/multipart_response_delegate.h"
23 #include "content/child/npapi/plugin_host.h"
24 #include "content/child/npapi/plugin_instance.h"
25 #include "content/child/npapi/webplugin_delegate_impl.h"
26 #include "content/child/npapi/webplugin_resource_client.h"
27 #include "content/common/view_messages.h"
28 #include "content/public/common/content_constants.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/renderer/content_renderer_client.h"
31 #include "content/renderer/npapi/webplugin_delegate_proxy.h"
32 #include "content/renderer/render_frame_impl.h"
33 #include "content/renderer/render_process.h"
34 #include "content/renderer/render_thread_impl.h"
35 #include "content/renderer/render_view_impl.h"
36 #include "net/base/escape.h"
37 #include "net/base/net_errors.h"
38 #include "net/http/http_response_headers.h"
39 #include "skia/ext/platform_canvas.h"
40 #include "third_party/WebKit/public/platform/WebCString.h"
41 #include "third_party/WebKit/public/platform/WebCookieJar.h"
42 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
43 #include "third_party/WebKit/public/platform/WebData.h"
44 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
45 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
46 #include "third_party/WebKit/public/platform/WebURL.h"
47 #include "third_party/WebKit/public/platform/WebURLError.h"
48 #include "third_party/WebKit/public/platform/WebURLLoader.h"
49 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
50 #include "third_party/WebKit/public/platform/WebURLResponse.h"
51 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
52 #include "third_party/WebKit/public/web/WebDocument.h"
53 #include "third_party/WebKit/public/web/WebFrame.h"
54 #include "third_party/WebKit/public/web/WebInputEvent.h"
55 #include "third_party/WebKit/public/web/WebKit.h"
56 #include "third_party/WebKit/public/web/WebPluginContainer.h"
57 #include "third_party/WebKit/public/web/WebPluginParams.h"
58 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
59 #include "third_party/WebKit/public/web/WebView.h"
60 #include "ui/gfx/geometry/rect.h"
61 #include "url/gurl.h"
62 #include "url/url_util.h"
64 using blink::WebCString;
65 using blink::WebCanvas;
66 using blink::WebConsoleMessage;
67 using blink::WebCookieJar;
68 using blink::WebCursorInfo;
69 using blink::WebData;
70 using blink::WebDataSource;
71 using blink::WebFrame;
72 using blink::WebHTTPBody;
73 using blink::WebHTTPHeaderVisitor;
74 using blink::WebInputEvent;
75 using blink::WebKeyboardEvent;
76 using blink::WebMouseEvent;
77 using blink::WebPluginContainer;
78 using blink::WebPluginParams;
79 using blink::WebRect;
80 using blink::WebString;
81 using blink::WebURL;
82 using blink::WebURLError;
83 using blink::WebURLLoader;
84 using blink::WebURLLoaderClient;
85 using blink::WebURLLoaderOptions;
86 using blink::WebURLRequest;
87 using blink::WebURLResponse;
88 using blink::WebVector;
89 using blink::WebView;
91 namespace content {
93 namespace {
95 // This class handles individual multipart responses. It is instantiated when
96 // we receive HTTP status code 206 in the HTTP response. This indicates
97 // that the response could have multiple parts each separated by a boundary
98 // specified in the response header.
99 class MultiPartResponseClient : public WebURLLoaderClient {
100 public:
101 explicit MultiPartResponseClient(WebPluginResourceClient* resource_client)
102 : byte_range_lower_bound_(0), resource_client_(resource_client) {}
104 virtual void willSendRequest(
105 WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
106 virtual void didSendData(
107 WebURLLoader*, unsigned long long, unsigned long long) {}
109 // Called when the multipart parser encounters an embedded multipart
110 // response.
111 virtual void didReceiveResponse(
112 WebURLLoader*, const WebURLResponse& response) {
113 int64 byte_range_upper_bound, instance_size;
114 if (!MultipartResponseDelegate::ReadContentRanges(
115 response,
116 &byte_range_lower_bound_,
117 &byte_range_upper_bound,
118 &instance_size)) {
119 NOTREACHED();
123 // Receives individual part data from a multipart response.
124 virtual void didReceiveData(WebURLLoader*,
125 const char* data,
126 int data_length,
127 int encoded_data_length) {
128 // TODO(ananta)
129 // We should defer further loads on multipart resources on the same lines
130 // as regular resources requested by plugins to prevent reentrancy.
131 resource_client_->DidReceiveData(
132 data, data_length, byte_range_lower_bound_);
133 byte_range_lower_bound_ += data_length;
136 virtual void didFinishLoading(WebURLLoader*,
137 double finishTime,
138 int64_t total_encoded_data_length) {}
139 virtual void didFail(WebURLLoader*, const WebURLError&) {}
141 private:
142 // The lower bound of the byte range.
143 int64 byte_range_lower_bound_;
144 // The handler for the data.
145 WebPluginResourceClient* resource_client_;
148 class HeaderFlattener : public WebHTTPHeaderVisitor {
149 public:
150 explicit HeaderFlattener(std::string* buf) : buf_(buf) {
153 virtual void visitHeader(const WebString& name, const WebString& value) {
154 // TODO(darin): Should we really exclude headers with an empty value?
155 if (!name.isEmpty() && !value.isEmpty()) {
156 buf_->append(name.utf8());
157 buf_->append(": ");
158 buf_->append(value.utf8());
159 buf_->append("\n");
163 private:
164 std::string* buf_;
167 std::string GetAllHeaders(const WebURLResponse& response) {
168 // TODO(darin): It is possible for httpStatusText to be empty and still have
169 // an interesting response, so this check seems wrong.
170 std::string result;
171 const WebString& status = response.httpStatusText();
172 if (status.isEmpty())
173 return result;
175 // TODO(darin): Shouldn't we also report HTTP version numbers?
176 result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
177 result.append(status.utf8());
178 result.append("\n");
180 HeaderFlattener flattener(&result);
181 response.visitHTTPHeaderFields(&flattener);
183 return result;
186 struct ResponseInfo {
187 GURL url;
188 std::string mime_type;
189 uint32 last_modified;
190 uint32 expected_length;
193 void GetResponseInfo(const WebURLResponse& response,
194 ResponseInfo* response_info) {
195 response_info->url = response.url();
196 response_info->mime_type = response.mimeType().utf8();
198 // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
199 response_info->last_modified =
200 static_cast<uint32>(response.lastModifiedDate());
202 // If the length comes in as -1, then it indicates that it was not
203 // read off the HTTP headers. We replicate Safari webkit behavior here,
204 // which is to set it to 0.
205 response_info->expected_length =
206 static_cast<uint32>(std::max(response.expectedContentLength(), 0LL));
208 WebString content_encoding =
209 response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
210 if (!content_encoding.isNull() &&
211 !EqualsASCII(content_encoding, "identity")) {
212 // Don't send the compressed content length to the plugin, which only
213 // cares about the decoded length.
214 response_info->expected_length = 0;
218 } // namespace
220 // blink::WebPlugin ----------------------------------------------------------
222 struct WebPluginImpl::ClientInfo {
223 unsigned long id;
224 WebPluginResourceClient* client;
225 blink::WebURLRequest request;
226 bool pending_failure_notification;
227 linked_ptr<blink::WebURLLoader> loader;
228 bool notify_redirects;
229 bool is_plugin_src_load;
230 int64 data_offset;
233 bool WebPluginImpl::initialize(WebPluginContainer* container) {
234 if (!render_view_.get()) {
235 LOG(ERROR) << "No RenderView";
236 return false;
239 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
240 this, mime_type_, render_view_, render_frame_);
242 // Store the plugin's unique identifier, used by the container to track its
243 // script objects.
244 npp_ = plugin_delegate->GetPluginNPP();
246 // Set the container before Initialize because the plugin may
247 // synchronously call NPN_GetValue to get its container, or make calls
248 // passing script objects that need to be tracked, during initialization.
249 SetContainer(container);
251 bool ok = plugin_delegate->Initialize(
252 plugin_url_, arg_names_, arg_values_, load_manually_);
253 if (!ok) {
254 plugin_delegate->PluginDestroyed();
256 blink::WebPlugin* replacement_plugin =
257 GetContentClient()->renderer()->CreatePluginReplacement(
258 render_frame_, file_path_);
259 if (!replacement_plugin)
260 return false;
262 // Disable scripting by this plugin before replacing it with the new
263 // one. This plugin also needs destroying, so use destroy(), which will
264 // implicitly disable scripting while un-setting the container.
265 destroy();
267 // Inform the container of the replacement plugin, then initialize it.
268 container->setPlugin(replacement_plugin);
269 return replacement_plugin->initialize(container);
272 delegate_ = plugin_delegate;
274 return true;
277 void WebPluginImpl::destroy() {
278 SetContainer(NULL);
279 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
282 NPObject* WebPluginImpl::scriptableObject() {
283 if (!delegate_)
284 return NULL;
286 return delegate_->GetPluginScriptableObject();
289 NPP WebPluginImpl::pluginNPP() {
290 return npp_;
293 bool WebPluginImpl::getFormValue(blink::WebString& value) {
294 if (!delegate_)
295 return false;
296 base::string16 form_value;
297 if (!delegate_->GetFormValue(&form_value))
298 return false;
299 value = form_value;
300 return true;
303 void WebPluginImpl::layoutIfNeeded() {
304 if (!container_)
305 return;
307 #if defined(OS_WIN)
308 // Force a geometry update if needed to allow plugins like media player
309 // which defer the initial geometry update to work. Do it now, rather
310 // than in paint, so that the paint rect invalidation is registered.
311 // Otherwise we may never get the paint call.
312 container_->reportGeometry();
313 #endif // OS_WIN
316 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
317 if (!delegate_ || !container_)
318 return;
320 // Note that |canvas| is only used when in windowless mode.
321 delegate_->Paint(canvas, paint_rect);
324 void WebPluginImpl::updateGeometry(const WebRect& window_rect,
325 const WebRect& clip_rect,
326 const WebRect& unobscured_rect,
327 const WebVector<WebRect>& cut_outs_rects,
328 bool is_visible) {
329 WebPluginGeometry new_geometry;
330 new_geometry.window = window_;
331 new_geometry.window_rect = window_rect;
332 new_geometry.clip_rect = clip_rect;
333 new_geometry.visible = is_visible;
334 new_geometry.rects_valid = true;
335 for (size_t i = 0; i < cut_outs_rects.size(); ++i)
336 new_geometry.cutout_rects.push_back(cut_outs_rects[i]);
338 // Only send DidMovePlugin if the geometry changed in some way.
339 if (window_ && (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
340 render_frame_->GetRenderWidget()->SchedulePluginMove(new_geometry);
341 // We invalidate windowed plugins during the first geometry update to
342 // ensure that they get reparented to the wrapper window in the browser.
343 // This ensures that they become visible and are painted by the OS. This is
344 // required as some pages don't invalidate when the plugin is added.
345 if (first_geometry_update_ && window_) {
346 InvalidateRect(window_rect);
350 // Only UpdateGeometry if either the window or clip rects have changed.
351 if (delegate_ && (first_geometry_update_ ||
352 new_geometry.window_rect != geometry_.window_rect ||
353 new_geometry.clip_rect != geometry_.clip_rect)) {
354 // Notify the plugin that its parameters have changed.
355 delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
358 // Initiate a download on the plugin url. This should be done for the
359 // first update geometry sequence. We need to ensure that the plugin
360 // receives the geometry update before it starts receiving data.
361 if (first_geometry_update_) {
362 // An empty url corresponds to an EMBED tag with no src attribute.
363 if (!load_manually_ && plugin_url_.is_valid()) {
364 // The Flash plugin hangs for a while if it receives data before
365 // receiving valid plugin geometry. By valid geometry we mean the
366 // geometry received by a call to setFrameRect in the Webkit
367 // layout code path. To workaround this issue we download the
368 // plugin source url on a timer.
369 base::ThreadTaskRunnerHandle::Get()->PostTask(
370 FROM_HERE, base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl,
371 weak_factory_.GetWeakPtr()));
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;
392 void WebPluginImpl::updateFocus(bool focused, blink::WebFocusType focus_type) {
393 if (accepts_input_events_)
394 delegate_->SetFocus(focused);
397 void WebPluginImpl::updateVisibility(bool visible) {
398 if (!window_)
399 return;
401 WebPluginGeometry move;
402 move.window = window_;
403 move.window_rect = gfx::Rect();
404 move.clip_rect = gfx::Rect();
405 move.rects_valid = false;
406 move.visible = visible;
408 render_frame_->GetRenderWidget()->SchedulePluginMove(move);
411 bool WebPluginImpl::acceptsInputEvents() {
412 return accepts_input_events_;
415 bool WebPluginImpl::handleInputEvent(
416 const WebInputEvent& event, WebCursorInfo& cursor_info) {
417 // Swallow context menu events in order to suppress the default context menu.
418 if (event.type == WebInputEvent::ContextMenu)
419 return true;
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;
433 void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
434 ignore_response_error_ = false;
436 ResponseInfo response_info;
437 GetResponseInfo(response, &response_info);
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);
447 void WebPluginImpl::didReceiveData(const char* data, int data_length) {
448 delegate_->DidReceiveManualData(data, data_length);
451 void WebPluginImpl::didFinishLoading() {
452 delegate_->DidFinishManualLoading();
455 void WebPluginImpl::didFailLoading(const WebURLError& error) {
456 if (!ignore_response_error_)
457 delegate_->DidManualLoadFail();
460 void WebPluginImpl::didFinishLoadingFrameRequest(
461 const WebURL& url, void* notify_data) {
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));
473 void WebPluginImpl::didFailLoadingFrameRequest(
474 const WebURL& url, void* notify_data, const WebURLError& error) {
475 if (!delegate_)
476 return;
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));
485 bool WebPluginImpl::isPlaceholder() {
486 return false;
489 WebPluginImpl::LoaderClient::LoaderClient(WebPluginImpl* parent)
490 : parent_(parent) {}
492 void WebPluginImpl::LoaderClient::willSendRequest(
493 blink::WebURLLoader* loader, blink::WebURLRequest& newRequest,
494 const blink::WebURLResponse& redirectResponse) {
495 parent_->willSendRequest(loader, newRequest, redirectResponse);
498 void WebPluginImpl::LoaderClient::didSendData(
499 blink::WebURLLoader* loader, unsigned long long bytesSent,
500 unsigned long long totalBytesToBeSent) {
501 parent_->didSendData(loader, bytesSent, totalBytesToBeSent);
504 void WebPluginImpl::LoaderClient::didReceiveResponse(
505 blink::WebURLLoader* loader, const blink::WebURLResponse& response) {
506 parent_->didReceiveResponse(loader, response);
509 void WebPluginImpl::LoaderClient::didDownloadData(
510 blink::WebURLLoader* loader, int dataLength, int encodedDataLength) {
513 void WebPluginImpl::LoaderClient::didReceiveData(
514 blink::WebURLLoader* loader, const char* data,
515 int dataLength, int encodedDataLength) {
516 parent_->didReceiveData(loader, data, dataLength, encodedDataLength);
519 void WebPluginImpl::LoaderClient::didReceiveCachedMetadata(
520 blink::WebURLLoader* loader, const char* data, int dataLength) {
523 void WebPluginImpl::LoaderClient::didFinishLoading(
524 blink::WebURLLoader* loader, double finishTime,
525 int64_t total_encoded_data_length) {
526 parent_->didFinishLoading(loader, finishTime);
529 void WebPluginImpl::LoaderClient::didFail(
530 blink::WebURLLoader* loader, const blink::WebURLError& error) {
531 parent_->didFail(loader, error);
534 // -----------------------------------------------------------------------------
536 WebPluginImpl::WebPluginImpl(
537 WebFrame* webframe,
538 const WebPluginParams& params,
539 const base::FilePath& file_path,
540 const base::WeakPtr<RenderViewImpl>& render_view,
541 RenderFrameImpl* render_frame)
542 : windowless_(false),
543 window_(gfx::kNullPluginWindow),
544 accepts_input_events_(false),
545 render_frame_(render_frame),
546 render_view_(render_view),
547 webframe_(webframe),
548 delegate_(NULL),
549 container_(NULL),
550 npp_(NULL),
551 plugin_url_(params.url),
552 load_manually_(params.loadManually),
553 first_geometry_update_(true),
554 ignore_response_error_(false),
555 file_path_(file_path),
556 mime_type_(base::UTF16ToASCII(params.mimeType)),
557 loader_client_(this),
558 weak_factory_(this) {
559 DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
560 base::StringToLowerASCII(&mime_type_);
562 for (size_t i = 0; i < params.attributeNames.size(); ++i) {
563 arg_names_.push_back(params.attributeNames[i].utf8());
564 arg_values_.push_back(params.attributeValues[i].utf8());
567 // Set subresource URL for crash reporting.
568 base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec());
571 WebPluginImpl::~WebPluginImpl() {
574 void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
575 if (window) {
576 DCHECK(!windowless_);
577 window_ = window;
578 #if defined(OS_MACOSX)
579 // TODO(kbr): remove. http://crbug.com/105344
581 // Lie to ourselves about being windowless even if we got a fake
582 // plugin window handle, so we continue to get input events.
583 windowless_ = true;
584 accepts_input_events_ = true;
585 // We do not really need to notify the page delegate that a plugin
586 // window was created -- so don't.
587 #else
588 accepts_input_events_ = false;
590 #endif // OS_MACOSX
591 } else {
592 DCHECK(!window_); // Make sure not called twice.
593 windowless_ = true;
594 accepts_input_events_ = true;
598 void WebPluginImpl::SetAcceptsInputEvents(bool accepts) {
599 accepts_input_events_ = accepts;
602 void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) {
603 DCHECK_EQ(window, window_);
604 window_ = gfx::kNullPluginWindow;
605 if (render_view_.get())
606 render_frame_->GetRenderWidget()->CleanupWindowInPluginMoves(window);
609 GURL WebPluginImpl::CompleteURL(const char* url) {
610 if (!webframe_) {
611 NOTREACHED();
612 return GURL();
614 // TODO(darin): Is conversion from UTF8 correct here?
615 return webframe_->document().completeURL(WebString::fromUTF8(url));
618 void WebPluginImpl::CancelResource(unsigned long id) {
619 for (size_t i = 0; i < clients_.size(); ++i) {
620 if (clients_[i].id == id) {
621 if (clients_[i].loader.get()) {
622 clients_[i].loader->setDefersLoading(false);
623 clients_[i].loader->cancel();
624 RemoveClient(i);
626 return;
631 bool WebPluginImpl::SetPostData(WebURLRequest* request,
632 const char *buf,
633 uint32 length) {
634 std::vector<std::string> names;
635 std::vector<std::string> values;
636 std::vector<char> body;
637 bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body);
639 for (size_t i = 0; i < names.size(); ++i) {
640 request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
641 WebString::fromUTF8(values[i]));
644 WebString content_type_header = WebString::fromUTF8("Content-Type");
645 const WebString& content_type =
646 request->httpHeaderField(content_type_header);
647 if (content_type.isEmpty()) {
648 request->setHTTPHeaderField(
649 content_type_header,
650 WebString::fromUTF8("application/x-www-form-urlencoded"));
653 WebHTTPBody http_body;
654 if (body.size()) {
655 http_body.initialize();
656 http_body.appendData(WebData(&body[0], body.size()));
658 request->setHTTPBody(http_body);
660 return rv;
663 bool WebPluginImpl::IsValidUrl(const GURL& url, ReferrerValue referrer_flag) {
664 if (referrer_flag == PLUGIN_SRC &&
665 mime_type_ == kFlashPluginSwfMimeType &&
666 url.GetOrigin() != plugin_url_.GetOrigin()) {
667 // Do url check to make sure that there are no @, ;, \ chars in between url
668 // scheme and url path.
669 const char* url_to_check(url.spec().data());
670 url::Parsed parsed;
671 url::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
672 if (parsed.path.begin <= parsed.scheme.end())
673 return true;
674 std::string string_to_search;
675 string_to_search.assign(url_to_check + parsed.scheme.end(),
676 parsed.path.begin - parsed.scheme.end());
677 if (string_to_search.find("@") != std::string::npos ||
678 string_to_search.find(";") != std::string::npos ||
679 string_to_search.find("\\") != std::string::npos)
680 return false;
683 return true;
686 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
687 const char* url,
688 bool is_javascript_url,
689 bool popups_allowed,
690 const char* method,
691 const char* target,
692 const char* buf,
693 unsigned int len,
694 int notify_id,
695 ReferrerValue referrer_flag) {
696 // If there is no target, there is nothing to do
697 if (!target)
698 return NOT_ROUTED;
700 // This could happen if the WebPluginContainer was already deleted.
701 if (!webframe_)
702 return NOT_ROUTED;
704 WebString target_str = WebString::fromUTF8(target);
706 // Take special action for JavaScript URLs
707 if (is_javascript_url) {
708 WebFrame* target_frame =
709 webframe_->view()->findFrameByName(target_str, webframe_);
710 // For security reasons, do not allow JavaScript on frames
711 // other than this frame.
712 if (target_frame != webframe_) {
713 // TODO(darin): Localize this message.
714 const char kMessage[] =
715 "Ignoring cross-frame javascript URL load requested by plugin.";
716 webframe_->addMessageToConsole(
717 WebConsoleMessage(WebConsoleMessage::LevelError,
718 WebString::fromUTF8(kMessage)));
719 return ROUTED;
722 // Route javascript calls back to the plugin.
723 return NOT_ROUTED;
726 // If we got this far, we're routing content to a target frame.
727 // Go fetch the URL.
729 GURL complete_url = CompleteURL(url);
730 // Remove when flash bug is fixed. http://crbug.com/40016.
731 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
732 return INVALID_URL;
734 if (strcmp(method, "GET") != 0) {
735 // We're only going to route HTTP/HTTPS requests
736 if (!complete_url.SchemeIsHTTPOrHTTPS())
737 return INVALID_URL;
740 WebURLRequest request(complete_url);
741 SetReferrer(&request, referrer_flag);
743 request.setHTTPMethod(WebString::fromUTF8(method));
744 request.setFirstPartyForCookies(
745 webframe_->document().firstPartyForCookies());
746 request.setHasUserGesture(popups_allowed);
747 // ServiceWorker is disabled for NPAPI.
748 request.setSkipServiceWorker(true);
749 if (len > 0) {
750 if (!SetPostData(&request, buf, len)) {
751 // Uhoh - we're in trouble. There isn't a good way
752 // to recover at this point. Break out.
753 NOTREACHED();
754 return ROUTED;
758 container_->loadFrameRequest(
759 request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
760 return ROUTED;
763 NPObject* WebPluginImpl::GetWindowScriptNPObject() {
764 if (!webframe_) {
765 NOTREACHED();
766 return NULL;
768 return webframe_->windowObject();
771 NPObject* WebPluginImpl::GetPluginElement() {
772 return container_->scriptableObjectForElement();
775 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) {
776 // Proxy resolving doesn't work in single-process mode.
777 return false;
780 void WebPluginImpl::SetCookie(const GURL& url,
781 const GURL& first_party_for_cookies,
782 const std::string& cookie) {
783 if (!render_view_.get())
784 return;
786 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
787 if (!cookie_jar) {
788 DLOG(WARNING) << "No cookie jar!";
789 return;
792 cookie_jar->setCookie(
793 url, first_party_for_cookies, WebString::fromUTF8(cookie));
796 std::string WebPluginImpl::GetCookies(const GURL& url,
797 const GURL& first_party_for_cookies) {
798 if (!render_view_.get())
799 return std::string();
801 WebCookieJar* cookie_jar = render_frame_->cookie_jar();
802 if (!cookie_jar) {
803 DLOG(WARNING) << "No cookie jar!";
804 return std::string();
807 return base::UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies));
810 void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
811 for (size_t i = 0; i < clients_.size(); ++i) {
812 if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
813 if (clients_[i].loader.get()) {
814 if (allow) {
815 clients_[i].loader->setDefersLoading(false);
816 } else {
817 clients_[i].loader->cancel();
818 if (clients_[i].client)
819 clients_[i].client->DidFail(clients_[i].id);
822 break;
827 bool WebPluginImpl::CheckIfRunInsecureContent(const GURL& url) {
828 if (!webframe_)
829 return true;
831 return webframe_->checkIfRunInsecureContent(url);
834 #if defined(OS_MACOSX)
835 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
836 gfx::GpuPreference gpu_preference) {
837 return NULL;
840 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
843 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width,
844 int32 height,
845 uint32 surface_id) {
846 next_io_surface_allocated_ = true;
847 next_io_surface_width_ = width;
848 next_io_surface_height_ = height;
849 next_io_surface_id_ = surface_id;
852 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
853 if (!container_)
854 return;
855 // Deferring the call to setBackingIOSurfaceId is an attempt to
856 // work around garbage occasionally showing up in the plugin's
857 // area during live resizing of Core Animation plugins. The
858 // assumption was that by the time this was called, the plugin
859 // process would have populated the newly allocated IOSurface. It
860 // is not 100% clear at this point why any garbage is getting
861 // through. More investigation is needed. http://crbug.com/105346
862 if (next_io_surface_allocated_) {
863 if (next_io_surface_id_) {
864 if (!io_surface_layer_.get()) {
865 io_surface_layer_ =
866 cc::IOSurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings());
867 web_layer_.reset(new cc_blink::WebLayerImpl(io_surface_layer_));
868 container_->setWebLayer(web_layer_.get());
870 io_surface_layer_->SetIOSurfaceProperties(
871 next_io_surface_id_,
872 gfx::Size(next_io_surface_width_, next_io_surface_height_));
873 } else {
874 container_->setWebLayer(NULL);
875 web_layer_.reset();
876 io_surface_layer_ = NULL;
878 next_io_surface_allocated_ = false;
879 } else {
880 if (io_surface_layer_.get())
881 io_surface_layer_->SetNeedsDisplay();
884 #endif
886 void WebPluginImpl::Invalidate() {
887 if (container_)
888 container_->invalidate();
891 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
892 if (container_)
893 container_->invalidateRect(rect);
896 void WebPluginImpl::OnDownloadPluginSrcUrl() {
897 HandleURLRequestInternal(
898 plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
899 false, true);
902 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
903 WebURLLoader* loader) {
904 ClientInfo* client_info = GetClientInfoFromLoader(loader);
905 if (client_info)
906 return client_info->client;
907 return NULL;
910 WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
911 WebURLLoader* loader) {
912 for (size_t i = 0; i < clients_.size(); ++i) {
913 if (clients_[i].loader.get() == loader)
914 return &clients_[i];
917 NOTREACHED();
918 return 0;
921 void WebPluginImpl::willSendRequest(WebURLLoader* loader,
922 WebURLRequest& request,
923 const WebURLResponse& response) {
924 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedRedirect
925 // until kDirectNPAPIRequests is the default and we can remove this old path.
926 WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
927 if (client_info) {
928 // Currently this check is just to catch an https -> http redirect when
929 // loading the main plugin src URL. Longer term, we could investigate
930 // firing mixed diplay or scripting issues for subresource loads
931 // initiated by plugins.
932 if (client_info->is_plugin_src_load &&
933 webframe_ &&
934 !webframe_->checkIfRunInsecureContent(request.url())) {
935 loader->cancel();
936 client_info->client->DidFail(client_info->id);
937 return;
939 if (net::HttpResponseHeaders::IsRedirectResponseCode(
940 response.httpStatusCode())) {
941 // If the plugin does not participate in url redirect notifications then
942 // just block cross origin 307 POST redirects.
943 if (!client_info->notify_redirects) {
944 if (response.httpStatusCode() == 307 &&
945 LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
946 GURL original_request_url(response.url());
947 GURL response_url(request.url());
948 if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
949 loader->setDefersLoading(true);
950 loader->cancel();
951 client_info->client->DidFail(client_info->id);
952 return;
955 } else {
956 loader->setDefersLoading(true);
959 client_info->client->WillSendRequest(request.url(),
960 response.httpStatusCode());
964 void WebPluginImpl::didSendData(WebURLLoader* loader,
965 unsigned long long bytes_sent,
966 unsigned long long total_bytes_to_be_sent) {
969 void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
970 const WebURLResponse& response) {
971 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
972 // until kDirectNPAPIRequests is the default and we can remove this old path.
973 static const int kHttpPartialResponseStatusCode = 206;
974 static const int kHttpResponseSuccessStatusCode = 200;
976 WebPluginResourceClient* client = GetClientFromLoader(loader);
977 if (!client)
978 return;
980 ResponseInfo response_info;
981 GetResponseInfo(response, &response_info);
982 ClientInfo* client_info = GetClientInfoFromLoader(loader);
983 if (!client_info)
984 return;
986 bool request_is_seekable = true;
987 if (client->IsMultiByteResponseExpected()) {
988 if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
989 ClientInfo* client_info = GetClientInfoFromLoader(loader);
990 if (!client_info)
991 return;
992 if (HandleHttpMultipartResponse(response, client)) {
993 // Multiple ranges requested, data will be delivered by
994 // MultipartResponseDelegate.
995 client_info->data_offset = 0;
996 return;
998 int64 upper_bound = 0, instance_size = 0;
999 // Single range requested - go through original processing for
1000 // non-multipart requests, but update data offset.
1001 MultipartResponseDelegate::ReadContentRanges(response,
1002 &client_info->data_offset,
1003 &upper_bound,
1004 &instance_size);
1005 } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
1006 RenderThreadImpl::current()->RecordAction(
1007 base::UserMetricsAction("Plugin_200ForByteRange"));
1008 // If the client issued a byte range request and the server responds with
1009 // HTTP 200 OK, it indicates that the server does not support byte range
1010 // requests.
1011 // We need to emulate Firefox behavior by doing the following:-
1012 // 1. Destroy the plugin instance in the plugin process. Ensure that
1013 // existing resource requests initiated for the plugin instance
1014 // continue to remain valid.
1015 // 2. Create a new plugin instance and notify it about the response
1016 // received here.
1017 if (!ReinitializePluginForResponse(loader)) {
1018 NOTREACHED();
1019 return;
1022 // The server does not support byte range requests. No point in creating
1023 // seekable streams.
1024 request_is_seekable = false;
1026 delete client;
1027 client = NULL;
1029 // Create a new resource client for this request.
1030 for (size_t i = 0; i < clients_.size(); ++i) {
1031 if (clients_[i].loader.get() == loader) {
1032 WebPluginResourceClient* resource_client =
1033 delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
1034 clients_[i].client = resource_client;
1035 client = resource_client;
1036 break;
1040 DCHECK(client != NULL);
1044 // Calling into a plugin could result in reentrancy if the plugin yields
1045 // control to the OS like entering a modal loop etc. Prevent this by
1046 // stopping further loading until the plugin notifies us that it is ready to
1047 // accept data
1048 loader->setDefersLoading(true);
1050 client->DidReceiveResponse(
1051 response_info.mime_type,
1052 GetAllHeaders(response),
1053 response_info.expected_length,
1054 response_info.last_modified,
1055 request_is_seekable);
1057 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1058 // error codes in the stream header and as a result, was unaware of the
1059 // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1060 // destroy the stream and invoke the NPP_DestroyStream function on the
1061 // plugin if the HTTP request fails.
1062 const GURL& url = response.url();
1063 if (url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme)) {
1064 if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
1065 // The plugin instance could be in the process of deletion here.
1066 // Verify if the WebPluginResourceClient instance still exists before
1067 // use.
1068 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1069 if (client_info) {
1070 client_info->pending_failure_notification = true;
1076 void WebPluginImpl::didReceiveData(WebURLLoader* loader,
1077 const char *buffer,
1078 int data_length,
1079 int encoded_data_length) {
1080 WebPluginResourceClient* client = GetClientFromLoader(loader);
1081 if (!client)
1082 return;
1084 MultiPartResponseHandlerMap::iterator index =
1085 multi_part_response_map_.find(client);
1086 if (index != multi_part_response_map_.end()) {
1087 MultipartResponseDelegate* multi_part_handler = (*index).second;
1088 DCHECK(multi_part_handler != NULL);
1089 multi_part_handler->OnReceivedData(buffer,
1090 data_length,
1091 encoded_data_length);
1092 } else {
1093 loader->setDefersLoading(true);
1094 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1095 client->DidReceiveData(buffer, data_length, client_info->data_offset);
1096 client_info->data_offset += data_length;
1100 void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
1101 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1102 if (client_info && client_info->client) {
1103 MultiPartResponseHandlerMap::iterator index =
1104 multi_part_response_map_.find(client_info->client);
1105 if (index != multi_part_response_map_.end()) {
1106 delete (*index).second;
1107 multi_part_response_map_.erase(index);
1108 DidStopLoading();
1110 loader->setDefersLoading(true);
1111 WebPluginResourceClient* resource_client = client_info->client;
1112 // The ClientInfo can get deleted in the call to DidFinishLoading below.
1113 // It is not safe to access this structure after that.
1114 client_info->client = NULL;
1115 resource_client->DidFinishLoading(client_info->id);
1119 void WebPluginImpl::didFail(WebURLLoader* loader,
1120 const WebURLError& error) {
1121 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1122 if (client_info && client_info->client) {
1123 loader->setDefersLoading(true);
1124 WebPluginResourceClient* resource_client = client_info->client;
1125 // The ClientInfo can get deleted in the call to DidFail below.
1126 // It is not safe to access this structure after that.
1127 client_info->client = NULL;
1128 resource_client->DidFail(client_info->id);
1132 void WebPluginImpl::RemoveClient(size_t i) {
1133 clients_.erase(clients_.begin() + i);
1136 void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
1137 for (size_t i = 0; i < clients_.size(); ++i) {
1138 if (clients_[i].loader.get() == loader) {
1139 RemoveClient(i);
1140 return;
1145 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
1146 if (!container)
1147 TearDownPluginInstance(NULL);
1148 container_ = container;
1149 if (container_)
1150 container_->allowScriptObjects();
1153 void WebPluginImpl::HandleURLRequest(const char* url,
1154 const char* method,
1155 const char* target,
1156 const char* buf,
1157 unsigned int len,
1158 int notify_id,
1159 bool popups_allowed,
1160 bool notify_redirects) {
1161 // GetURL/PostURL requests initiated explicitly by plugins should specify the
1162 // plugin SRC url as the referrer if it is available.
1163 HandleURLRequestInternal(
1164 url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
1165 notify_redirects, false);
1168 void WebPluginImpl::HandleURLRequestInternal(const char* url,
1169 const char* method,
1170 const char* target,
1171 const char* buf,
1172 unsigned int len,
1173 int notify_id,
1174 bool popups_allowed,
1175 ReferrerValue referrer_flag,
1176 bool notify_redirects,
1177 bool is_plugin_src_load) {
1178 // For this request, we either route the output to a frame
1179 // because a target has been specified, or we handle the request
1180 // here, i.e. by executing the script if it is a javascript url
1181 // or by initiating a download on the URL, etc. There is one special
1182 // case in that the request is a javascript url and the target is "_self",
1183 // in which case we route the output to the plugin rather than routing it
1184 // to the plugin's frame.
1185 bool is_javascript_url =
1186 url::FindAndCompareScheme(url, strlen(url), url::kJavaScriptScheme, NULL);
1187 RoutingStatus routing_status = RouteToFrame(
1188 url, is_javascript_url, popups_allowed, method, target, buf, len,
1189 notify_id, referrer_flag);
1190 if (routing_status == ROUTED)
1191 return;
1193 if (is_javascript_url) {
1194 GURL gurl(url);
1195 WebString result = container_->executeScriptURL(gurl, popups_allowed);
1197 // delegate_ could be NULL because executeScript caused the container to
1198 // be deleted.
1199 if (delegate_) {
1200 delegate_->SendJavaScriptStream(
1201 gurl, result.utf8(), !result.isNull(), notify_id);
1204 return;
1207 unsigned long resource_id = GetNextResourceId();
1208 if (!resource_id)
1209 return;
1211 GURL complete_url = CompleteURL(url);
1212 // Remove when flash bug is fixed. http://crbug.com/40016.
1213 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
1214 return;
1216 // If the RouteToFrame call returned a failure then inform the result
1217 // back to the plugin asynchronously.
1218 if ((routing_status == INVALID_URL) ||
1219 (routing_status == GENERAL_FAILURE)) {
1220 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1221 resource_id, complete_url, notify_id);
1222 if (resource_client)
1223 resource_client->DidFail(resource_id);
1224 return;
1227 // CreateResourceClient() sends a synchronous IPC message so it's possible
1228 // that TearDownPluginInstance() may have been called in the nested
1229 // message loop. If so, don't start the request.
1230 if (!delegate_)
1231 return;
1233 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1234 switches::kDisableDirectNPAPIRequests)) {
1235 // We got here either because the plugin called GetURL/PostURL, or because
1236 // we're fetching the data for an embed tag. If we're in multi-process mode,
1237 // we want to fetch the data in the plugin process as the renderer won't be
1238 // able to request any origin when site isolation is in place. So bounce
1239 // this request back to the plugin process which will use ResourceDispatcher
1240 // to fetch the url.
1242 // TODO(jam): any better way of getting this? Can't find a way to get
1243 // frame()->loader()->outgoingReferrer() which
1244 // WebFrameImpl::setReferrerForRequest does.
1245 WebURLRequest request(complete_url);
1246 SetReferrer(&request, referrer_flag);
1247 Referrer referrer(
1248 GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
1249 request.referrerPolicy());
1251 GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
1252 delegate_->FetchURL(resource_id, notify_id, complete_url,
1253 first_party_for_cookies, method, buf, len, referrer,
1254 notify_redirects, is_plugin_src_load, 0,
1255 render_frame_->GetRoutingID(),
1256 render_view_->GetRoutingID());
1257 } else {
1258 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1259 resource_id, complete_url, notify_id);
1260 if (!resource_client)
1261 return;
1262 InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
1263 len, NULL, referrer_flag, notify_redirects,
1264 is_plugin_src_load);
1268 unsigned long WebPluginImpl::GetNextResourceId() {
1269 if (!webframe_)
1270 return 0;
1271 WebView* view = webframe_->view();
1272 if (!view)
1273 return 0;
1274 return view->createUniqueIdentifierForRequest();
1277 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
1278 WebPluginResourceClient* client,
1279 const GURL& url,
1280 const char* method,
1281 const char* buf,
1282 int buf_len,
1283 const char* range_info,
1284 ReferrerValue referrer_flag,
1285 bool notify_redirects,
1286 bool is_plugin_src_load) {
1287 if (!client) {
1288 NOTREACHED();
1289 return false;
1292 ClientInfo info;
1293 info.id = resource_id;
1294 info.client = client;
1295 info.request.initialize();
1296 info.request.setURL(url);
1297 info.request.setFirstPartyForCookies(
1298 webframe_->document().firstPartyForCookies());
1299 info.request.setRequestorProcessID(delegate_->GetProcessId());
1300 // TODO(mkwst): Is this a request for a plugin object itself
1301 // (RequestContextObject), or a request that the plugin makes
1302 // (RequestContextPlugin)?
1303 info.request.setRequestContext(WebURLRequest::RequestContextPlugin);
1304 info.request.setHTTPMethod(WebString::fromUTF8(method));
1305 // ServiceWorker is disabled for NPAPI.
1306 info.request.setSkipServiceWorker(true);
1307 info.pending_failure_notification = false;
1308 info.notify_redirects = notify_redirects;
1309 info.is_plugin_src_load = is_plugin_src_load;
1310 info.data_offset = 0;
1312 if (range_info) {
1313 info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
1314 WebString::fromUTF8(range_info));
1317 if (strcmp(method, "POST") == 0) {
1318 // Adds headers or form data to a request. This must be called before
1319 // we initiate the actual request.
1320 SetPostData(&info.request, buf, buf_len);
1323 SetReferrer(&info.request, referrer_flag);
1325 WebURLLoaderOptions options;
1326 options.allowCredentials = true;
1327 options.crossOriginRequestPolicy =
1328 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
1329 info.loader.reset(webframe_->createAssociatedURLLoader(options));
1330 if (!info.loader.get())
1331 return false;
1332 info.loader->loadAsynchronously(info.request, &loader_client_);
1334 clients_.push_back(info);
1335 return true;
1338 void WebPluginImpl::CancelDocumentLoad() {
1339 if (webframe_) {
1340 ignore_response_error_ = true;
1341 webframe_->stopLoading();
1345 void WebPluginImpl::InitiateHTTPRangeRequest(
1346 const char* url, const char* range_info, int range_request_id) {
1347 unsigned long resource_id = GetNextResourceId();
1348 if (!resource_id)
1349 return;
1351 GURL complete_url = CompleteURL(url);
1352 // Remove when flash bug is fixed. http://crbug.com/40016.
1353 if (!WebPluginImpl::IsValidUrl(complete_url,
1354 load_manually_ ? NO_REFERRER : PLUGIN_SRC))
1355 return;
1357 WebPluginResourceClient* resource_client =
1358 delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
1359 InitiateHTTPRequest(
1360 resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
1361 load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
1364 void WebPluginImpl::DidStartLoading() {
1365 if (render_view_.get()) {
1366 // TODO(darin): Make is_loading_ be a counter!
1367 render_view_->DidStartLoading();
1371 void WebPluginImpl::DidStopLoading() {
1372 if (render_view_.get()) {
1373 // TODO(darin): Make is_loading_ be a counter!
1374 render_view_->DidStopLoading();
1378 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
1379 bool defer) {
1380 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1381 while (client_index != clients_.end()) {
1382 ClientInfo& client_info = *client_index;
1384 if (client_info.id == resource_id) {
1385 client_info.loader->setDefersLoading(defer);
1387 // If we determined that the request had failed via the HTTP headers
1388 // in the response then we send out a failure notification to the
1389 // plugin process, as certain plugins don't handle HTTP failure codes
1390 // correctly.
1391 if (!defer && client_info.client &&
1392 client_info.pending_failure_notification) {
1393 // The ClientInfo and the iterator can become invalid due to the call
1394 // to DidFail below.
1395 WebPluginResourceClient* resource_client = client_info.client;
1396 client_info.loader->cancel();
1397 clients_.erase(client_index++);
1398 resource_client->DidFail(resource_id);
1400 break;
1402 client_index++;
1406 bool WebPluginImpl::IsOffTheRecord() {
1407 return false;
1410 bool WebPluginImpl::HandleHttpMultipartResponse(
1411 const WebURLResponse& response, WebPluginResourceClient* client) {
1412 std::string multipart_boundary;
1413 if (!MultipartResponseDelegate::ReadMultipartBoundary(
1414 response, &multipart_boundary)) {
1415 return false;
1418 DidStartLoading();
1420 MultiPartResponseClient* multi_part_response_client =
1421 new MultiPartResponseClient(client);
1423 MultipartResponseDelegate* multi_part_response_handler =
1424 new MultipartResponseDelegate(multi_part_response_client, NULL,
1425 response,
1426 multipart_boundary);
1427 multi_part_response_map_[client] = multi_part_response_handler;
1428 return true;
1431 bool WebPluginImpl::ReinitializePluginForResponse(
1432 WebURLLoader* loader) {
1433 WebFrame* webframe = webframe_;
1434 if (!webframe)
1435 return false;
1437 WebView* webview = webframe->view();
1438 if (!webview)
1439 return false;
1441 WebPluginContainer* container_widget = container_;
1443 // Destroy the current plugin instance.
1444 TearDownPluginInstance(loader);
1446 container_ = container_widget;
1447 webframe_ = webframe;
1449 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
1450 this, mime_type_, render_view_, render_frame_);
1452 // Store the plugin's unique identifier, used by the container to track its
1453 // script objects, and enable script objects (since Initialize may use them
1454 // even if it fails).
1455 npp_ = plugin_delegate->GetPluginNPP();
1456 container_->allowScriptObjects();
1458 bool ok = plugin_delegate && plugin_delegate->Initialize(
1459 plugin_url_, arg_names_, arg_values_, load_manually_);
1461 if (!ok) {
1462 container_->clearScriptObjects();
1463 container_ = NULL;
1464 // TODO(iyengar) Should we delete the current plugin instance here?
1465 return false;
1468 delegate_ = plugin_delegate;
1470 // Force a geometry update to occur to ensure that the plugin becomes
1471 // visible.
1472 container_->reportGeometry();
1474 // The plugin move sequences accumulated via DidMove are sent to the browser
1475 // whenever the renderer paints. Force a paint here to ensure that changes
1476 // to the plugin window are propagated to the browser.
1477 container_->invalidate();
1478 return true;
1481 void WebPluginImpl::TearDownPluginInstance(
1482 WebURLLoader* loader_to_ignore) {
1483 // JavaScript garbage collection may cause plugin script object references to
1484 // be retained long after the plugin is destroyed. Some plugins won't cope
1485 // with their objects being released after they've been destroyed, and once
1486 // we've actually unloaded the plugin the object's releaseobject() code may
1487 // no longer be in memory. The container tracks the plugin's objects and lets
1488 // us invalidate them, releasing the references to them held by the JavaScript
1489 // runtime.
1490 if (container_) {
1491 container_->clearScriptObjects();
1492 container_->setWebLayer(NULL);
1495 // Call PluginDestroyed() first to prevent the plugin from calling us back
1496 // in the middle of tearing down the render tree.
1497 if (delegate_) {
1498 // The plugin may call into the browser and pass script objects even during
1499 // teardown, so temporarily re-enable plugin script objects.
1500 DCHECK(container_);
1501 container_->allowScriptObjects();
1503 delegate_->PluginDestroyed();
1504 delegate_ = NULL;
1506 // Invalidate any script objects created during teardown here, before the
1507 // plugin might actually be unloaded.
1508 container_->clearScriptObjects();
1511 // Cancel any pending requests because otherwise this deleted object will
1512 // be called by the ResourceDispatcher.
1513 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1514 while (client_index != clients_.end()) {
1515 ClientInfo& client_info = *client_index;
1517 if (loader_to_ignore == client_info.loader) {
1518 client_index++;
1519 continue;
1522 if (client_info.loader.get())
1523 client_info.loader->cancel();
1525 client_index = clients_.erase(client_index);
1528 // This needs to be called now and not in the destructor since the
1529 // webframe_ might not be valid anymore.
1530 webframe_ = NULL;
1531 weak_factory_.InvalidateWeakPtrs();
1534 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
1535 ReferrerValue referrer_flag) {
1536 switch (referrer_flag) {
1537 case DOCUMENT_URL:
1538 webframe_->setReferrerForRequest(*request, GURL());
1539 break;
1541 case PLUGIN_SRC:
1542 webframe_->setReferrerForRequest(*request, plugin_url_);
1543 break;
1545 default:
1546 break;
1550 } // namespace content