Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / chrome / browser / drive / drive_api_util.cc
blob8d153877411a4b0b66f09fbd95d3b4b026d49bcb
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.
5 #include "chrome/browser/drive/drive_api_util.h"
7 #include <string>
9 #include "base/files/file.h"
10 #include "base/logging.h"
11 #include "base/md5.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "net/base/escape.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/net_errors.h"
21 #include "storage/browser/blob/file_stream_reader.h"
22 #include "third_party/re2/re2/re2.h"
23 #include "url/gurl.h"
25 namespace drive {
26 namespace util {
27 namespace {
29 struct HostedDocumentKind {
30 const char* mime_type;
31 const char* extension;
34 const HostedDocumentKind kHostedDocumentKinds[] = {
35 {kGoogleDocumentMimeType, ".gdoc"},
36 {kGoogleSpreadsheetMimeType, ".gsheet"},
37 {kGooglePresentationMimeType, ".gslides"},
38 {kGoogleDrawingMimeType, ".gdraw"},
39 {kGoogleTableMimeType, ".gtable"},
40 {kGoogleFormMimeType, ".gform"},
41 {kGoogleMapMimeType, ".gmaps"},
44 const char kUnknownHostedDocumentExtension[] = ".glink";
46 const int kMd5DigestBufferSize = 512 * 1024; // 512 kB.
48 } // namespace
50 std::string EscapeQueryStringValue(const std::string& str) {
51 std::string result;
52 result.reserve(str.size());
53 for (size_t i = 0; i < str.size(); ++i) {
54 if (str[i] == '\\' || str[i] == '\'') {
55 result.push_back('\\');
57 result.push_back(str[i]);
59 return result;
62 std::string TranslateQuery(const std::string& original_query) {
63 // In order to handle non-ascii white spaces correctly, convert to UTF16.
64 base::string16 query = base::UTF8ToUTF16(original_query);
65 const base::string16 kDelimiter(
66 base::kWhitespaceUTF16 + base::ASCIIToUTF16("\""));
68 std::string result;
69 for (size_t index = query.find_first_not_of(base::kWhitespaceUTF16);
70 index != base::string16::npos;
71 index = query.find_first_not_of(base::kWhitespaceUTF16, index)) {
72 bool is_exclusion = (query[index] == '-');
73 if (is_exclusion)
74 ++index;
75 if (index == query.length()) {
76 // Here, the token is '-' and it should be ignored.
77 continue;
80 size_t begin_token = index;
81 base::string16 token;
82 if (query[begin_token] == '"') {
83 // Quoted query.
84 ++begin_token;
85 size_t end_token = query.find('"', begin_token);
86 if (end_token == base::string16::npos) {
87 // This is kind of syntax error, since quoted string isn't finished.
88 // However, the query is built by user manually, so here we treat
89 // whole remaining string as a token as a fallback, by appending
90 // a missing double-quote character.
91 end_token = query.length();
92 query.push_back('"');
95 token = query.substr(begin_token, end_token - begin_token);
96 index = end_token + 1; // Consume last '"', too.
97 } else {
98 size_t end_token = query.find_first_of(kDelimiter, begin_token);
99 if (end_token == base::string16::npos) {
100 end_token = query.length();
103 token = query.substr(begin_token, end_token - begin_token);
104 index = end_token;
107 if (token.empty()) {
108 // Just ignore an empty token.
109 continue;
112 if (!result.empty()) {
113 // If there are two or more tokens, need to connect with "and".
114 result.append(" and ");
117 // The meaning of "fullText" should include title, description and content.
118 base::StringAppendF(
119 &result,
120 "%sfullText contains \'%s\'",
121 is_exclusion ? "not " : "",
122 EscapeQueryStringValue(base::UTF16ToUTF8(token)).c_str());
125 return result;
128 std::string CanonicalizeResourceId(const std::string& resource_id) {
129 // If resource ID is in the old WAPI format starting with a prefix like
130 // "document:", strip it and return the remaining part.
131 std::string stripped_resource_id;
132 if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
133 &stripped_resource_id))
134 return stripped_resource_id;
135 return resource_id;
138 std::string GetMd5Digest(const base::FilePath& file_path) {
139 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
140 if (!file.IsValid())
141 return std::string();
143 base::MD5Context context;
144 base::MD5Init(&context);
146 int64 offset = 0;
147 scoped_ptr<char[]> buffer(new char[kMd5DigestBufferSize]);
148 while (true) {
149 int result = file.Read(offset, buffer.get(), kMd5DigestBufferSize);
150 if (result < 0) {
151 // Found an error.
152 return std::string();
155 if (result == 0) {
156 // End of file.
157 break;
160 offset += result;
161 base::MD5Update(&context, base::StringPiece(buffer.get(), result));
164 base::MD5Digest digest;
165 base::MD5Final(&digest, &context);
166 return MD5DigestToBase16(digest);
169 FileStreamMd5Digester::FileStreamMd5Digester()
170 : buffer_(new net::IOBuffer(kMd5DigestBufferSize)) {
173 FileStreamMd5Digester::~FileStreamMd5Digester() {
176 void FileStreamMd5Digester::GetMd5Digest(
177 scoped_ptr<storage::FileStreamReader> stream_reader,
178 const ResultCallback& callback) {
179 reader_ = stream_reader.Pass();
180 callback_ = callback;
181 base::MD5Init(&md5_context_);
183 // Start the read/hash.
184 ReadNextChunk();
187 void FileStreamMd5Digester::ReadNextChunk() {
188 const int result = reader_->Read(
189 buffer_.get(), kMd5DigestBufferSize,
190 base::Bind(&FileStreamMd5Digester::OnChunkRead, base::Unretained(this)));
191 if (result != net::ERR_IO_PENDING)
192 OnChunkRead(result);
195 void FileStreamMd5Digester::OnChunkRead(int bytesRead) {
196 if (bytesRead < 0) {
197 // Error - just return empty string.
198 callback_.Run("");
199 return;
200 } else if (bytesRead == 0) {
201 // EOF.
202 base::MD5Digest digest;
203 base::MD5Final(&digest, &md5_context_);
204 std::string result = MD5DigestToBase16(digest);
205 callback_.Run(result);
206 return;
209 // Read data and digest it.
210 base::MD5Update(&md5_context_, base::StringPiece(buffer_->data(), bytesRead));
212 // Kick off the next read.
213 ReadNextChunk();
216 std::string GetHostedDocumentExtension(const std::string& mime_type) {
217 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
218 if (mime_type == kHostedDocumentKinds[i].mime_type)
219 return kHostedDocumentKinds[i].extension;
221 return kUnknownHostedDocumentExtension;
224 bool IsKnownHostedDocumentMimeType(const std::string& mime_type) {
225 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
226 if (mime_type == kHostedDocumentKinds[i].mime_type)
227 return true;
229 return false;
232 bool HasHostedDocumentExtension(const base::FilePath& path) {
233 const std::string extension = base::FilePath(path.Extension()).AsUTF8Unsafe();
234 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
235 if (extension == kHostedDocumentKinds[i].extension)
236 return true;
238 return extension == kUnknownHostedDocumentExtension;
241 } // namespace util
242 } // namespace drive