Index: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc |
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc |
index 8068a7f3d96d991b71c71c12ef21388c5cf251f3..26c3db560f4e50625ccf73fa079cafbbdc6bb89f 100644 |
--- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc |
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc |
@@ -14,11 +14,48 @@ |
namespace arc { |
+// This is based on net/base/escape.cc: net::(anonymous namespace)::Escape. |
+// TODO(nya): Consider consolidating this function with EscapeFileSystemId() in |
+// chrome/browser/chromeos/file_system_provider/mount_path_util.cc. |
+// This version differs from the other one in the point that dots are not always |
+// escaped because authorities often contain harmless dots. |
+std::string EscapePathComponent(const std::string& name) { |
+ std::string escaped; |
+ // Escape dots only when they forms a special file name. |
+ if (name == "." || name == "..") { |
+ base::ReplaceChars(name, ".", "%2E", &escaped); |
+ return escaped; |
+ } |
+ // Escape % and / only. |
+ for (size_t i = 0; i < name.size(); ++i) { |
+ const char c = name[i]; |
+ if (c == '%' || c == '/') |
+ base::StringAppendF(&escaped, "%%%02X", c); |
+ else |
+ escaped.push_back(c); |
+ } |
+ return escaped; |
+} |
+ |
+std::string UnescapePathComponent(const std::string& escaped) { |
+ return net::UnescapeURLComponent( |
+ escaped, net::UnescapeRule::PATH_SEPARATORS | |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); |
+} |
+ |
const char kDocumentsProviderMountPointName[] = "arc-documents-provider"; |
const base::FilePath::CharType kDocumentsProviderMountPointPath[] = |
"/special/arc-documents-provider"; |
const char kAndroidDirectoryMimeType[] = "vnd.android.document/directory"; |
+base::FilePath GetDocumentsProviderMountPath( |
+ const std::string& authority, |
+ const std::string& root_document_id) { |
+ return base::FilePath(kDocumentsProviderMountPointPath) |
+ .Append(EscapePathComponent(authority)) |
+ .Append(EscapePathComponent(root_document_id)); |
+} |
+ |
bool ParseDocumentsProviderUrl(const storage::FileSystemURL& url, |
std::string* authority, |
std::string* root_document_id, |
@@ -39,12 +76,11 @@ bool ParseDocumentsProviderUrl(const storage::FileSystemURL& url, |
if (components.size() < 5) |
return false; |
- *authority = components[3]; |
- *root_document_id = components[4]; |
+ *authority = UnescapePathComponent(components[3]); |
+ *root_document_id = UnescapePathComponent(components[4]); |
- base::FilePath root_path = base::FilePath(kDocumentsProviderMountPointPath) |
- .Append(*authority) |
- .Append(*root_document_id); |
+ base::FilePath root_path = |
+ GetDocumentsProviderMountPath(*authority, *root_document_id); |
// Special case: AppendRelativePath() fails for identical paths. |
if (url_path_stripped == root_path) { |
path->clear(); |