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/child/npapi/plugin_stream_url.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/stl_util.h"
     10 #include "base/strings/string_util.h"
     11 #include "content/child/npapi/plugin_host.h"
     12 #include "content/child/npapi/plugin_instance.h"
     13 #include "content/child/npapi/plugin_lib.h"
     14 #include "content/child/npapi/plugin_url_fetcher.h"
     15 #include "content/child/npapi/webplugin.h"
     16 #include "net/http/http_response_headers.h"
     17 
     18 namespace content {
     19 
     20 PluginStreamUrl::PluginStreamUrl(
     21     unsigned long resource_id,
     22     const GURL &url,
     23     PluginInstance *instance,
     24     bool notify_needed,
     25     void *notify_data)
     26     : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
     27       url_(url),
     28       id_(resource_id) {
     29 }
     30 
     31 void PluginStreamUrl::SetPluginURLFetcher(PluginURLFetcher* fetcher) {
     32   plugin_url_fetcher_.reset(fetcher);
     33 }
     34 
     35 void PluginStreamUrl::URLRedirectResponse(bool allow) {
     36   if (plugin_url_fetcher_.get()) {
     37     plugin_url_fetcher_->URLRedirectResponse(allow);
     38   } else {
     39     instance()->webplugin()->URLRedirectResponse(allow, id_);
     40   }
     41 
     42   if (allow)
     43     UpdateUrl(pending_redirect_url_.c_str());
     44 }
     45 
     46 void PluginStreamUrl::FetchRange(const std::string& range) {
     47   PluginURLFetcher* range_fetcher = new PluginURLFetcher(
     48       this, url_, plugin_url_fetcher_->first_party_for_cookies(), "GET", NULL,
     49       0, plugin_url_fetcher_->referrer(), range, false, false,
     50       plugin_url_fetcher_->origin_pid(),
     51       plugin_url_fetcher_->render_frame_id(),
     52       plugin_url_fetcher_->render_view_id(), id_,
     53       plugin_url_fetcher_->copy_stream_data());
     54   range_request_fetchers_.push_back(range_fetcher);
     55 }
     56 
     57 bool PluginStreamUrl::Close(NPReason reason) {
     58   // Protect the stream against it being destroyed or the whole plugin instance
     59   // being destroyed within the destroy stream handler.
     60   scoped_refptr<PluginStream> protect(this);
     61   CancelRequest();
     62   bool result = PluginStream::Close(reason);
     63   instance()->RemoveStream(this);
     64   return result;
     65 }
     66 
     67 WebPluginResourceClient* PluginStreamUrl::AsResourceClient() {
     68   return static_cast<WebPluginResourceClient*>(this);
     69 }
     70 
     71 void PluginStreamUrl::CancelRequest() {
     72   if (id_ > 0) {
     73     if (plugin_url_fetcher_.get()) {
     74       plugin_url_fetcher_->Cancel();
     75     } else {
     76       if (instance()->webplugin()) {
     77         instance()->webplugin()->CancelResource(id_);
     78       }
     79     }
     80     id_ = 0;
     81   }
     82   if (instance()->webplugin()) {
     83     for (size_t i = 0; i < range_requests_.size(); ++i)
     84       instance()->webplugin()->CancelResource(range_requests_[i]);
     85   }
     86 
     87   range_requests_.clear();
     88 
     89   STLDeleteElements(&range_request_fetchers_);
     90 }
     91 
     92 void PluginStreamUrl::WillSendRequest(const GURL& url, int http_status_code) {
     93   if (notify_needed()) {
     94     // If the plugin participates in HTTP url redirect handling then notify it.
     95     if (net::HttpResponseHeaders::IsRedirectResponseCode(http_status_code) &&
     96         instance()->handles_url_redirects()) {
     97       pending_redirect_url_ = url.spec();
     98       instance()->NPP_URLRedirectNotify(url.spec().c_str(), http_status_code,
     99           notify_data());
    100       return;
    101     }
    102   }
    103   url_ = url;
    104   UpdateUrl(url.spec().c_str());
    105 }
    106 
    107 void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
    108                                          const std::string& headers,
    109                                          uint32 expected_length,
    110                                          uint32 last_modified,
    111                                          bool request_is_seekable) {
    112   // Protect the stream against it being destroyed or the whole plugin instance
    113   // being destroyed within the new stream handler.
    114   scoped_refptr<PluginStream> protect(this);
    115 
    116   bool opened = Open(mime_type,
    117                      headers,
    118                      expected_length,
    119                      last_modified,
    120                      request_is_seekable);
    121   if (!opened) {
    122     CancelRequest();
    123     instance()->RemoveStream(this);
    124   } else {
    125     SetDeferLoading(false);
    126   }
    127 }
    128 
    129 void PluginStreamUrl::DidReceiveData(const char* buffer, int length,
    130                                      int data_offset) {
    131   if (!open())
    132     return;
    133 
    134   // Protect the stream against it being destroyed or the whole plugin instance
    135   // being destroyed within the write handlers
    136   scoped_refptr<PluginStream> protect(this);
    137 
    138   if (length > 0) {
    139     // The PluginStreamUrl instance could get deleted if the plugin fails to
    140     // accept data in NPP_Write.
    141     if (Write(const_cast<char*>(buffer), length, data_offset) > 0) {
    142       SetDeferLoading(false);
    143     }
    144   }
    145 }
    146 
    147 void PluginStreamUrl::DidFinishLoading(unsigned long resource_id) {
    148   if (!seekable()) {
    149     Close(NPRES_DONE);
    150   } else {
    151     std::vector<unsigned long>::iterator it_resource = std::find(
    152         range_requests_.begin(),
    153         range_requests_.end(),
    154         resource_id);
    155     // Resource id must be known to us - either main resource id, or one
    156     // of the resources, created for range requests.
    157     DCHECK(resource_id == id_ || it_resource != range_requests_.end());
    158     // We should notify the plugin about failed/finished requests to ensure
    159     // that the number of active resource clients does not continue to grow.
    160     if (instance()->webplugin())
    161       instance()->webplugin()->CancelResource(resource_id);
    162     if (it_resource != range_requests_.end())
    163       range_requests_.erase(it_resource);
    164   }
    165 }
    166 
    167 void PluginStreamUrl::DidFail(unsigned long resource_id) {
    168   Close(NPRES_NETWORK_ERR);
    169 }
    170 
    171 bool PluginStreamUrl::IsMultiByteResponseExpected() {
    172   return seekable();
    173 }
    174 
    175 int PluginStreamUrl::ResourceId() {
    176   return id_;
    177 }
    178 
    179 PluginStreamUrl::~PluginStreamUrl() {
    180   if (!plugin_url_fetcher_.get() && instance() && instance()->webplugin()) {
    181     instance()->webplugin()->ResourceClientDeleted(AsResourceClient());
    182   }
    183 
    184   STLDeleteElements(&range_request_fetchers_);
    185 }
    186 
    187 void PluginStreamUrl::AddRangeRequestResourceId(unsigned long resource_id) {
    188   DCHECK_NE(resource_id, 0u);
    189   range_requests_.push_back(resource_id);
    190 }
    191 
    192 void PluginStreamUrl::SetDeferLoading(bool value) {
    193   // If we determined that the request had failed via the HTTP headers in the
    194   // response then we send out a failure notification to the plugin process, as
    195   // certain plugins don't handle HTTP failure codes correctly.
    196   if (plugin_url_fetcher_.get()) {
    197     if (!value && plugin_url_fetcher_->pending_failure_notification()) {
    198       // This object may be deleted now.
    199       DidFail(id_);
    200     }
    201     return;
    202   }
    203   if (id_ > 0)
    204     instance()->webplugin()->SetDeferResourceLoading(id_, value);
    205   for (size_t i = 0; i < range_requests_.size(); ++i)
    206     instance()->webplugin()->SetDeferResourceLoading(range_requests_[i],
    207                                                      value);
    208 }
    209 
    210 void PluginStreamUrl::UpdateUrl(const char* url) {
    211   DCHECK(!open());
    212   free(const_cast<char*>(stream()->url));
    213   stream()->url = base::strdup(url);
    214   pending_redirect_url_.clear();
    215 }
    216 
    217 }  // namespace content
    218