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