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