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