Home | History | Annotate | Download | only in google_apis
      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 "chrome/browser/google_apis/gdata_wapi_url_generator.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "net/base/escape.h"
     11 #include "net/base/url_util.h"
     12 #include "url/gurl.h"
     13 
     14 namespace google_apis {
     15 namespace {
     16 
     17 // Content URL for modification or resource list retrieval in a particular
     18 // directory specified by "%s" which will be replaced with its resource id.
     19 const char kContentURLFormat[] = "/feeds/default/private/full/%s/contents";
     20 
     21 // Content URL for removing a resource specified by the latter "%s" from the
     22 // directory specified by the former "%s".
     23 const char kResourceURLForRemovalFormat[] =
     24     "/feeds/default/private/full/%s/contents/%s";
     25 
     26 // URL requesting single resource entry whose resource id is followed by this
     27 // prefix.
     28 const char kGetEditURLPrefix[] = "/feeds/default/private/full/";
     29 
     30 // Root resource list url.
     31 const char kResourceListRootURL[] = "/feeds/default/private/full";
     32 
     33 // Metadata feed with things like user quota.
     34 const char kAccountMetadataURL[] = "/feeds/metadata/default";
     35 
     36 // URL to upload a new file under a particular directory specified by "%s".
     37 const char kInitiateUploadNewFileURLFormat[] =
     38     "/feeds/upload/create-session/default/private/full/%s/contents";
     39 
     40 // URL to upload a file content to overwrite a file whose resource id is
     41 // followed by this prefix.
     42 const char kInitiateUploadExistingFileURLPrefix[] =
     43     "/feeds/upload/create-session/default/private/full/";
     44 
     45 // Maximum number of resource entries to include in a feed.
     46 // Be careful not to use something too small because it might overload the
     47 // server. Be careful not to use something too large because it makes the
     48 // "fetched N items" UI less responsive.
     49 const int kMaxDocumentsPerFeed = 500;
     50 const int kMaxDocumentsPerSearchFeed = 50;
     51 
     52 // URL requesting documents list of changes to documents collections.
     53 const char kGetChangesListURL[] = "/feeds/default/private/changes";
     54 
     55 }  // namespace
     56 
     57 const char GDataWapiUrlGenerator::kBaseUrlForProduction[] =
     58     "https://docs.google.com/";
     59 
     60 const char GDataWapiUrlGenerator::kBaseDownloadUrlForProduction[] =
     61     "https://www.googledrive.com/host/";
     62 
     63 // static
     64 GURL GDataWapiUrlGenerator::AddStandardUrlParams(const GURL& url) {
     65   GURL result = net::AppendOrReplaceQueryParameter(url, "v", "3");
     66   result = net::AppendOrReplaceQueryParameter(result, "alt", "json");
     67   result = net::AppendOrReplaceQueryParameter(result, "showroot", "true");
     68   return result;
     69 }
     70 
     71 // static
     72 GURL GDataWapiUrlGenerator::AddInitiateUploadUrlParams(const GURL& url) {
     73   GURL result = net::AppendOrReplaceQueryParameter(url, "convert", "false");
     74   return AddStandardUrlParams(result);
     75 }
     76 
     77 // static
     78 GURL GDataWapiUrlGenerator::AddFeedUrlParams(
     79     const GURL& url,
     80     int num_items_to_fetch) {
     81   GURL result = AddStandardUrlParams(url);
     82   result = net::AppendOrReplaceQueryParameter(result, "showfolders", "true");
     83   result = net::AppendOrReplaceQueryParameter(result, "include-shared", "true");
     84   result = net::AppendOrReplaceQueryParameter(
     85       result, "max-results", base::IntToString(num_items_to_fetch));
     86   return result;
     87 }
     88 
     89 GDataWapiUrlGenerator::GDataWapiUrlGenerator(const GURL& base_url,
     90                                              const GURL& base_download_url)
     91     : base_url_(base_url),
     92       base_download_url_(base_download_url) {
     93 }
     94 
     95 GDataWapiUrlGenerator::~GDataWapiUrlGenerator() {
     96 }
     97 
     98 GURL GDataWapiUrlGenerator::GenerateResourceListUrl(
     99     const GURL& override_url,
    100     int64 start_changestamp,
    101     const std::string& search_string,
    102     const std::string& directory_resource_id) const {
    103   DCHECK_LE(0, start_changestamp);
    104 
    105   int max_docs = search_string.empty() ? kMaxDocumentsPerFeed :
    106                                          kMaxDocumentsPerSearchFeed;
    107   GURL url;
    108   if (!override_url.is_empty()) {
    109     // |override_url| specifies the URL of the continuation feed when the feed
    110     // is broken up to multiple chunks. In this case we must not add the
    111     // |start_changestamp| that provides the original start point.
    112     start_changestamp = 0;
    113     url = override_url;
    114   } else if (start_changestamp > 0) {
    115     // The start changestamp shouldn't be used for a search.
    116     DCHECK(search_string.empty());
    117     url = base_url_.Resolve(kGetChangesListURL);
    118   } else if (!directory_resource_id.empty()) {
    119     url = base_url_.Resolve(
    120         base::StringPrintf(kContentURLFormat,
    121                            net::EscapePath(
    122                                directory_resource_id).c_str()));
    123   } else {
    124     url = base_url_.Resolve(kResourceListRootURL);
    125   }
    126 
    127   url = AddFeedUrlParams(url, max_docs);
    128 
    129   if (start_changestamp) {
    130     url = net::AppendOrReplaceQueryParameter(
    131         url, "start-index", base::Int64ToString(start_changestamp));
    132   }
    133   if (!search_string.empty()) {
    134     url = net::AppendOrReplaceQueryParameter(url, "q", search_string);
    135   }
    136 
    137   return url;
    138 }
    139 
    140 GURL GDataWapiUrlGenerator::GenerateSearchByTitleUrl(
    141     const std::string& title,
    142     const std::string& directory_resource_id) const {
    143   DCHECK(!title.empty());
    144 
    145   GURL url = directory_resource_id.empty() ?
    146       base_url_.Resolve(kResourceListRootURL) :
    147       base_url_.Resolve(base::StringPrintf(
    148           kContentURLFormat, net::EscapePath(directory_resource_id).c_str()));
    149   url = AddFeedUrlParams(url, kMaxDocumentsPerFeed);
    150   url = net::AppendOrReplaceQueryParameter(url, "title", title);
    151   url = net::AppendOrReplaceQueryParameter(url, "title-exact", "true");
    152   return url;
    153 }
    154 
    155 GURL GDataWapiUrlGenerator::GenerateEditUrl(
    156     const std::string& resource_id) const {
    157   return AddStandardUrlParams(GenerateEditUrlWithoutParams(resource_id));
    158 }
    159 
    160 GURL GDataWapiUrlGenerator::GenerateEditUrlWithoutParams(
    161     const std::string& resource_id) const {
    162   return base_url_.Resolve(kGetEditURLPrefix + net::EscapePath(resource_id));
    163 }
    164 
    165 GURL GDataWapiUrlGenerator::GenerateEditUrlWithEmbedOrigin(
    166     const std::string& resource_id, const GURL& embed_origin) const {
    167   GURL url = GenerateEditUrl(resource_id);
    168   if (!embed_origin.is_empty()) {
    169     // Construct a valid serialized embed origin from an url, according to
    170     // WD-html5-20110525. Such string has to be built manually, since
    171     // GURL::spec() always adds the trailing slash. Moreover, ports are
    172     // currently not supported.
    173     DCHECK(!embed_origin.has_port());
    174     DCHECK(!embed_origin.has_path() || embed_origin.path() == "/");
    175     const std::string serialized_embed_origin =
    176         embed_origin.scheme() + "://" + embed_origin.host();
    177     url = net::AppendOrReplaceQueryParameter(
    178         url, "embedOrigin", serialized_embed_origin);
    179   }
    180   return url;
    181 }
    182 
    183 GURL GDataWapiUrlGenerator::GenerateContentUrl(
    184     const std::string& resource_id) const {
    185   if (resource_id.empty()) {
    186     // |resource_id| must not be empty. Return an empty GURL as an error.
    187     return GURL();
    188   }
    189 
    190   GURL result = base_url_.Resolve(
    191       base::StringPrintf(kContentURLFormat,
    192                          net::EscapePath(resource_id).c_str()));
    193   return AddStandardUrlParams(result);
    194 }
    195 
    196 GURL GDataWapiUrlGenerator::GenerateResourceUrlForRemoval(
    197     const std::string& parent_resource_id,
    198     const std::string& resource_id) const {
    199   if (resource_id.empty() || parent_resource_id.empty()) {
    200     // Both |resource_id| and |parent_resource_id| must be non-empty.
    201     // Return an empty GURL as an error.
    202     return GURL();
    203   }
    204 
    205   GURL result = base_url_.Resolve(
    206       base::StringPrintf(kResourceURLForRemovalFormat,
    207                          net::EscapePath(parent_resource_id).c_str(),
    208                          net::EscapePath(resource_id).c_str()));
    209   return AddStandardUrlParams(result);
    210 }
    211 
    212 GURL GDataWapiUrlGenerator::GenerateInitiateUploadNewFileUrl(
    213     const std::string& parent_resource_id) const {
    214   GURL result = base_url_.Resolve(
    215       base::StringPrintf(kInitiateUploadNewFileURLFormat,
    216                          net::EscapePath(parent_resource_id).c_str()));
    217   return AddInitiateUploadUrlParams(result);
    218 }
    219 
    220 GURL GDataWapiUrlGenerator::GenerateInitiateUploadExistingFileUrl(
    221     const std::string& resource_id) const {
    222   GURL result = base_url_.Resolve(
    223       kInitiateUploadExistingFileURLPrefix + net::EscapePath(resource_id));
    224   return AddInitiateUploadUrlParams(result);
    225 }
    226 
    227 GURL GDataWapiUrlGenerator::GenerateResourceListRootUrl() const {
    228   return AddStandardUrlParams(base_url_.Resolve(kResourceListRootURL));
    229 }
    230 
    231 GURL GDataWapiUrlGenerator::GenerateAccountMetadataUrl(
    232     bool include_installed_apps) const {
    233   GURL result = AddStandardUrlParams(base_url_.Resolve(kAccountMetadataURL));
    234   if (include_installed_apps) {
    235     result = net::AppendOrReplaceQueryParameter(
    236         result, "include-installed-apps", "true");
    237   }
    238   return result;
    239 }
    240 
    241 GURL GDataWapiUrlGenerator::GenerateDownloadFileUrl(
    242     const std::string& resource_id) const {
    243   // Strip the file type prefix before the colon character.
    244   size_t colon = resource_id.find(':');
    245   return base_download_url_.Resolve(net::EscapePath(
    246       colon == std::string::npos ? resource_id
    247                                  : resource_id.substr(colon + 1)));
    248 }
    249 
    250 }  // namespace google_apis
    251