IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / child / npapi / plugin_url_fetcher.cc
blob9a1d1d411fa764fafdfd666f2e05ed8e6f977d9c
1 // Copyright (c) 2013 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_url_fetcher.h"
7 #include "content/child/child_thread.h"
8 #include "content/child/npapi/webplugin.h"
9 #include "content/child/npapi/plugin_host.h"
10 #include "content/child/npapi/plugin_instance.h"
11 #include "content/child/npapi/plugin_stream_url.h"
12 #include "content/child/npapi/webplugin_resource_client.h"
13 #include "content/child/plugin_messages.h"
14 #include "content/child/resource_dispatcher.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_response_headers.h"
18 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
19 #include "third_party/WebKit/public/platform/WebURLResponse.h"
20 #include "webkit/child/multipart_response_delegate.h"
21 #include "webkit/child/weburlloader_impl.h"
22 #include "webkit/common/resource_request_body.h"
24 namespace content {
25 namespace {
27 // This class handles individual multipart responses. It is instantiated when
28 // we receive HTTP status code 206 in the HTTP response. This indicates
29 // that the response could have multiple parts each separated by a boundary
30 // specified in the response header.
31 // TODO(jam): this is similar to MultiPartResponseClient in webplugin_impl.cc,
32 // we should remove that other class once we switch to loading from the plugin
33 // process by default.
34 class MultiPartResponseClient : public blink::WebURLLoaderClient {
35 public:
36 explicit MultiPartResponseClient(PluginStreamUrl* plugin_stream)
37 : byte_range_lower_bound_(0), plugin_stream_(plugin_stream) {}
39 // blink::WebURLLoaderClient implementation:
40 virtual void didReceiveResponse(
41 blink::WebURLLoader* loader,
42 const blink::WebURLResponse& response) OVERRIDE {
43 int64 byte_range_upper_bound, instance_size;
44 if (!webkit_glue::MultipartResponseDelegate::ReadContentRanges(
45 response, &byte_range_lower_bound_, &byte_range_upper_bound,
46 &instance_size)) {
47 NOTREACHED();
50 virtual void didReceiveData(blink::WebURLLoader* loader,
51 const char* data,
52 int data_length,
53 int encoded_data_length) OVERRIDE {
54 // TODO(ananta)
55 // We should defer further loads on multipart resources on the same lines
56 // as regular resources requested by plugins to prevent reentrancy.
57 int64 data_offset = byte_range_lower_bound_;
58 byte_range_lower_bound_ += data_length;
59 plugin_stream_->DidReceiveData(data, data_length, data_offset);
60 // DANGER: this instance may be deleted at this point.
63 private:
64 // The lower bound of the byte range.
65 int64 byte_range_lower_bound_;
66 // The handler for the data.
67 PluginStreamUrl* plugin_stream_;
70 } // namespace
72 PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
73 const GURL& url,
74 const GURL& first_party_for_cookies,
75 const std::string& method,
76 const char* buf,
77 unsigned int len,
78 const GURL& referrer,
79 bool notify_redirects,
80 bool is_plugin_src_load,
81 int origin_pid,
82 int render_frame_id,
83 unsigned long resource_id)
84 : plugin_stream_(plugin_stream),
85 url_(url),
86 first_party_for_cookies_(first_party_for_cookies),
87 method_(method),
88 referrer_(referrer),
89 notify_redirects_(notify_redirects),
90 is_plugin_src_load_(is_plugin_src_load),
91 resource_id_(resource_id),
92 data_offset_(0),
93 pending_failure_notification_(false) {
94 webkit_glue::ResourceLoaderBridge::RequestInfo request_info;
95 request_info.method = method;
96 request_info.url = url;
97 request_info.first_party_for_cookies = first_party_for_cookies;
98 request_info.referrer = referrer;
99 request_info.load_flags = net::LOAD_NORMAL;
100 request_info.requestor_pid = origin_pid;
101 request_info.request_type = ResourceType::OBJECT;
102 request_info.routing_id = render_frame_id;
104 std::vector<char> body;
105 if (method == "POST") {
106 bool content_type_found = false;
107 std::vector<std::string> names;
108 std::vector<std::string> values;
109 PluginHost::SetPostData(buf, len, &names, &values, &body);
110 for (size_t i = 0; i < names.size(); ++i) {
111 if (!request_info.headers.empty())
112 request_info.headers += "\r\n";
113 request_info.headers += names[i] + ": " + values[i];
114 if (LowerCaseEqualsASCII(names[i], "content-type"))
115 content_type_found = true;
118 if (!content_type_found) {
119 if (!request_info.headers.empty())
120 request_info.headers += "\r\n";
121 request_info.headers += "Content-Type: application/x-www-form-urlencoded";
125 bridge_.reset(ChildThread::current()->resource_dispatcher()->CreateBridge(
126 request_info));
127 if (!body.empty()) {
128 scoped_refptr<webkit_glue::ResourceRequestBody> request_body =
129 new webkit_glue::ResourceRequestBody;
130 request_body->AppendBytes(&body[0], body.size());
131 bridge_->SetRequestBody(request_body.get());
134 bridge_->Start(this);
136 // TODO(jam): range requests
139 PluginURLFetcher::~PluginURLFetcher() {
142 void PluginURLFetcher::Cancel() {
143 bridge_->Cancel();
146 void PluginURLFetcher::URLRedirectResponse(bool allow) {
147 if (allow) {
148 bridge_->SetDefersLoading(false);
149 } else {
150 bridge_->Cancel();
151 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
155 void PluginURLFetcher::OnUploadProgress(uint64 position, uint64 size) {
158 bool PluginURLFetcher::OnReceivedRedirect(
159 const GURL& new_url,
160 const webkit_glue::ResourceResponseInfo& info,
161 bool* has_new_first_party_for_cookies,
162 GURL* new_first_party_for_cookies) {
163 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::willSendRequest until
164 // kDirectNPAPIRequests is the default and we can remove the old path there.
166 // Currently this check is just to catch an https -> http redirect when
167 // loading the main plugin src URL. Longer term, we could investigate
168 // firing mixed diplay or scripting issues for subresource loads
169 // initiated by plug-ins.
170 if (is_plugin_src_load_ &&
171 !plugin_stream_->instance()->webplugin()->CheckIfRunInsecureContent(
172 new_url)) {
173 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
174 return false;
177 // It's unfortunate that this logic of when a redirect's method changes is
178 // in url_request.cc, but weburlloader_impl.cc and this file have to duplicate
179 // it instead of passing that information.
180 int response_code = info.headers->response_code();
181 if (response_code != 307)
182 method_ = "GET";
183 GURL old_url = url_;
184 url_ = new_url;
185 *has_new_first_party_for_cookies = true;
186 *new_first_party_for_cookies = first_party_for_cookies_;
188 // If the plugin does not participate in url redirect notifications then just
189 // block cross origin 307 POST redirects.
190 if (!notify_redirects_) {
191 if (response_code == 307 && method_ == "POST" &&
192 old_url.GetOrigin() != new_url.GetOrigin()) {
193 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
194 return false;
196 } else {
197 // Pause the request while we ask the plugin what to do about the redirect.
198 bridge_->SetDefersLoading(true);
199 plugin_stream_->WillSendRequest(url_, response_code);
202 return true;
205 void PluginURLFetcher::OnReceivedResponse(
206 const webkit_glue::ResourceResponseInfo& info) {
207 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::didReceiveResponse
208 // GetAllHeaders, and GetResponseInfo until kDirectNPAPIRequests is the
209 // default and we can remove the old path there.
211 bool request_is_seekable = true;
212 DCHECK(!multipart_delegate_.get());
213 if (plugin_stream_->seekable()) {
214 int response_code = info.headers->response_code();
215 if (response_code == 206) {
216 blink::WebURLResponse response;
217 response.initialize();
218 webkit_glue::WebURLLoaderImpl::PopulateURLResponse(url_, info, &response);
220 std::string multipart_boundary;
221 if (webkit_glue::MultipartResponseDelegate::ReadMultipartBoundary(
222 response, &multipart_boundary)) {
223 plugin_stream_->instance()->webplugin()->DidStartLoading();
225 MultiPartResponseClient* multi_part_response_client =
226 new MultiPartResponseClient(plugin_stream_);
228 multipart_delegate_.reset(new webkit_glue::MultipartResponseDelegate(
229 multi_part_response_client, NULL, response, multipart_boundary));
231 // Multiple ranges requested, data will be delivered by
232 // MultipartResponseDelegate.
233 data_offset_ = 0;
234 return;
237 int64 upper_bound = 0, instance_size = 0;
238 // Single range requested - go through original processing for
239 // non-multipart requests, but update data offset.
240 webkit_glue::MultipartResponseDelegate::ReadContentRanges(
241 response, &data_offset_, &upper_bound, &instance_size);
242 } else if (response_code == 200) {
243 // TODO: should we handle this case? We used to but it's not clear that we
244 // still need to. This was bug 5403, fixed in r7139.
248 // If the length comes in as -1, then it indicates that it was not
249 // read off the HTTP headers. We replicate Safari webkit behavior here,
250 // which is to set it to 0.
251 int expected_length = std::max(static_cast<int>(info.content_length), 0);
253 base::Time temp;
254 uint32 last_modified = 0;
255 std::string headers;
256 if (info.headers) { // NULL for data: urls.
257 if (info.headers->GetLastModifiedValue(&temp))
258 last_modified = static_cast<uint32>(temp.ToDoubleT());
260 // TODO(darin): Shouldn't we also report HTTP version numbers?
261 int response_code = info.headers->response_code();
262 headers = base::StringPrintf("HTTP %d ", response_code);
263 headers += info.headers->GetStatusText();
264 headers += "\n";
266 void* iter = NULL;
267 std::string name, value;
268 while (info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
269 // TODO(darin): Should we really exclude headers with an empty value?
270 if (!name.empty() && !value.empty())
271 headers += name + ": " + value + "\n";
274 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
275 // error codes in the stream header and as a result, was unaware of the fate
276 // of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF destroy
277 // the stream and invoke the NPP_DestroyStream function on the plugin if the
278 // HTTPrequest fails.
279 if ((url_.SchemeIs("http") || url_.SchemeIs("https")) &&
280 (response_code < 100 || response_code >= 400)) {
281 pending_failure_notification_ = true;
285 plugin_stream_->DidReceiveResponse(info.mime_type,
286 headers,
287 expected_length,
288 last_modified,
289 request_is_seekable);
292 void PluginURLFetcher::OnDownloadedData(int len,
293 int encoded_data_length) {
296 void PluginURLFetcher::OnReceivedData(const char* data,
297 int data_length,
298 int encoded_data_length) {
299 if (multipart_delegate_) {
300 multipart_delegate_->OnReceivedData(data, data_length, encoded_data_length);
301 } else {
302 int64 offset = data_offset_;
303 data_offset_ += data_length;
304 plugin_stream_->DidReceiveData(data, data_length, offset);
305 // DANGER: this instance may be deleted at this point.
309 void PluginURLFetcher::OnCompletedRequest(
310 int error_code,
311 bool was_ignored_by_handler,
312 const std::string& security_info,
313 const base::TimeTicks& completion_time) {
314 if (multipart_delegate_) {
315 multipart_delegate_->OnCompletedRequest();
316 multipart_delegate_.reset();
319 if (error_code == net::OK) {
320 plugin_stream_->DidFinishLoading(resource_id_);
321 } else {
322 plugin_stream_->DidFail(resource_id_);
326 } // namespace content