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