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