Home | History | Annotate | Download | only in pepper
      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