Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / child / npapi / plugin_stream_url.cc
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