OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |