Home | History | Annotate | Download | only in drive
      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/drive/drive_api_util.h"
      6 
      7 #include <string>
      8 
      9 #include "base/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/strings/string16.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/drive/drive_switches.h"
     17 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "net/base/escape.h"
     20 #include "third_party/re2/re2/re2.h"
     21 #include "url/gurl.h"
     22 
     23 namespace drive {
     24 namespace util {
     25 
     26 bool IsDriveV2ApiEnabled() {
     27   const CommandLine* command_line = CommandLine::ForCurrentProcess();
     28 
     29   // Disable Drive API v2 by default.
     30   if (!command_line->HasSwitch(switches::kEnableDriveV2Api))
     31     return false;
     32 
     33   std::string value =
     34       command_line->GetSwitchValueASCII(switches::kEnableDriveV2Api);
     35   StringToLowerASCII(&value);
     36   // The value must be "" or "true" for true, or "false" for false.
     37   DCHECK(value.empty() || value == "true" || value == "false");
     38   return value != "false";
     39 }
     40 
     41 std::string EscapeQueryStringValue(const std::string& str) {
     42   std::string result;
     43   result.reserve(str.size());
     44   for (size_t i = 0; i < str.size(); ++i) {
     45     if (str[i] == '\\' || str[i] == '\'') {
     46       result.push_back('\\');
     47     }
     48     result.push_back(str[i]);
     49   }
     50   return result;
     51 }
     52 
     53 std::string TranslateQuery(const std::string& original_query) {
     54   // In order to handle non-ascii white spaces correctly, convert to UTF16.
     55   base::string16 query = UTF8ToUTF16(original_query);
     56   const base::string16 kDelimiter(
     57       kWhitespaceUTF16 + base::string16(1, static_cast<char16>('"')));
     58 
     59   std::string result;
     60   for (size_t index = query.find_first_not_of(kWhitespaceUTF16);
     61        index != base::string16::npos;
     62        index = query.find_first_not_of(kWhitespaceUTF16, index)) {
     63     bool is_exclusion = (query[index] == '-');
     64     if (is_exclusion)
     65       ++index;
     66     if (index == query.length()) {
     67       // Here, the token is '-' and it should be ignored.
     68       continue;
     69     }
     70 
     71     size_t begin_token = index;
     72     base::string16 token;
     73     if (query[begin_token] == '"') {
     74       // Quoted query.
     75       ++begin_token;
     76       size_t end_token = query.find('"', begin_token);
     77       if (end_token == base::string16::npos) {
     78         // This is kind of syntax error, since quoted string isn't finished.
     79         // However, the query is built by user manually, so here we treat
     80         // whole remaining string as a token as a fallback, by appending
     81         // a missing double-quote character.
     82         end_token = query.length();
     83         query.push_back('"');
     84       }
     85 
     86       token = query.substr(begin_token, end_token - begin_token);
     87       index = end_token + 1;  // Consume last '"', too.
     88     } else {
     89       size_t end_token = query.find_first_of(kDelimiter, begin_token);
     90       if (end_token == base::string16::npos) {
     91         end_token = query.length();
     92       }
     93 
     94       token = query.substr(begin_token, end_token - begin_token);
     95       index = end_token;
     96     }
     97 
     98     if (token.empty()) {
     99       // Just ignore an empty token.
    100       continue;
    101     }
    102 
    103     if (!result.empty()) {
    104       // If there are two or more tokens, need to connect with "and".
    105       result.append(" and ");
    106     }
    107 
    108     // The meaning of "fullText" should include title, description and content.
    109     base::StringAppendF(
    110         &result,
    111         "%sfullText contains \'%s\'",
    112         is_exclusion ? "not " : "",
    113         EscapeQueryStringValue(UTF16ToUTF8(token)).c_str());
    114   }
    115 
    116   return result;
    117 }
    118 
    119 std::string ExtractResourceIdFromUrl(const GURL& url) {
    120   return net::UnescapeURLComponent(url.ExtractFileName(),
    121                                    net::UnescapeRule::URL_SPECIAL_CHARS);
    122 }
    123 
    124 std::string CanonicalizeResourceId(const std::string& resource_id) {
    125   // If resource ID is in the old WAPI format starting with a prefix like
    126   // "document:", strip it and return the remaining part.
    127   std::string stripped_resource_id;
    128   if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
    129                      &stripped_resource_id))
    130     return stripped_resource_id;
    131   return resource_id;
    132 }
    133 
    134 const char kDocsListScope[] = "https://docs.google.com/feeds/";
    135 const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
    136 
    137 void ParseShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
    138                          google_apis::GDataErrorCode error,
    139                          scoped_ptr<base::Value> value) {
    140   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    141 
    142   if (!value) {
    143     callback.Run(error, GURL());
    144     return;
    145   }
    146 
    147   // Parsing ResourceEntry is cheap enough to do on UI thread.
    148   scoped_ptr<google_apis::ResourceEntry> entry =
    149       google_apis::ResourceEntry::ExtractAndParse(*value);
    150   if (!entry) {
    151     callback.Run(google_apis::GDATA_PARSE_ERROR, GURL());
    152     return;
    153   }
    154 
    155   const google_apis::Link* share_link =
    156       entry->GetLinkByType(google_apis::Link::LINK_SHARE);
    157   callback.Run(error, share_link ? share_link->href() : GURL());
    158 }
    159 
    160 }  // namespace util
    161 }  // namespace drive
    162