Removing uses of X11 native key events.
[chromium-blink-merge.git] / content / child / npapi / plugin_url_fetcher.cc
blob6a6fc100e7fee79673f7193f7d43a1527accec57
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 "base/memory/scoped_ptr.h"
8 #include "content/child/child_thread.h"
9 #include "content/child/multipart_response_delegate.h"
10 #include "content/child/npapi/plugin_host.h"
11 #include "content/child/npapi/plugin_instance.h"
12 #include "content/child/npapi/plugin_stream_url.h"
13 #include "content/child/npapi/webplugin.h"
14 #include "content/child/npapi/webplugin_resource_client.h"
15 #include "content/child/plugin_messages.h"
16 #include "content/child/request_extra_data.h"
17 #include "content/child/request_info.h"
18 #include "content/child/resource_dispatcher.h"
19 #include "content/child/resource_loader_bridge.h"
20 #include "content/child/web_url_loader_impl.h"
21 #include "content/common/resource_request_body.h"
22 #include "content/common/service_worker/service_worker_types.h"
23 #include "content/public/common/resource_response_info.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/net_errors.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/redirect_info.h"
28 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
29 #include "third_party/WebKit/public/platform/WebURLResponse.h"
31 namespace content {
32 namespace {
34 // This class handles individual multipart responses. It is instantiated when
35 // we receive HTTP status code 206 in the HTTP response. This indicates
36 // that the response could have multiple parts each separated by a boundary
37 // specified in the response header.
38 // TODO(jam): this is similar to MultiPartResponseClient in webplugin_impl.cc,
39 // we should remove that other class once we switch to loading from the plugin
40 // process by default.
41 class MultiPartResponseClient : public blink::WebURLLoaderClient {
42 public:
43 explicit MultiPartResponseClient(PluginStreamUrl* plugin_stream)
44 : byte_range_lower_bound_(0), plugin_stream_(plugin_stream) {}
46 // blink::WebURLLoaderClient implementation:
47 virtual void didReceiveResponse(
48 blink::WebURLLoader* loader,
49 const blink::WebURLResponse& response) OVERRIDE {
50 int64 byte_range_upper_bound, instance_size;
51 if (!MultipartResponseDelegate::ReadContentRanges(response,
52 &byte_range_lower_bound_,
53 &byte_range_upper_bound,
54 &instance_size)) {
55 NOTREACHED();
58 virtual void didReceiveData(blink::WebURLLoader* loader,
59 const char* data,
60 int data_length,
61 int encoded_data_length) OVERRIDE {
62 // TODO(ananta)
63 // We should defer further loads on multipart resources on the same lines
64 // as regular resources requested by plugins to prevent reentrancy.
65 int64 data_offset = byte_range_lower_bound_;
66 byte_range_lower_bound_ += data_length;
67 plugin_stream_->DidReceiveData(data, data_length, data_offset);
68 // DANGER: this instance may be deleted at this point.
71 private:
72 // The lower bound of the byte range.
73 int64 byte_range_lower_bound_;
74 // The handler for the data.
75 PluginStreamUrl* plugin_stream_;
78 } // namespace
80 PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
81 const GURL& url,
82 const GURL& first_party_for_cookies,
83 const std::string& method,
84 const char* buf,
85 unsigned int len,
86 const GURL& referrer,
87 const std::string& range,
88 bool notify_redirects,
89 bool is_plugin_src_load,
90 int origin_pid,
91 int render_frame_id,
92 int render_view_id,
93 unsigned long resource_id,
94 bool copy_stream_data)
95 : plugin_stream_(plugin_stream),
96 url_(url),
97 first_party_for_cookies_(first_party_for_cookies),
98 referrer_(referrer),
99 notify_redirects_(notify_redirects),
100 is_plugin_src_load_(is_plugin_src_load),
101 origin_pid_(origin_pid),
102 render_frame_id_(render_frame_id),
103 render_view_id_(render_view_id),
104 resource_id_(resource_id),
105 copy_stream_data_(copy_stream_data),
106 data_offset_(0),
107 pending_failure_notification_(false) {
108 RequestInfo request_info;
109 request_info.method = method;
110 request_info.url = url;
111 request_info.first_party_for_cookies = first_party_for_cookies;
112 request_info.referrer = referrer;
113 request_info.load_flags = net::LOAD_NORMAL;
114 request_info.requestor_pid = origin_pid;
115 request_info.request_type = RESOURCE_TYPE_OBJECT;
116 request_info.routing_id = render_view_id;
118 RequestExtraData extra_data;
119 extra_data.set_render_frame_id(render_frame_id);
120 extra_data.set_is_main_frame(false);
121 request_info.extra_data = &extra_data;
123 std::vector<char> body;
124 if (method == "POST") {
125 bool content_type_found = false;
126 std::vector<std::string> names;
127 std::vector<std::string> values;
128 PluginHost::SetPostData(buf, len, &names, &values, &body);
129 for (size_t i = 0; i < names.size(); ++i) {
130 if (!request_info.headers.empty())
131 request_info.headers += "\r\n";
132 request_info.headers += names[i] + ": " + values[i];
133 if (LowerCaseEqualsASCII(names[i], "content-type"))
134 content_type_found = true;
137 if (!content_type_found) {
138 if (!request_info.headers.empty())
139 request_info.headers += "\r\n";
140 request_info.headers += "Content-Type: application/x-www-form-urlencoded";
142 } else {
143 if (!range.empty())
144 request_info.headers = std::string("Range: ") + range;
147 bridge_.reset(ChildThread::current()->resource_dispatcher()->CreateBridge(
148 request_info));
149 if (!body.empty()) {
150 scoped_refptr<ResourceRequestBody> request_body =
151 new ResourceRequestBody;
152 request_body->AppendBytes(&body[0], body.size());
153 bridge_->SetRequestBody(request_body.get());
156 bridge_->Start(this);
158 // TODO(jam): range requests
161 PluginURLFetcher::~PluginURLFetcher() {
164 void PluginURLFetcher::Cancel() {
165 bridge_->Cancel();
167 // Due to races and nested event loops, PluginURLFetcher may still receive
168 // events from the bridge before being destroyed. Do not forward additional
169 // events back to the plugin, via either |plugin_stream_| or
170 // |multipart_delegate_| which has its own pointer via
171 // MultiPartResponseClient.
172 if (multipart_delegate_)
173 multipart_delegate_->Cancel();
174 plugin_stream_ = NULL;
177 void PluginURLFetcher::URLRedirectResponse(bool allow) {
178 if (!plugin_stream_)
179 return;
181 if (allow) {
182 bridge_->SetDefersLoading(false);
183 } else {
184 bridge_->Cancel();
185 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
189 void PluginURLFetcher::OnUploadProgress(uint64 position, uint64 size) {
192 bool PluginURLFetcher::OnReceivedRedirect(
193 const net::RedirectInfo& redirect_info,
194 const ResourceResponseInfo& info) {
195 if (!plugin_stream_)
196 return false;
198 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::willSendRequest until
199 // kDirectNPAPIRequests is the default and we can remove the old path there.
201 // Currently this check is just to catch an https -> http redirect when
202 // loading the main plugin src URL. Longer term, we could investigate
203 // firing mixed diplay or scripting issues for subresource loads
204 // initiated by plug-ins.
205 if (is_plugin_src_load_ &&
206 !plugin_stream_->instance()->webplugin()->CheckIfRunInsecureContent(
207 redirect_info.new_url)) {
208 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
209 return false;
212 GURL old_url = url_;
213 url_ = redirect_info.new_url;
214 first_party_for_cookies_ = redirect_info.new_first_party_for_cookies;
216 // If the plugin does not participate in url redirect notifications then just
217 // block cross origin 307 POST redirects.
218 if (!notify_redirects_) {
219 if (redirect_info.status_code == 307 &&
220 redirect_info.new_method == "POST" &&
221 old_url.GetOrigin() != url_.GetOrigin()) {
222 plugin_stream_->DidFail(resource_id_); // That will delete |this|.
223 return false;
225 } else {
226 // Pause the request while we ask the plugin what to do about the redirect.
227 bridge_->SetDefersLoading(true);
228 plugin_stream_->WillSendRequest(url_, redirect_info.status_code);
231 return true;
234 void PluginURLFetcher::OnReceivedResponse(const ResourceResponseInfo& info) {
235 if (!plugin_stream_)
236 return;
238 // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::didReceiveResponse
239 // GetAllHeaders, and GetResponseInfo until kDirectNPAPIRequests is the
240 // default and we can remove the old path there.
242 bool request_is_seekable = true;
243 DCHECK(!multipart_delegate_.get());
244 if (plugin_stream_->seekable()) {
245 int response_code = info.headers->response_code();
246 if (response_code == 206) {
247 blink::WebURLResponse response;
248 response.initialize();
249 WebURLLoaderImpl::PopulateURLResponse(url_, info, &response);
251 std::string multipart_boundary;
252 if (MultipartResponseDelegate::ReadMultipartBoundary(
253 response, &multipart_boundary)) {
254 plugin_stream_->instance()->webplugin()->DidStartLoading();
256 MultiPartResponseClient* multi_part_response_client =
257 new MultiPartResponseClient(plugin_stream_);
259 multipart_delegate_.reset(new MultipartResponseDelegate(
260 multi_part_response_client, NULL, response, multipart_boundary));
262 // Multiple ranges requested, data will be delivered by
263 // MultipartResponseDelegate.
264 data_offset_ = 0;
265 return;
268 int64 upper_bound = 0, instance_size = 0;
269 // Single range requested - go through original processing for
270 // non-multipart requests, but update data offset.
271 MultipartResponseDelegate::ReadContentRanges(
272 response, &data_offset_, &upper_bound, &instance_size);
273 } else if (response_code == 200) {
274 // TODO: should we handle this case? We used to but it's not clear that we
275 // still need to. This was bug 5403, fixed in r7139.
279 // If the length comes in as -1, then it indicates that it was not
280 // read off the HTTP headers. We replicate Safari webkit behavior here,
281 // which is to set it to 0.
282 int expected_length = std::max(static_cast<int>(info.content_length), 0);
284 base::Time temp;
285 uint32 last_modified = 0;
286 std::string headers;
287 if (info.headers.get()) { // NULL for data: urls.
288 if (info.headers->GetLastModifiedValue(&temp))
289 last_modified = static_cast<uint32>(temp.ToDoubleT());
291 // TODO(darin): Shouldn't we also report HTTP version numbers?
292 int response_code = info.headers->response_code();
293 headers = base::StringPrintf("HTTP %d ", response_code);
294 headers += info.headers->GetStatusText();
295 headers += "\n";
297 void* iter = NULL;
298 std::string name, value;
299 while (info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
300 // TODO(darin): Should we really exclude headers with an empty value?
301 if (!name.empty() && !value.empty())
302 headers += name + ": " + value + "\n";
305 // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
306 // error codes in the stream header and as a result, was unaware of the fate
307 // of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF destroy
308 // the stream and invoke the NPP_DestroyStream function on the plugin if the
309 // HTTPrequest fails.
310 if ((url_.SchemeIs("http") || url_.SchemeIs("https")) &&
311 (response_code < 100 || response_code >= 400)) {
312 pending_failure_notification_ = true;
316 plugin_stream_->DidReceiveResponse(info.mime_type,
317 headers,
318 expected_length,
319 last_modified,
320 request_is_seekable);
323 void PluginURLFetcher::OnDownloadedData(int len,
324 int encoded_data_length) {
327 void PluginURLFetcher::OnReceivedData(const char* data,
328 int data_length,
329 int encoded_data_length) {
330 if (!plugin_stream_)
331 return;
333 if (multipart_delegate_) {
334 multipart_delegate_->OnReceivedData(data, data_length, encoded_data_length);
335 } else {
336 int64 offset = data_offset_;
337 data_offset_ += data_length;
339 if (copy_stream_data_) {
340 // QuickTime writes to this memory, and since we got it from
341 // ResourceDispatcher it's not mapped for write access in this process.
342 // http://crbug.com/308466.
343 scoped_ptr<char[]> data_copy(new char[data_length]);
344 memcpy(data_copy.get(), data, data_length);
345 plugin_stream_->DidReceiveData(data_copy.get(), data_length, offset);
346 } else {
347 plugin_stream_->DidReceiveData(data, data_length, offset);
349 // DANGER: this instance may be deleted at this point.
353 void PluginURLFetcher::OnCompletedRequest(
354 int error_code,
355 bool was_ignored_by_handler,
356 bool stale_copy_in_cache,
357 const std::string& security_info,
358 const base::TimeTicks& completion_time,
359 int64 total_transfer_size) {
360 if (!plugin_stream_)
361 return;
363 if (multipart_delegate_) {
364 multipart_delegate_->OnCompletedRequest();
365 multipart_delegate_.reset();
368 if (error_code == net::OK) {
369 plugin_stream_->DidFinishLoading(resource_id_);
370 } else {
371 plugin_stream_->DidFail(resource_id_);
375 } // namespace content