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