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