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