Add ICU message format support
[chromium-blink-merge.git] / content / renderer / npapi / webplugin_impl.cc
blobbb42af96991053b25e8a0be9438f46e81242cf6e
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 !base::EqualsASCII(base::StringPiece16(content_encoding), "identity")) {
212 // Don't send the compressed content length to the plugin, which only
213 // cares about the decoded length.
214 response_info->expected_length = 0;
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(base::StringPiece16(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(base::StringPiece16(
808 cookie_jar->cookies(url, first_party_for_cookies)));
811 void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
812 for (size_t i = 0; i < clients_.size(); ++i) {
813 if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
814 if (clients_[i].loader.get()) {
815 if (allow) {
816 clients_[i].loader->setDefersLoading(false);
817 } else {
818 clients_[i].loader->cancel();
819 if (clients_[i].client)
820 clients_[i].client->DidFail(clients_[i].id);
823 break;
828 bool WebPluginImpl::CheckIfRunInsecureContent(const GURL& url) {
829 if (!webframe_)
830 return true;
832 return webframe_->checkIfRunInsecureContent(url);
835 #if defined(OS_MACOSX)
836 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface(
837 gfx::GpuPreference gpu_preference) {
838 return NULL;
841 void WebPluginImpl::AcceleratedPluginEnabledRendering() {
844 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32 width,
845 int32 height,
846 uint32 surface_id) {
847 next_io_surface_allocated_ = true;
848 next_io_surface_width_ = width;
849 next_io_surface_height_ = height;
850 next_io_surface_id_ = surface_id;
853 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() {
854 if (!container_)
855 return;
856 // Deferring the call to setBackingIOSurfaceId is an attempt to
857 // work around garbage occasionally showing up in the plugin's
858 // area during live resizing of Core Animation plugins. The
859 // assumption was that by the time this was called, the plugin
860 // process would have populated the newly allocated IOSurface. It
861 // is not 100% clear at this point why any garbage is getting
862 // through. More investigation is needed. http://crbug.com/105346
863 if (next_io_surface_allocated_) {
864 if (next_io_surface_id_) {
865 if (!io_surface_layer_.get()) {
866 io_surface_layer_ =
867 cc::IOSurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings());
868 web_layer_.reset(new cc_blink::WebLayerImpl(io_surface_layer_));
869 container_->setWebLayer(web_layer_.get());
871 io_surface_layer_->SetIOSurfaceProperties(
872 next_io_surface_id_,
873 gfx::Size(next_io_surface_width_, next_io_surface_height_));
874 } else {
875 container_->setWebLayer(NULL);
876 web_layer_.reset();
877 io_surface_layer_ = NULL;
879 next_io_surface_allocated_ = false;
880 } else {
881 if (io_surface_layer_.get())
882 io_surface_layer_->SetNeedsDisplay();
885 #endif
887 void WebPluginImpl::Invalidate() {
888 if (container_)
889 container_->invalidate();
892 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
893 if (container_)
894 container_->invalidateRect(rect);
897 void WebPluginImpl::OnDownloadPluginSrcUrl() {
898 HandleURLRequestInternal(
899 plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
900 false, true);
903 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
904 WebURLLoader* loader) {
905 ClientInfo* client_info = GetClientInfoFromLoader(loader);
906 if (client_info)
907 return client_info->client;
908 return NULL;
911 WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
912 WebURLLoader* loader) {
913 for (size_t i = 0; i < clients_.size(); ++i) {
914 if (clients_[i].loader.get() == loader)
915 return &clients_[i];
918 NOTREACHED();
919 return 0;
922 void WebPluginImpl::willSendRequest(WebURLLoader* loader,
923 WebURLRequest& request,
924 const WebURLResponse& response) {
925 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedRedirect
926 // until kDirectNPAPIRequests is the default and we can remove this old path.
927 WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
928 if (client_info) {
929 // Currently this check is just to catch an https -> http redirect when
930 // loading the main plugin src URL. Longer term, we could investigate
931 // firing mixed diplay or scripting issues for subresource loads
932 // initiated by plugins.
933 if (client_info->is_plugin_src_load &&
934 webframe_ &&
935 !webframe_->checkIfRunInsecureContent(request.url())) {
936 loader->cancel();
937 client_info->client->DidFail(client_info->id);
938 return;
940 if (net::HttpResponseHeaders::IsRedirectResponseCode(
941 response.httpStatusCode())) {
942 // If the plugin does not participate in url redirect notifications then
943 // just block cross origin 307 POST redirects.
944 if (!client_info->notify_redirects) {
945 if (response.httpStatusCode() == 307 &&
946 base::LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
947 GURL original_request_url(response.url());
948 GURL response_url(request.url());
949 if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
950 loader->setDefersLoading(true);
951 loader->cancel();
952 client_info->client->DidFail(client_info->id);
953 return;
956 } else {
957 loader->setDefersLoading(true);
960 client_info->client->WillSendRequest(request.url(),
961 response.httpStatusCode());
965 void WebPluginImpl::didSendData(WebURLLoader* loader,
966 unsigned long long bytes_sent,
967 unsigned long long total_bytes_to_be_sent) {
970 void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
971 const WebURLResponse& response) {
972 // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
973 // until kDirectNPAPIRequests is the default and we can remove this old path.
974 static const int kHttpPartialResponseStatusCode = 206;
975 static const int kHttpResponseSuccessStatusCode = 200;
977 WebPluginResourceClient* client = GetClientFromLoader(loader);
978 if (!client)
979 return;
981 ResponseInfo response_info;
982 GetResponseInfo(response, &response_info);
983 ClientInfo* client_info = GetClientInfoFromLoader(loader);
984 if (!client_info)
985 return;
987 bool request_is_seekable = true;
988 if (client->IsMultiByteResponseExpected()) {
989 if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
990 ClientInfo* client_info = GetClientInfoFromLoader(loader);
991 if (!client_info)
992 return;
993 if (HandleHttpMultipartResponse(response, client)) {
994 // Multiple ranges requested, data will be delivered by
995 // MultipartResponseDelegate.
996 client_info->data_offset = 0;
997 return;
999 int64 upper_bound = 0, instance_size = 0;
1000 // Single range requested - go through original processing for
1001 // non-multipart requests, but update data offset.
1002 MultipartResponseDelegate::ReadContentRanges(response,
1003 &client_info->data_offset,
1004 &upper_bound,
1005 &instance_size);
1006 } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
1007 RenderThreadImpl::current()->RecordAction(
1008 base::UserMetricsAction("Plugin_200ForByteRange"));
1009 // If the client issued a byte range request and the server responds with
1010 // HTTP 200 OK, it indicates that the server does not support byte range
1011 // requests.
1012 // We need to emulate Firefox behavior by doing the following:-
1013 // 1. Destroy the plugin instance in the plugin process. Ensure that
1014 // existing resource requests initiated for the plugin instance
1015 // continue to remain valid.
1016 // 2. Create a new plugin instance and notify it about the response
1017 // received here.
1018 if (!ReinitializePluginForResponse(loader)) {
1019 NOTREACHED();
1020 return;
1023 // The server does not support byte range requests. No point in creating
1024 // seekable streams.
1025 request_is_seekable = false;
1027 delete client;
1028 client = NULL;
1030 // Create a new resource client for this request.
1031 for (size_t i = 0; i < clients_.size(); ++i) {
1032 if (clients_[i].loader.get() == loader) {
1033 WebPluginResourceClient* resource_client =
1034 delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
1035 clients_[i].client = resource_client;
1036 client = resource_client;
1037 break;
1041 DCHECK(client != NULL);
1045 // Calling into a plugin could result in reentrancy if the plugin yields
1046 // control to the OS like entering a modal loop etc. Prevent this by
1047 // stopping further loading until the plugin notifies us that it is ready to
1048 // accept data
1049 loader->setDefersLoading(true);
1051 client->DidReceiveResponse(
1052 response_info.mime_type,
1053 GetAllHeaders(response),
1054 response_info.expected_length,
1055 response_info.last_modified,
1056 request_is_seekable);
1058 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
1059 // error codes in the stream header and as a result, was unaware of the
1060 // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
1061 // destroy the stream and invoke the NPP_DestroyStream function on the
1062 // plugin if the HTTP request fails.
1063 const GURL& url = response.url();
1064 if (url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme)) {
1065 if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
1066 // The plugin instance could be in the process of deletion here.
1067 // Verify if the WebPluginResourceClient instance still exists before
1068 // use.
1069 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1070 if (client_info) {
1071 client_info->pending_failure_notification = true;
1077 void WebPluginImpl::didReceiveData(WebURLLoader* loader,
1078 const char *buffer,
1079 int data_length,
1080 int encoded_data_length) {
1081 WebPluginResourceClient* client = GetClientFromLoader(loader);
1082 if (!client)
1083 return;
1085 MultiPartResponseHandlerMap::iterator index =
1086 multi_part_response_map_.find(client);
1087 if (index != multi_part_response_map_.end()) {
1088 MultipartResponseDelegate* multi_part_handler = (*index).second;
1089 DCHECK(multi_part_handler != NULL);
1090 multi_part_handler->OnReceivedData(buffer,
1091 data_length,
1092 encoded_data_length);
1093 } else {
1094 loader->setDefersLoading(true);
1095 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1096 client->DidReceiveData(buffer, data_length, client_info->data_offset);
1097 client_info->data_offset += data_length;
1101 void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
1102 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1103 if (client_info && client_info->client) {
1104 MultiPartResponseHandlerMap::iterator index =
1105 multi_part_response_map_.find(client_info->client);
1106 if (index != multi_part_response_map_.end()) {
1107 delete (*index).second;
1108 multi_part_response_map_.erase(index);
1109 DidStopLoading();
1111 loader->setDefersLoading(true);
1112 WebPluginResourceClient* resource_client = client_info->client;
1113 // The ClientInfo can get deleted in the call to DidFinishLoading below.
1114 // It is not safe to access this structure after that.
1115 client_info->client = NULL;
1116 resource_client->DidFinishLoading(client_info->id);
1120 void WebPluginImpl::didFail(WebURLLoader* loader,
1121 const WebURLError& error) {
1122 ClientInfo* client_info = GetClientInfoFromLoader(loader);
1123 if (client_info && client_info->client) {
1124 loader->setDefersLoading(true);
1125 WebPluginResourceClient* resource_client = client_info->client;
1126 // The ClientInfo can get deleted in the call to DidFail below.
1127 // It is not safe to access this structure after that.
1128 client_info->client = NULL;
1129 resource_client->DidFail(client_info->id);
1133 void WebPluginImpl::RemoveClient(size_t i) {
1134 clients_.erase(clients_.begin() + i);
1137 void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
1138 for (size_t i = 0; i < clients_.size(); ++i) {
1139 if (clients_[i].loader.get() == loader) {
1140 RemoveClient(i);
1141 return;
1146 void WebPluginImpl::SetContainer(WebPluginContainer* container) {
1147 if (!container)
1148 TearDownPluginInstance(NULL);
1149 container_ = container;
1150 if (container_)
1151 container_->allowScriptObjects();
1154 void WebPluginImpl::HandleURLRequest(const char* url,
1155 const char* method,
1156 const char* target,
1157 const char* buf,
1158 unsigned int len,
1159 int notify_id,
1160 bool popups_allowed,
1161 bool notify_redirects) {
1162 // GetURL/PostURL requests initiated explicitly by plugins should specify the
1163 // plugin SRC url as the referrer if it is available.
1164 HandleURLRequestInternal(
1165 url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
1166 notify_redirects, false);
1169 void WebPluginImpl::HandleURLRequestInternal(const char* url,
1170 const char* method,
1171 const char* target,
1172 const char* buf,
1173 unsigned int len,
1174 int notify_id,
1175 bool popups_allowed,
1176 ReferrerValue referrer_flag,
1177 bool notify_redirects,
1178 bool is_plugin_src_load) {
1179 // For this request, we either route the output to a frame
1180 // because a target has been specified, or we handle the request
1181 // here, i.e. by executing the script if it is a javascript url
1182 // or by initiating a download on the URL, etc. There is one special
1183 // case in that the request is a javascript url and the target is "_self",
1184 // in which case we route the output to the plugin rather than routing it
1185 // to the plugin's frame.
1186 bool is_javascript_url =
1187 url::FindAndCompareScheme(url, strlen(url), url::kJavaScriptScheme, NULL);
1188 RoutingStatus routing_status = RouteToFrame(
1189 url, is_javascript_url, popups_allowed, method, target, buf, len,
1190 notify_id, referrer_flag);
1191 if (routing_status == ROUTED)
1192 return;
1194 if (is_javascript_url) {
1195 GURL gurl(url);
1196 WebString result = container_->executeScriptURL(gurl, popups_allowed);
1198 // delegate_ could be NULL because executeScript caused the container to
1199 // be deleted.
1200 if (delegate_) {
1201 delegate_->SendJavaScriptStream(
1202 gurl, result.utf8(), !result.isNull(), notify_id);
1205 return;
1208 unsigned long resource_id = GetNextResourceId();
1209 if (!resource_id)
1210 return;
1212 GURL complete_url = CompleteURL(url);
1213 // Remove when flash bug is fixed. http://crbug.com/40016.
1214 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
1215 return;
1217 // If the RouteToFrame call returned a failure then inform the result
1218 // back to the plugin asynchronously.
1219 if ((routing_status == INVALID_URL) ||
1220 (routing_status == GENERAL_FAILURE)) {
1221 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1222 resource_id, complete_url, notify_id);
1223 if (resource_client)
1224 resource_client->DidFail(resource_id);
1225 return;
1228 // CreateResourceClient() sends a synchronous IPC message so it's possible
1229 // that TearDownPluginInstance() may have been called in the nested
1230 // message loop. If so, don't start the request.
1231 if (!delegate_)
1232 return;
1234 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1235 switches::kDisableDirectNPAPIRequests)) {
1236 // We got here either because the plugin called GetURL/PostURL, or because
1237 // we're fetching the data for an embed tag. If we're in multi-process mode,
1238 // we want to fetch the data in the plugin process as the renderer won't be
1239 // able to request any origin when site isolation is in place. So bounce
1240 // this request back to the plugin process which will use ResourceDispatcher
1241 // to fetch the url.
1243 // TODO(jam): any better way of getting this? Can't find a way to get
1244 // frame()->loader()->outgoingReferrer() which
1245 // WebFrameImpl::setReferrerForRequest does.
1246 WebURLRequest request(complete_url);
1247 SetReferrer(&request, referrer_flag);
1248 Referrer referrer(
1249 GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
1250 request.referrerPolicy());
1252 GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
1253 delegate_->FetchURL(resource_id, notify_id, complete_url,
1254 first_party_for_cookies, method, buf, len, referrer,
1255 notify_redirects, is_plugin_src_load, 0,
1256 render_frame_->GetRoutingID(),
1257 render_view_->GetRoutingID());
1258 } else {
1259 WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
1260 resource_id, complete_url, notify_id);
1261 if (!resource_client)
1262 return;
1263 InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
1264 len, NULL, referrer_flag, notify_redirects,
1265 is_plugin_src_load);
1269 unsigned long WebPluginImpl::GetNextResourceId() {
1270 if (!webframe_)
1271 return 0;
1272 WebView* view = webframe_->view();
1273 if (!view)
1274 return 0;
1275 return view->createUniqueIdentifierForRequest();
1278 bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
1279 WebPluginResourceClient* client,
1280 const GURL& url,
1281 const char* method,
1282 const char* buf,
1283 int buf_len,
1284 const char* range_info,
1285 ReferrerValue referrer_flag,
1286 bool notify_redirects,
1287 bool is_plugin_src_load) {
1288 if (!client) {
1289 NOTREACHED();
1290 return false;
1293 ClientInfo info;
1294 info.id = resource_id;
1295 info.client = client;
1296 info.request.initialize();
1297 info.request.setURL(url);
1298 info.request.setFirstPartyForCookies(
1299 webframe_->document().firstPartyForCookies());
1300 info.request.setRequestorProcessID(delegate_->GetProcessId());
1301 // TODO(mkwst): Is this a request for a plugin object itself
1302 // (RequestContextObject), or a request that the plugin makes
1303 // (RequestContextPlugin)?
1304 info.request.setRequestContext(WebURLRequest::RequestContextPlugin);
1305 info.request.setHTTPMethod(WebString::fromUTF8(method));
1306 // ServiceWorker is disabled for NPAPI.
1307 info.request.setSkipServiceWorker(true);
1308 info.pending_failure_notification = false;
1309 info.notify_redirects = notify_redirects;
1310 info.is_plugin_src_load = is_plugin_src_load;
1311 info.data_offset = 0;
1313 if (range_info) {
1314 info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
1315 WebString::fromUTF8(range_info));
1318 if (strcmp(method, "POST") == 0) {
1319 // Adds headers or form data to a request. This must be called before
1320 // we initiate the actual request.
1321 SetPostData(&info.request, buf, buf_len);
1324 SetReferrer(&info.request, referrer_flag);
1326 WebURLLoaderOptions options;
1327 options.allowCredentials = true;
1328 options.crossOriginRequestPolicy =
1329 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
1330 info.loader.reset(webframe_->createAssociatedURLLoader(options));
1331 if (!info.loader.get())
1332 return false;
1333 info.loader->loadAsynchronously(info.request, &loader_client_);
1335 clients_.push_back(info);
1336 return true;
1339 void WebPluginImpl::CancelDocumentLoad() {
1340 if (webframe_) {
1341 ignore_response_error_ = true;
1342 webframe_->stopLoading();
1346 void WebPluginImpl::InitiateHTTPRangeRequest(
1347 const char* url, const char* range_info, int range_request_id) {
1348 unsigned long resource_id = GetNextResourceId();
1349 if (!resource_id)
1350 return;
1352 GURL complete_url = CompleteURL(url);
1353 // Remove when flash bug is fixed. http://crbug.com/40016.
1354 if (!WebPluginImpl::IsValidUrl(complete_url,
1355 load_manually_ ? NO_REFERRER : PLUGIN_SRC))
1356 return;
1358 WebPluginResourceClient* resource_client =
1359 delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
1360 InitiateHTTPRequest(
1361 resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
1362 load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
1365 void WebPluginImpl::DidStartLoading() {
1366 if (render_view_.get()) {
1367 // TODO(darin): Make is_loading_ be a counter!
1368 render_view_->DidStartLoading();
1372 void WebPluginImpl::DidStopLoading() {
1373 if (render_view_.get()) {
1374 // TODO(darin): Make is_loading_ be a counter!
1375 render_view_->DidStopLoading();
1379 void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
1380 bool defer) {
1381 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1382 while (client_index != clients_.end()) {
1383 ClientInfo& client_info = *client_index;
1385 if (client_info.id == resource_id) {
1386 client_info.loader->setDefersLoading(defer);
1388 // If we determined that the request had failed via the HTTP headers
1389 // in the response then we send out a failure notification to the
1390 // plugin process, as certain plugins don't handle HTTP failure codes
1391 // correctly.
1392 if (!defer && client_info.client &&
1393 client_info.pending_failure_notification) {
1394 // The ClientInfo and the iterator can become invalid due to the call
1395 // to DidFail below.
1396 WebPluginResourceClient* resource_client = client_info.client;
1397 client_info.loader->cancel();
1398 clients_.erase(client_index++);
1399 resource_client->DidFail(resource_id);
1401 break;
1403 client_index++;
1407 bool WebPluginImpl::IsOffTheRecord() {
1408 return false;
1411 bool WebPluginImpl::HandleHttpMultipartResponse(
1412 const WebURLResponse& response, WebPluginResourceClient* client) {
1413 std::string multipart_boundary;
1414 if (!MultipartResponseDelegate::ReadMultipartBoundary(
1415 response, &multipart_boundary)) {
1416 return false;
1419 DidStartLoading();
1421 MultiPartResponseClient* multi_part_response_client =
1422 new MultiPartResponseClient(client);
1424 MultipartResponseDelegate* multi_part_response_handler =
1425 new MultipartResponseDelegate(multi_part_response_client, NULL,
1426 response,
1427 multipart_boundary);
1428 multi_part_response_map_[client] = multi_part_response_handler;
1429 return true;
1432 bool WebPluginImpl::ReinitializePluginForResponse(
1433 WebURLLoader* loader) {
1434 WebFrame* webframe = webframe_;
1435 if (!webframe)
1436 return false;
1438 WebView* webview = webframe->view();
1439 if (!webview)
1440 return false;
1442 WebPluginContainer* container_widget = container_;
1444 // Destroy the current plugin instance.
1445 TearDownPluginInstance(loader);
1447 container_ = container_widget;
1448 webframe_ = webframe;
1450 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy(
1451 this, mime_type_, render_view_, render_frame_);
1453 // Store the plugin's unique identifier, used by the container to track its
1454 // script objects, and enable script objects (since Initialize may use them
1455 // even if it fails).
1456 npp_ = plugin_delegate->GetPluginNPP();
1457 container_->allowScriptObjects();
1459 bool ok = plugin_delegate && plugin_delegate->Initialize(
1460 plugin_url_, arg_names_, arg_values_, load_manually_);
1462 if (!ok) {
1463 container_->clearScriptObjects();
1464 container_ = NULL;
1465 // TODO(iyengar) Should we delete the current plugin instance here?
1466 return false;
1469 delegate_ = plugin_delegate;
1471 // Force a geometry update to occur to ensure that the plugin becomes
1472 // visible.
1473 container_->reportGeometry();
1475 // The plugin move sequences accumulated via DidMove are sent to the browser
1476 // whenever the renderer paints. Force a paint here to ensure that changes
1477 // to the plugin window are propagated to the browser.
1478 container_->invalidate();
1479 return true;
1482 void WebPluginImpl::TearDownPluginInstance(
1483 WebURLLoader* loader_to_ignore) {
1484 // JavaScript garbage collection may cause plugin script object references to
1485 // be retained long after the plugin is destroyed. Some plugins won't cope
1486 // with their objects being released after they've been destroyed, and once
1487 // we've actually unloaded the plugin the object's releaseobject() code may
1488 // no longer be in memory. The container tracks the plugin's objects and lets
1489 // us invalidate them, releasing the references to them held by the JavaScript
1490 // runtime.
1491 if (container_) {
1492 container_->clearScriptObjects();
1493 container_->setWebLayer(NULL);
1496 // Call PluginDestroyed() first to prevent the plugin from calling us back
1497 // in the middle of tearing down the render tree.
1498 if (delegate_) {
1499 // The plugin may call into the browser and pass script objects even during
1500 // teardown, so temporarily re-enable plugin script objects.
1501 DCHECK(container_);
1502 container_->allowScriptObjects();
1504 delegate_->PluginDestroyed();
1505 delegate_ = NULL;
1507 // Invalidate any script objects created during teardown here, before the
1508 // plugin might actually be unloaded.
1509 container_->clearScriptObjects();
1512 // Cancel any pending requests because otherwise this deleted object will
1513 // be called by the ResourceDispatcher.
1514 std::vector<ClientInfo>::iterator client_index = clients_.begin();
1515 while (client_index != clients_.end()) {
1516 ClientInfo& client_info = *client_index;
1518 if (loader_to_ignore == client_info.loader) {
1519 client_index++;
1520 continue;
1523 if (client_info.loader.get())
1524 client_info.loader->cancel();
1526 client_index = clients_.erase(client_index);
1529 // This needs to be called now and not in the destructor since the
1530 // webframe_ might not be valid anymore.
1531 webframe_ = NULL;
1532 weak_factory_.InvalidateWeakPtrs();
1535 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
1536 ReferrerValue referrer_flag) {
1537 switch (referrer_flag) {
1538 case DOCUMENT_URL:
1539 webframe_->setReferrerForRequest(*request, GURL());
1540 break;
1542 case PLUGIN_SRC:
1543 webframe_->setReferrerForRequest(*request, plugin_url_);
1544 break;
1546 default:
1547 break;
1551 } // namespace content