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