• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PluginStreamUrl(unsigned long resource_id,const GURL & url,PluginInstance * instance,bool notify_needed,void * notify_data)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 
SetPluginURLFetcher(PluginURLFetcher * fetcher)31 void PluginStreamUrl::SetPluginURLFetcher(PluginURLFetcher* fetcher) {
32   plugin_url_fetcher_.reset(fetcher);
33 }
34 
URLRedirectResponse(bool allow)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 
FetchRange(const std::string & range)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 
Close(NPReason reason)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 
AsResourceClient()67 WebPluginResourceClient* PluginStreamUrl::AsResourceClient() {
68   return static_cast<WebPluginResourceClient*>(this);
69 }
70 
CancelRequest()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 
WillSendRequest(const GURL & url,int http_status_code)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 
DidReceiveResponse(const std::string & mime_type,const std::string & headers,uint32 expected_length,uint32 last_modified,bool request_is_seekable)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 
DidReceiveData(const char * buffer,int length,int data_offset)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 
DidFinishLoading(unsigned long resource_id)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 
DidFail(unsigned long resource_id)167 void PluginStreamUrl::DidFail(unsigned long resource_id) {
168   Close(NPRES_NETWORK_ERR);
169 }
170 
IsMultiByteResponseExpected()171 bool PluginStreamUrl::IsMultiByteResponseExpected() {
172   return seekable();
173 }
174 
ResourceId()175 int PluginStreamUrl::ResourceId() {
176   return id_;
177 }
178 
~PluginStreamUrl()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 
AddRangeRequestResourceId(unsigned long resource_id)187 void PluginStreamUrl::AddRangeRequestResourceId(unsigned long resource_id) {
188   DCHECK_NE(resource_id, 0u);
189   range_requests_.push_back(resource_id);
190 }
191 
SetDeferLoading(bool value)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 
UpdateUrl(const char * url)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