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.
5 #include "content/child/npapi/plugin_stream_url.h"
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"
20 PluginStreamUrl::PluginStreamUrl(
21 unsigned long resource_id
,
23 PluginInstance
*instance
,
26 : PluginStream(instance
, url
.spec().c_str(), notify_needed
, notify_data
),
31 void PluginStreamUrl::SetPluginURLFetcher(PluginURLFetcher
* fetcher
) {
32 plugin_url_fetcher_
.reset(fetcher
);
35 void PluginStreamUrl::URLRedirectResponse(bool allow
) {
36 if (plugin_url_fetcher_
.get()) {
37 plugin_url_fetcher_
->URLRedirectResponse(allow
);
39 instance()->webplugin()->URLRedirectResponse(allow
, id_
);
43 UpdateUrl(pending_redirect_url_
.c_str());
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
);
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);
62 bool result
= PluginStream::Close(reason
);
63 instance()->RemoveStream(this);
67 WebPluginResourceClient
* PluginStreamUrl::AsResourceClient() {
68 return static_cast<WebPluginResourceClient
*>(this);
71 void PluginStreamUrl::CancelRequest() {
73 if (plugin_url_fetcher_
.get()) {
74 plugin_url_fetcher_
->Cancel();
76 if (instance()->webplugin()) {
77 instance()->webplugin()->CancelResource(id_
);
82 if (instance()->webplugin()) {
83 for (size_t i
= 0; i
< range_requests_
.size(); ++i
)
84 instance()->webplugin()->CancelResource(range_requests_
[i
]);
87 range_requests_
.clear();
89 STLDeleteElements(&range_request_fetchers_
);
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
,
104 UpdateUrl(url
.spec().c_str());
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);
116 bool opened
= Open(mime_type
,
120 request_is_seekable
);
123 instance()->RemoveStream(this);
125 SetDeferLoading(false);
129 void PluginStreamUrl::DidReceiveData(const char* buffer
, int length
,
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);
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);
147 void PluginStreamUrl::DidFinishLoading(unsigned long resource_id
) {
151 std::vector
<unsigned long>::iterator it_resource
= std::find(
152 range_requests_
.begin(),
153 range_requests_
.end(),
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
);
167 void PluginStreamUrl::DidFail(unsigned long resource_id
) {
168 Close(NPRES_NETWORK_ERR
);
171 bool PluginStreamUrl::IsMultiByteResponseExpected() {
175 int PluginStreamUrl::ResourceId() {
179 PluginStreamUrl::~PluginStreamUrl() {
180 if (!plugin_url_fetcher_
.get() && instance() && instance()->webplugin()) {
181 instance()->webplugin()->ResourceClientDeleted(AsResourceClient());
184 STLDeleteElements(&range_request_fetchers_
);
187 void PluginStreamUrl::AddRangeRequestResourceId(unsigned long resource_id
) {
188 DCHECK_NE(resource_id
, 0u);
189 range_requests_
.push_back(resource_id
);
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.
204 instance()->webplugin()->SetDeferResourceLoading(id_
, value
);
205 for (size_t i
= 0; i
< range_requests_
.size(); ++i
)
206 instance()->webplugin()->SetDeferResourceLoading(range_requests_
[i
],
210 void PluginStreamUrl::UpdateUrl(const char* url
) {
212 free(const_cast<char*>(stream()->url
));
213 stream()->url
= base::strdup(url
);
214 pending_redirect_url_
.clear();
217 } // namespace content