Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: content/renderer/pepper/pepper_url_loader_host.cc

Issue 11416064: Convert URLLoader to the new proxy design (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments, merge Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/renderer/pepper/pepper_url_loader_host.h"
6
7 #include "content/public/renderer/renderer_ppapi_host.h"
8 #include "net/base/net_errors.h"
9 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/host/dispatch_host_message.h"
11 #include "ppapi/host/host_message_context.h"
12 #include "ppapi/host/ppapi_host.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/shared_impl/ppapi_globals.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatfo rmSupport.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError. h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLLoader .h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLReques t.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRespon se.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h "
27 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
28 #include "webkit/plugins/ppapi/url_request_info_util.h"
29 #include "webkit/plugins/ppapi/url_response_info_util.h"
30
31 using WebKit::WebFrame;
32 using WebKit::WebString;
33 using WebKit::WebURL;
34 using WebKit::WebURLError;
35 using WebKit::WebURLLoader;
36 using WebKit::WebURLLoaderOptions;
37 using WebKit::WebURLRequest;
38 using WebKit::WebURLResponse;
39
40 #ifdef _MSC_VER
41 // Do not warn about use of std::copy with raw pointers.
42 #pragma warning(disable : 4996)
43 #endif
44
45 namespace content {
46
47 PepperURLLoaderHost::PepperURLLoaderHost(RendererPpapiHost* host,
48 bool main_document_loader,
49 PP_Instance instance,
50 PP_Resource resource)
51 : ResourceHost(host->GetPpapiHost(), instance, resource),
52 renderer_ppapi_host_(host),
53 main_document_loader_(main_document_loader),
54 has_universal_access_(false),
55 bytes_sent_(0),
56 total_bytes_to_be_sent_(-1),
57 bytes_received_(0),
58 total_bytes_to_be_received_(-1) {
59 DCHECK((main_document_loader && !resource) ||
60 (!main_document_loader && resource));
61 }
62
63 PepperURLLoaderHost::~PepperURLLoaderHost() {
64 // Normally deleting this object will delete the loader which will implicitly
65 // cancel the load. But this won't happen for the main document loader. So it
66 // would be nice to issue a Close() here.
67 //
68 // However, the PDF plugin will cancel the document load and then close the
69 // resource (which is reasonable). It then makes a second request to load the
70 // document so it can set the "want progress" flags (which is unreasonable --
71 // we should probably provide download progress on document loads).
72 //
73 // But a Close() on the main document (even if the request is already
74 // canceled) will cancel all pending subresources, of which the second
75 // request is one, and the load will fail. Even if we fixed the PDF reader to
76 // change the timing or to send progress events to avoid the second request,
77 // we don't want to cancel other loads when the main one is closed.
78 //
79 // "Leaking" the main document load here by not closing it will only affect
80 // plugins handling main document loads (which are very few, mostly only PDF)
81 // that dereference without explicitly closing the main document load (which
82 // PDF doesn't do -- it explicitly closes it before issuing the second
83 // request). And the worst thing that will happen is that any remaining data
84 // will get queued inside WebKit.
85 if (main_document_loader_) {
86 // The PluginInstance has a non-owning pointer to us.
87 webkit::ppapi::PluginInstance* instance_object =
88 renderer_ppapi_host_->GetPluginInstance(pp_instance());
89 if (instance_object) {
90 DCHECK(instance_object->document_loader() == this);
91 instance_object->set_document_loader(NULL);
92 }
93 }
94
95 // There is a path whereby the destructor for the loader_ member can
96 // invoke InstanceWasDeleted() upon this URLLoaderResource, thereby
97 // re-entering the scoped_ptr destructor with the same scoped_ptr object
98 // via loader_.reset(). Be sure that loader_ is first NULL then destroy
99 // the scoped_ptr. See http://crbug.com/159429.
100 scoped_ptr<WebKit::WebURLLoader> for_destruction_only(loader_.release());
101
102 for (size_t i = 0; i < pending_replies_.size(); i++)
103 delete pending_replies_[i];
104 }
105
106 int32_t PepperURLLoaderHost::OnResourceMessageReceived(
107 const IPC::Message& msg,
108 ppapi::host::HostMessageContext* context) {
109 IPC_BEGIN_MESSAGE_MAP(PepperURLLoaderHost, msg)
110 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
111 PpapiHostMsg_URLLoader_Open,
112 OnHostMsgOpen)
113 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
114 PpapiHostMsg_URLLoader_SetDeferLoading,
115 OnHostMsgSetDeferLoading)
116 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
117 PpapiHostMsg_URLLoader_Close,
118 OnHostMsgClose);
119 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
120 PpapiHostMsg_URLLoader_GrantUniversalAccess,
121 OnHostMsgGrantUniversalAccess)
122 IPC_END_MESSAGE_MAP()
123 return PP_ERROR_FAILED;
124 }
125
126 void PepperURLLoaderHost::willSendRequest(
127 WebURLLoader* loader,
128 WebURLRequest& new_request,
129 const WebURLResponse& redirect_response) {
130 if (!request_data_.follow_redirects) {
131 SaveResponse(redirect_response);
132 SetDefersLoading(true);
133 }
134 }
135
136 void PepperURLLoaderHost::didSendData(
137 WebURLLoader* loader,
138 unsigned long long bytes_sent,
139 unsigned long long total_bytes_to_be_sent) {
140 // TODO(darin): Bounds check input?
141 bytes_sent_ = static_cast<int64_t>(bytes_sent);
142 total_bytes_to_be_sent_ = static_cast<int64_t>(total_bytes_to_be_sent);
143 UpdateProgress();
144 }
145
146 void PepperURLLoaderHost::didReceiveResponse(WebURLLoader* loader,
147 const WebURLResponse& response) {
148 // Sets -1 if the content length is unknown. Send before issuing callback.
149 total_bytes_to_be_received_ = response.expectedContentLength();
150 UpdateProgress();
151
152 SaveResponse(response);
153 }
154
155 void PepperURLLoaderHost::didDownloadData(WebURLLoader* loader,
156 int data_length) {
157 bytes_received_ += data_length;
158 UpdateProgress();
159 }
160
161 void PepperURLLoaderHost::didReceiveData(WebURLLoader* loader,
162 const char* data,
163 int data_length,
164 int encoded_data_length) {
165 // Note that |loader| will be NULL for document loads.
166 bytes_received_ += data_length;
167 UpdateProgress();
168
169 PpapiPluginMsg_URLLoader_SendData* message =
170 new PpapiPluginMsg_URLLoader_SendData;
171 message->WriteData(data, data_length);
172 SendUpdateToPlugin(message);
173 }
174
175 void PepperURLLoaderHost::didFinishLoading(WebURLLoader* loader,
176 double finish_time) {
177 SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(PP_OK));
178 }
179
180 void PepperURLLoaderHost::didFail(WebURLLoader* loader,
181 const WebURLError& error) {
182 int32_t pp_error = PP_ERROR_FAILED;
183 if (error.domain.equals(WebString::fromUTF8(net::kErrorDomain))) {
184 // TODO(bbudge): Extend pp_errors.h to cover interesting network errors
185 // from the net error domain.
186 switch (error.reason) {
187 case net::ERR_ACCESS_DENIED:
188 case net::ERR_NETWORK_ACCESS_DENIED:
189 pp_error = PP_ERROR_NOACCESS;
190 break;
191 }
192 } else {
193 // It's a WebKit error.
194 pp_error = PP_ERROR_NOACCESS;
195 }
196
197 SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(pp_error));
198 }
199
200 void PepperURLLoaderHost::DidConnectPendingHostToResource() {
201 for (size_t i = 0; i < pending_replies_.size(); i++) {
202 host()->SendUnsolicitedReply(pp_resource(), *pending_replies_[i]);
203 delete pending_replies_[i];
204 }
205 pending_replies_.clear();
206 }
207
208 int32_t PepperURLLoaderHost::OnHostMsgOpen(
209 ppapi::host::HostMessageContext* context,
210 const ppapi::URLRequestInfoData& request_data) {
211 // An "Open" isn't a resource Call so has no reply, but failure to open
212 // implies a load failure. To make it harder to forget to send the load
213 // failed reply from the open handler, we instead catch errors and convert
214 // them to load failed messages.
215 int32_t ret = InternalOnHostMsgOpen(context, request_data);
216 DCHECK(ret != PP_OK_COMPLETIONPENDING);
217
218 if (ret != PP_OK)
219 SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(ret));
220 return PP_OK;
221 }
222
223 // Since this is wrapped by OnHostMsgOpen, we can return errors here and they
224 // will be translated into a FinishedLoading call automatically.
225 int32_t PepperURLLoaderHost::InternalOnHostMsgOpen(
226 ppapi::host::HostMessageContext* context,
227 const ppapi::URLRequestInfoData& request_data) {
228 // Main document loads are already open, so don't allow people to open them
229 // again.
230 if (main_document_loader_)
231 return PP_ERROR_INPROGRESS;
232
233 // Create a copy of the request data since CreateWebURLRequest will populate
234 // the file refs.
235 ppapi::URLRequestInfoData filled_in_request_data = request_data;
236
237 if (webkit::ppapi::URLRequestRequiresUniversalAccess(
238 filled_in_request_data) &&
239 !has_universal_access_) {
240 ppapi::PpapiGlobals::Get()->LogWithSource(
241 pp_instance(), PP_LOGLEVEL_ERROR, std::string(),
242 "PPB_URLLoader.Open: The URL you're requesting is "
243 " on a different security origin than your plugin. To request "
244 " cross-origin resources, see "
245 " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS.");
246 return PP_ERROR_NOACCESS;
247 }
248
249 if (loader_.get())
250 return PP_ERROR_INPROGRESS;
251
252 WebFrame* frame = GetFrame();
253 if (!frame)
254 return PP_ERROR_FAILED;
255 WebURLRequest web_request;
256 if (!webkit::ppapi::CreateWebURLRequest(&filled_in_request_data, frame,
257 &web_request))
258 return PP_ERROR_FAILED;
259 web_request.setRequestorProcessID(renderer_ppapi_host_->GetPluginPID());
260
261 WebURLLoaderOptions options;
262 if (has_universal_access_) {
263 options.allowCredentials = true;
264 options.crossOriginRequestPolicy =
265 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
266 } else {
267 // All other HTTP requests are untrusted.
268 options.untrustedHTTP = true;
269 if (filled_in_request_data.allow_cross_origin_requests) {
270 // Allow cross-origin requests with access control. The request specifies
271 // if credentials are to be sent.
272 options.allowCredentials = filled_in_request_data.allow_credentials;
273 options.crossOriginRequestPolicy =
274 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
275 } else {
276 // Same-origin requests can always send credentials.
277 options.allowCredentials = true;
278 }
279 }
280
281 loader_.reset(frame->createAssociatedURLLoader(options));
282 if (!loader_.get())
283 return PP_ERROR_FAILED;
284
285 // Don't actually save the request until we know we're going to load.
286 request_data_ = filled_in_request_data;
287 loader_->loadAsynchronously(web_request, this);
288
289 // Although the request is technically pending, this is not a "Call" message
290 // so we don't return COMPLETIONPENDING.
291 return PP_OK;
292 }
293
294 int32_t PepperURLLoaderHost::OnHostMsgSetDeferLoading(
295 ppapi::host::HostMessageContext* context,
296 bool defers_loading) {
297 SetDefersLoading(defers_loading);
298 return PP_OK;
299 }
300
301 int32_t PepperURLLoaderHost::OnHostMsgClose(
302 ppapi::host::HostMessageContext* context) {
303 Close();
304 return PP_OK;
305 }
306
307 int32_t PepperURLLoaderHost::OnHostMsgGrantUniversalAccess(
308 ppapi::host::HostMessageContext* context) {
309 // Only plugins with private permission can bypass same origin.
310 if (!host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
311 return PP_ERROR_FAILED;
312 has_universal_access_ = true;
313 return PP_OK;
314 }
315
316 void PepperURLLoaderHost::SendUpdateToPlugin(IPC::Message* msg) {
317 if (pp_resource()) {
318 host()->SendUnsolicitedReply(pp_resource(), *msg);
319 delete msg;
320 } else {
321 pending_replies_.push_back(msg);
322 }
323 }
324
325 void PepperURLLoaderHost::Close() {
326 if (loader_.get())
327 loader_->cancel();
328 else if (main_document_loader_)
329 GetFrame()->stopLoading();
330 }
331
332 WebKit::WebFrame* PepperURLLoaderHost::GetFrame() {
333 webkit::ppapi::PluginInstance* instance_object =
334 renderer_ppapi_host_->GetPluginInstance(pp_instance());
335 if (!instance_object)
336 return NULL;
337 return instance_object->container()->element().document().frame();
338 }
339
340 void PepperURLLoaderHost::SetDefersLoading(bool defers_loading) {
341 if (loader_.get())
342 loader_->setDefersLoading(defers_loading);
343
344 // TODO(brettw) bug 96770: We need a way to set the defers loading flag on
345 // main document loads (when the loader_ is null).
346 }
347
348 void PepperURLLoaderHost::SaveResponse(const WebURLResponse& response) {
349 if (!main_document_loader_) {
350 // When we're the main document loader, we send the response data up front,
351 // so we don't want to trigger any callbacks in the plugin which aren't
352 // expected. We should not be getting redirects so the response sent
353 // up-front should be valid (plugin document loads happen after all
354 // redirects are processed since WebKit has to know the MIME type).
355 SendUpdateToPlugin(
356 new PpapiPluginMsg_URLLoader_ReceivedResponse(
357 webkit::ppapi::DataFromWebURLResponse(pp_instance(), response)));
358 }
359 }
360
361 void PepperURLLoaderHost::UpdateProgress() {
362 bool record_download = request_data_.record_download_progress;
363 bool record_upload = request_data_.record_upload_progress;
364
365 if (record_download || record_upload) {
366 // Here we go through some effort to only send the exact information that
367 // the requestor wanted in the request flags. It would be just as
368 // efficient to send all of it, but we don't want people to rely on
369 // getting download progress when they happen to set the upload progress
370 // flag.
371 ppapi::proxy::ResourceMessageReplyParams params;
372 SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_UpdateProgress(
373 record_upload ? bytes_sent_ : -1,
374 record_upload ? total_bytes_to_be_sent_ : -1,
375 record_download ? bytes_received_ : -1,
376 record_download ? total_bytes_to_be_received_ : -1));
377 }
378 }
379
380 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_url_loader_host.h ('k') | content/renderer/pepper/renderer_ppapi_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698