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