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 "storage/browser/database/database_util.h"
7 #include "base/basictypes.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "storage/browser/database/database_tracker.h"
10 #include "storage/browser/database/vfs_backend.h"
11 #include "storage/common/database/database_identifier.h"
17 bool IsSafeSuffix(const base::string16
& suffix
) {
18 base::char16 prev_c
= 0;
19 for (base::string16::const_iterator it
= suffix
.begin();
20 it
< suffix
.end(); ++it
) {
22 if (!(base::IsAsciiAlpha(c
) || base::IsAsciiDigit(c
) ||
23 c
== '-' || c
== '.' || c
== '_')) {
26 if (c
== '.' && prev_c
== '.')
35 const char DatabaseUtil::kJournalFileSuffix
[] = "-journal";
37 bool DatabaseUtil::CrackVfsFileName(const base::string16
& vfs_file_name
,
38 std::string
* origin_identifier
,
39 base::string16
* database_name
,
40 base::string16
* sqlite_suffix
) {
41 // 'vfs_file_name' is of the form <origin_identifier>/<db_name>#<suffix>.
42 // <suffix> is optional.
43 DCHECK(!vfs_file_name
.empty());
44 size_t first_slash_index
= vfs_file_name
.find('/');
45 size_t last_pound_index
= vfs_file_name
.rfind('#');
46 // '/' and '#' must be present in the string. Also, the string cannot start
47 // with a '/' (origin_identifier cannot be empty) and '/' must come before '#'
48 if ((first_slash_index
== base::string16::npos
) ||
49 (last_pound_index
== base::string16::npos
) ||
50 (first_slash_index
== 0) ||
51 (first_slash_index
> last_pound_index
)) {
55 std::string origin_id
= base::UTF16ToASCII(
56 vfs_file_name
.substr(0, first_slash_index
));
57 if (!IsValidOriginIdentifier(origin_id
))
60 base::string16 suffix
= vfs_file_name
.substr(
61 last_pound_index
+ 1, vfs_file_name
.length() - last_pound_index
- 1);
62 if (!IsSafeSuffix(suffix
))
65 if (origin_identifier
)
66 *origin_identifier
= origin_id
;
69 *database_name
= vfs_file_name
.substr(
70 first_slash_index
+ 1, last_pound_index
- first_slash_index
- 1);
74 *sqlite_suffix
= suffix
;
79 base::FilePath
DatabaseUtil::GetFullFilePathForVfsFile(
80 DatabaseTracker
* db_tracker
, const base::string16
& vfs_file_name
) {
81 std::string origin_identifier
;
82 base::string16 database_name
;
83 base::string16 sqlite_suffix
;
84 if (!CrackVfsFileName(vfs_file_name
, &origin_identifier
,
85 &database_name
, &sqlite_suffix
)) {
86 return base::FilePath(); // invalid vfs_file_name
89 base::FilePath full_path
= db_tracker
->GetFullDBFilePath(
90 origin_identifier
, database_name
);
91 if (!full_path
.empty() && !sqlite_suffix
.empty()) {
92 DCHECK(full_path
.Extension().empty());
93 full_path
= full_path
.InsertBeforeExtensionASCII(
94 base::UTF16ToASCII(sqlite_suffix
));
96 // Watch out for directory traversal attempts from a compromised renderer.
97 if (full_path
.value().find(FILE_PATH_LITERAL("..")) !=
98 base::FilePath::StringType::npos
)
99 return base::FilePath();
103 bool DatabaseUtil::IsValidOriginIdentifier(
104 const std::string
& origin_identifier
) {
105 return GetOriginFromIdentifier(origin_identifier
).is_valid();
108 } // namespace storage