3059a613fac39139592ef4841b04aac07d453758
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / url_request_info_util.cc
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/url_request_info_util.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "content/common/fileapi/file_system_messages.h"
10 #include "content/renderer/pepper/common.h"
11 #include "content/renderer/pepper/host_globals.h"
12 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
14 #include "content/renderer/pepper/plugin_module.h"
15 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
16 #include "content/renderer/render_thread_impl.h"
17 #include "net/http/http_util.h"
18 #include "ppapi/proxy/ppapi_messages.h"
19 #include "ppapi/shared_impl/url_request_info_data.h"
20 #include "ppapi/shared_impl/var.h"
21 #include "ppapi/thunk/enter.h"
22 #include "third_party/WebKit/public/platform/WebData.h"
23 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
24 #include "third_party/WebKit/public/platform/WebURL.h"
25 #include "third_party/WebKit/public/platform/WebURLRequest.h"
26 #include "third_party/WebKit/public/web/WebDocument.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "url/gurl.h"
29 #include "url/url_util.h"
30 #include "webkit/child/weburlrequest_extradata_impl.h"
31
32 using ppapi::Resource;
33 using ppapi::URLRequestInfoData;
34 using ppapi::thunk::EnterResourceNoLock;
35 using blink::WebData;
36 using blink::WebHTTPBody;
37 using blink::WebString;
38 using blink::WebFrame;
39 using blink::WebURL;
40 using blink::WebURLRequest;
41
42 namespace content {
43
44 namespace {
45
46 // Appends the file ref given the Resource pointer associated with it to the
47 // given HTTP body, returning true on success.
48 bool AppendFileRefToBody(
49     PP_Instance instance,
50     PP_Resource resource,
51     int64_t start_offset,
52     int64_t number_of_bytes,
53     PP_Time expected_last_modified_time,
54     WebHTTPBody *http_body) {
55   base::FilePath platform_path;
56   PepperPluginInstanceImpl* instance_impl =
57       HostGlobals::Get()->GetInstance(instance);
58   if (!instance_impl)
59     return false;
60
61   RendererPpapiHost* renderer_ppapi_host =
62       instance_impl->module()->renderer_ppapi_host();
63   if (!renderer_ppapi_host)
64     return false;
65   ppapi::host::ResourceHost* resource_host =
66       renderer_ppapi_host->GetPpapiHost()->GetResourceHost(resource);
67   if (!resource_host || !resource_host->IsFileRefHost())
68     return false;
69   PepperFileRefRendererHost* file_ref_host =
70       static_cast<PepperFileRefRendererHost*>(resource_host);
71   switch (file_ref_host->GetFileSystemType()) {
72     case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
73     case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
74       // TODO(kinuko): remove this sync IPC when we fully support
75       // AppendURLRange for FileSystem URL.
76       RenderThreadImpl::current()->Send(
77           new FileSystemHostMsg_SyncGetPlatformPath(
78               file_ref_host->GetFileSystemURL(), &platform_path));
79       break;
80     case PP_FILESYSTEMTYPE_EXTERNAL:
81       platform_path = file_ref_host->GetExternalFilePath();
82       break;
83     default:
84       NOTREACHED();
85   }
86   http_body->appendFileRange(
87       platform_path.AsUTF16Unsafe(),
88       start_offset,
89       number_of_bytes,
90       expected_last_modified_time);
91   return true;
92 }
93
94 // Checks that the request data is valid. Returns false on failure. Note that
95 // method and header validation is done by the URL loader when the request is
96 // opened, and any access errors are returned asynchronously.
97 bool ValidateURLRequestData(const URLRequestInfoData& data) {
98   if (data.prefetch_buffer_lower_threshold < 0 ||
99       data.prefetch_buffer_upper_threshold < 0 ||
100       data.prefetch_buffer_upper_threshold <=
101       data.prefetch_buffer_lower_threshold) {
102     return false;
103   }
104   return true;
105 }
106
107 }  // namespace
108
109 bool CreateWebURLRequest(PP_Instance instance,
110                          URLRequestInfoData* data,
111                          WebFrame* frame,
112                          WebURLRequest* dest) {
113   // In the out-of-process case, we've received the URLRequestInfoData
114   // from the untrusted plugin and done no validation on it. We need to be
115   // sure it's not being malicious by checking everything for consistency.
116   if (!ValidateURLRequestData(*data))
117     return false;
118
119   dest->initialize();
120   dest->setURL(frame->document().completeURL(WebString::fromUTF8(
121       data->url)));
122   dest->setDownloadToFile(data->stream_to_file);
123   dest->setReportUploadProgress(data->record_upload_progress);
124
125   if (!data->method.empty())
126     dest->setHTTPMethod(WebString::fromUTF8(data->method));
127
128   dest->setFirstPartyForCookies(frame->document().firstPartyForCookies());
129
130   const std::string& headers = data->headers;
131   if (!headers.empty()) {
132     net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n\r");
133     while (it.GetNext()) {
134       dest->addHTTPHeaderField(
135           WebString::fromUTF8(it.name()),
136           WebString::fromUTF8(it.values()));
137     }
138   }
139
140   // Append the upload data.
141   if (!data->body.empty()) {
142     WebHTTPBody http_body;
143     http_body.initialize();
144     int file_index = 0;
145     for (size_t i = 0; i < data->body.size(); ++i) {
146       const URLRequestInfoData::BodyItem& item = data->body[i];
147       if (item.is_file) {
148         if (!AppendFileRefToBody(instance,
149                                  item.file_ref_pp_resource,
150                                  item.start_offset,
151                                  item.number_of_bytes,
152                                  item.expected_last_modified_time,
153                                  &http_body))
154           return false;
155         file_index++;
156       } else {
157         DCHECK(!item.data.empty());
158         http_body.appendData(WebData(item.data));
159       }
160     }
161     dest->setHTTPBody(http_body);
162   }
163
164   // Add the "Referer" header if there is a custom referrer. Such requests
165   // require universal access. For all other requests, "Referer" will be set
166   // after header security checks are done in AssociatedURLLoader.
167   if (data->has_custom_referrer_url && !data->custom_referrer_url.empty())
168     frame->setReferrerForRequest(*dest, GURL(data->custom_referrer_url));
169
170   if (data->has_custom_content_transfer_encoding &&
171       !data->custom_content_transfer_encoding.empty()) {
172     dest->addHTTPHeaderField(
173         WebString::fromUTF8("Content-Transfer-Encoding"),
174         WebString::fromUTF8(data->custom_content_transfer_encoding));
175   }
176
177   if (data->has_custom_user_agent) {
178     bool was_after_preconnect_request = false;
179     dest->setExtraData(new webkit_glue::WebURLRequestExtraDataImpl(
180         WebString::fromUTF8(data->custom_user_agent),
181         was_after_preconnect_request));
182   }
183
184   return true;
185 }
186
187 bool URLRequestRequiresUniversalAccess(const URLRequestInfoData& data) {
188   return
189       data.has_custom_referrer_url ||
190       data.has_custom_content_transfer_encoding ||
191       data.has_custom_user_agent ||
192       url_util::FindAndCompareScheme(data.url, "javascript", NULL);
193 }
194
195 }  // namespace content