[email protected] | 94af057 | 2012-01-17 22:10:14 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 5826f3ea | 2010-06-24 19:43:37 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 20790a22 | 2013-07-25 02:23:05 | [diff] [blame] | 5 | #include "content/renderer/pepper/url_request_info_util.h" |
[email protected] | 5826f3ea | 2010-06-24 19:43:37 | [diff] [blame] | 6 | |
avi | 1023d01 | 2015-12-25 02:39:14 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
| 9 | |
[email protected] | 5826f3ea | 2010-06-24 19:43:37 | [diff] [blame] | 10 | #include "base/logging.h" |
[email protected] | f63582d | 2013-06-11 22:52:54 | [diff] [blame] | 11 | #include "base/strings/string_util.h" |
[email protected] | 354ce19 | 2014-03-25 21:35:00 | [diff] [blame] | 12 | #include "content/child/request_extra_data.h" |
[email protected] | 4de8c308 | 2013-07-29 23:26:56 | [diff] [blame] | 13 | #include "content/common/fileapi/file_system_messages.h" |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 14 | #include "content/renderer/pepper/host_globals.h" |
| 15 | #include "content/renderer/pepper/pepper_file_ref_renderer_host.h" |
| 16 | #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |
[email protected] | 20790a22 | 2013-07-25 02:23:05 | [diff] [blame] | 17 | #include "content/renderer/pepper/plugin_module.h" |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 18 | #include "content/renderer/pepper/renderer_ppapi_host_impl.h" |
[email protected] | 4de8c308 | 2013-07-29 23:26:56 | [diff] [blame] | 19 | #include "content/renderer/render_thread_impl.h" |
[email protected] | 9731ede | 2010-07-15 05:56:20 | [diff] [blame] | 20 | #include "net/http/http_util.h" |
[email protected] | 095162b | 2014-07-10 19:35:05 | [diff] [blame] | 21 | #include "ppapi/c/pp_bool.h" |
| 22 | #include "ppapi/c/pp_var.h" |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 23 | #include "ppapi/proxy/ppapi_messages.h" |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 24 | #include "ppapi/shared_impl/url_request_info_data.h" |
[email protected] | ce701cd | 2011-08-01 21:47:04 | [diff] [blame] | 25 | #include "ppapi/shared_impl/var.h" |
[email protected] | bf712f8e | 2011-06-17 02:10:45 | [diff] [blame] | 26 | #include "ppapi/thunk/enter.h" |
[email protected] | c1088446 | 2013-05-30 00:22:09 | [diff] [blame] | 27 | #include "third_party/WebKit/public/platform/WebData.h" |
| 28 | #include "third_party/WebKit/public/platform/WebHTTPBody.h" |
| 29 | #include "third_party/WebKit/public/platform/WebURL.h" |
| 30 | #include "third_party/WebKit/public/platform/WebURLRequest.h" |
[email protected] | 2255a933 | 2013-06-17 05:12:31 | [diff] [blame] | 31 | #include "third_party/WebKit/public/web/WebDocument.h" |
| 32 | #include "third_party/WebKit/public/web/WebFrame.h" |
[email protected] | ad67777 | 2013-06-29 14:18:38 | [diff] [blame] | 33 | #include "url/gurl.h" |
| 34 | #include "url/url_util.h" |
[email protected] | 5826f3ea | 2010-06-24 19:43:37 | [diff] [blame] | 35 | |
[email protected] | 76bf34a | 2013-09-05 23:36:16 | [diff] [blame] | 36 | using ppapi::Resource; |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 37 | using ppapi::URLRequestInfoData; |
[email protected] | bf712f8e | 2011-06-17 02:10:45 | [diff] [blame] | 38 | using ppapi::thunk::EnterResourceNoLock; |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 39 | using blink::WebData; |
| 40 | using blink::WebHTTPBody; |
| 41 | using blink::WebString; |
| 42 | using blink::WebFrame; |
| 43 | using blink::WebURL; |
| 44 | using blink::WebURLRequest; |
[email protected] | a033865 | 2010-06-30 04:55:29 | [diff] [blame] | 45 | |
[email protected] | adab233 | 2013-07-25 18:04:32 | [diff] [blame] | 46 | namespace content { |
[email protected] | 5826f3ea | 2010-06-24 19:43:37 | [diff] [blame] | 47 | |
| 48 | namespace { |
| 49 | |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 50 | // Appends the file ref given the Resource pointer associated with it to the |
| 51 | // given HTTP body, returning true on success. |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 52 | bool AppendFileRefToBody(PP_Instance instance, |
| 53 | PP_Resource resource, |
| 54 | int64_t start_offset, |
| 55 | int64_t number_of_bytes, |
| 56 | PP_Time expected_last_modified_time, |
| 57 | WebHTTPBody* http_body) { |
[email protected] | 76bf34a | 2013-09-05 23:36:16 | [diff] [blame] | 58 | base::FilePath platform_path; |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 59 | PepperPluginInstanceImpl* instance_impl = |
| 60 | HostGlobals::Get()->GetInstance(instance); |
| 61 | if (!instance_impl) |
| 62 | return false; |
| 63 | |
| 64 | RendererPpapiHost* renderer_ppapi_host = |
| 65 | instance_impl->module()->renderer_ppapi_host(); |
| 66 | if (!renderer_ppapi_host) |
| 67 | return false; |
| 68 | ppapi::host::ResourceHost* resource_host = |
| 69 | renderer_ppapi_host->GetPpapiHost()->GetResourceHost(resource); |
| 70 | if (!resource_host || !resource_host->IsFileRefHost()) |
| 71 | return false; |
| 72 | PepperFileRefRendererHost* file_ref_host = |
| 73 | static_cast<PepperFileRefRendererHost*>(resource_host); |
| 74 | switch (file_ref_host->GetFileSystemType()) { |
[email protected] | 6f75c95 | 2011-08-26 04:51:07 | [diff] [blame] | 75 | case PP_FILESYSTEMTYPE_LOCALTEMPORARY: |
| 76 | case PP_FILESYSTEMTYPE_LOCALPERSISTENT: |
[email protected] | 2cd2107 | 2012-08-28 10:19:45 | [diff] [blame] | 77 | // TODO(kinuko): remove this sync IPC when we fully support |
| 78 | // AppendURLRange for FileSystem URL. |
[email protected] | 4de8c308 | 2013-07-29 23:26:56 | [diff] [blame] | 79 | RenderThreadImpl::current()->Send( |
| 80 | new FileSystemHostMsg_SyncGetPlatformPath( |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 81 | file_ref_host->GetFileSystemURL(), &platform_path)); |
[email protected] | 6f75c95 | 2011-08-26 04:51:07 | [diff] [blame] | 82 | break; |
| 83 | case PP_FILESYSTEMTYPE_EXTERNAL: |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 84 | platform_path = file_ref_host->GetExternalFilePath(); |
[email protected] | 6f75c95 | 2011-08-26 04:51:07 | [diff] [blame] | 85 | break; |
| 86 | default: |
| 87 | NOTREACHED(); |
| 88 | } |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 89 | http_body->appendFileRange(platform_path.AsUTF16Unsafe(), |
| 90 | start_offset, |
| 91 | number_of_bytes, |
| 92 | expected_last_modified_time); |
[email protected] | 6f75c95 | 2011-08-26 04:51:07 | [diff] [blame] | 93 | return true; |
| 94 | } |
| 95 | |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 96 | // Checks that the request data is valid. Returns false on failure. Note that |
| 97 | // method and header validation is done by the URL loader when the request is |
| 98 | // opened, and any access errors are returned asynchronously. |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 99 | bool ValidateURLRequestData(const URLRequestInfoData& data) { |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 100 | if (data.prefetch_buffer_lower_threshold < 0 || |
| 101 | data.prefetch_buffer_upper_threshold < 0 || |
| 102 | data.prefetch_buffer_upper_threshold <= |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 103 | data.prefetch_buffer_lower_threshold) { |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 104 | return false; |
| 105 | } |
| 106 | return true; |
| 107 | } |
| 108 | |
[email protected] | 069c7b1 | 2014-08-20 19:23:20 | [diff] [blame] | 109 | std::string FilterStringForXRequestedWithValue(const std::string& s) { |
| 110 | std::string rv; |
| 111 | rv.reserve(s.length()); |
| 112 | for (size_t i = 0; i < s.length(); i++) { |
| 113 | char c = s[i]; |
| 114 | // Allow ASCII digits, letters, periods, commas, and underscores. (Ignore |
| 115 | // all other characters.) |
| 116 | if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || |
| 117 | (c >= 'a' && c <= 'z') || (c == '.') || (c == ',') || (c == '_')) |
| 118 | rv.push_back(c); |
| 119 | } |
| 120 | return rv; |
| 121 | } |
| 122 | |
| 123 | // Returns an appropriate value for the X-Requested-With header for plugins that |
| 124 | // present an X-Requested-With header. Returns a blank string for other plugins. |
| 125 | // We produce a user-agent-like string (eating spaces and other undesired |
| 126 | // characters) like "ShockwaveFlash/11.5.31.135" from the plugin name and |
| 127 | // version. |
| 128 | std::string MakeXRequestedWithValue(const std::string& name, |
| 129 | const std::string& version) { |
| 130 | std::string rv = FilterStringForXRequestedWithValue(name); |
| 131 | if (rv.empty()) |
| 132 | return std::string(); |
| 133 | |
| 134 | // Apply to a narrow list of plugins only. |
| 135 | if (rv != "ShockwaveFlash" && rv != "PPAPITests") |
| 136 | return std::string(); |
| 137 | |
| 138 | std::string filtered_version = FilterStringForXRequestedWithValue(version); |
| 139 | if (!filtered_version.empty()) |
| 140 | rv += "/" + filtered_version; |
| 141 | |
| 142 | return rv; |
| 143 | } |
| 144 | |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 145 | } // namespace |
| 146 | |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 147 | bool CreateWebURLRequest(PP_Instance instance, |
| 148 | URLRequestInfoData* data, |
[email protected] | d0fef94d2 | 2013-08-05 18:26:16 | [diff] [blame] | 149 | WebFrame* frame, |
| 150 | WebURLRequest* dest) { |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 151 | // In the out-of-process case, we've received the URLRequestInfoData |
| 152 | // from the untrusted plugin and done no validation on it. We need to be |
| 153 | // sure it's not being malicious by checking everything for consistency. |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 154 | if (!ValidateURLRequestData(*data)) |
[email protected] | d0fef94d2 | 2013-08-05 18:26:16 | [diff] [blame] | 155 | return false; |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 156 | |
[email protected] | 069c7b1 | 2014-08-20 19:23:20 | [diff] [blame] | 157 | std::string name_version; |
| 158 | |
| 159 | // Allow instance to be 0 or -1 for testing purposes. |
| 160 | if (instance && instance != -1) { |
| 161 | PepperPluginInstanceImpl* instance_impl = |
| 162 | HostGlobals::Get()->GetInstance(instance); |
| 163 | if (instance_impl) { |
| 164 | name_version = MakeXRequestedWithValue( |
| 165 | instance_impl->module()->name(), |
| 166 | instance_impl->module()->version()); |
| 167 | } |
| 168 | } else { |
| 169 | name_version = "internal_testing_only"; |
| 170 | } |
| 171 | |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 172 | dest->initialize(); |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 173 | dest->setURL(frame->document().completeURL(WebString::fromUTF8(data->url))); |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 174 | dest->setDownloadToFile(data->stream_to_file); |
| 175 | dest->setReportUploadProgress(data->record_upload_progress); |
| 176 | |
| 177 | if (!data->method.empty()) |
| 178 | dest->setHTTPMethod(WebString::fromUTF8(data->method)); |
| 179 | |
| 180 | dest->setFirstPartyForCookies(frame->document().firstPartyForCookies()); |
| 181 | |
| 182 | const std::string& headers = data->headers; |
| 183 | if (!headers.empty()) { |
| 184 | net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n\r"); |
| 185 | while (it.GetNext()) { |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 186 | dest->addHTTPHeaderField(WebString::fromUTF8(it.name()), |
| 187 | WebString::fromUTF8(it.values())); |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 188 | } |
| 189 | } |
| 190 | |
| 191 | // Append the upload data. |
| 192 | if (!data->body.empty()) { |
| 193 | WebHTTPBody http_body; |
| 194 | http_body.initialize(); |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 195 | int file_index = 0; |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 196 | for (size_t i = 0; i < data->body.size(); ++i) { |
| 197 | const URLRequestInfoData::BodyItem& item = data->body[i]; |
| 198 | if (item.is_file) { |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 199 | if (!AppendFileRefToBody(instance, |
| 200 | item.file_ref_pp_resource, |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 201 | item.start_offset, |
| 202 | item.number_of_bytes, |
| 203 | item.expected_last_modified_time, |
[email protected] | d0fef94d2 | 2013-08-05 18:26:16 | [diff] [blame] | 204 | &http_body)) |
| 205 | return false; |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 206 | file_index++; |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 207 | } else { |
| 208 | DCHECK(!item.data.empty()); |
| 209 | http_body.appendData(WebData(item.data)); |
| 210 | } |
| 211 | } |
| 212 | dest->setHTTPBody(http_body); |
| 213 | } |
| 214 | |
| 215 | // Add the "Referer" header if there is a custom referrer. Such requests |
| 216 | // require universal access. For all other requests, "Referer" will be set |
| 217 | // after header security checks are done in AssociatedURLLoader. |
| 218 | if (data->has_custom_referrer_url && !data->custom_referrer_url.empty()) |
| 219 | frame->setReferrerForRequest(*dest, GURL(data->custom_referrer_url)); |
| 220 | |
| 221 | if (data->has_custom_content_transfer_encoding && |
| 222 | !data->custom_content_transfer_encoding.empty()) { |
| 223 | dest->addHTTPHeaderField( |
| 224 | WebString::fromUTF8("Content-Transfer-Encoding"), |
| 225 | WebString::fromUTF8(data->custom_content_transfer_encoding)); |
| 226 | } |
| 227 | |
[email protected] | 069c7b1 | 2014-08-20 19:23:20 | [diff] [blame] | 228 | if (data->has_custom_user_agent || !name_version.empty()) { |
[email protected] | 354ce19 | 2014-03-25 21:35:00 | [diff] [blame] | 229 | RequestExtraData* extra_data = new RequestExtraData(); |
[email protected] | 069c7b1 | 2014-08-20 19:23:20 | [diff] [blame] | 230 | if (data->has_custom_user_agent) { |
| 231 | extra_data->set_custom_user_agent( |
| 232 | WebString::fromUTF8(data->custom_user_agent)); |
| 233 | } |
| 234 | if (!name_version.empty()) { |
| 235 | extra_data->set_requested_with(WebString::fromUTF8(name_version)); |
| 236 | } |
[email protected] | 354ce19 | 2014-03-25 21:35:00 | [diff] [blame] | 237 | dest->setExtraData(extra_data); |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 238 | } |
[email protected] | d0fef94d2 | 2013-08-05 18:26:16 | [diff] [blame] | 239 | |
| 240 | return true; |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 241 | } |
| 242 | |
[email protected] | c6420f08 | 2013-09-18 22:42:41 | [diff] [blame] | 243 | bool URLRequestRequiresUniversalAccess(const URLRequestInfoData& data) { |
[email protected] | ad63b5c | 2014-04-11 21:12:36 | [diff] [blame] | 244 | return data.has_custom_referrer_url || |
| 245 | data.has_custom_content_transfer_encoding || |
| 246 | data.has_custom_user_agent || |
sungmann.cho | 8a8db05 | 2014-09-24 01:59:25 | [diff] [blame] | 247 | url::FindAndCompareScheme(data.url, url::kJavaScriptScheme, NULL); |
[email protected] | 7b2f729 | 2012-09-19 19:52:12 | [diff] [blame] | 248 | } |
[email protected] | 6f75c95 | 2011-08-26 04:51:07 | [diff] [blame] | 249 | |
[email protected] | adab233 | 2013-07-25 18:04:32 | [diff] [blame] | 250 | } // namespace content |