1 // Copyright 2013 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 "storage/common/database/database_identifier.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_util.h" 9 #include "url/url_canon.h" 10 11 namespace storage { 12 13 // static 14 std::string GetIdentifierFromOrigin(const GURL& origin) { 15 return DatabaseIdentifier::CreateFromOrigin(origin).ToString(); 16 } 17 18 // static 19 GURL GetOriginFromIdentifier(const std::string& identifier) { 20 return DatabaseIdentifier::Parse(identifier).ToOrigin(); 21 } 22 23 static bool SchemeIsUnique(const std::string& scheme) { 24 return scheme == "about" || scheme == "data" || scheme == "javascript"; 25 } 26 27 // static 28 const DatabaseIdentifier DatabaseIdentifier::UniqueFileIdentifier() { 29 return DatabaseIdentifier("", "", 0, true, true); 30 } 31 32 // static 33 DatabaseIdentifier DatabaseIdentifier::CreateFromOrigin(const GURL& origin) { 34 if (!origin.is_valid() || origin.is_empty() || 35 !origin.IsStandard() || SchemeIsUnique(origin.scheme())) 36 return DatabaseIdentifier(); 37 38 if (origin.SchemeIsFile()) 39 return UniqueFileIdentifier(); 40 41 int port = origin.IntPort(); 42 if (port == url::PORT_INVALID) 43 return DatabaseIdentifier(); 44 45 // We encode the default port for the specified scheme as 0. GURL 46 // canonicalizes this as an unspecified port. 47 if (port == url::PORT_UNSPECIFIED) 48 port = 0; 49 50 return DatabaseIdentifier(origin.scheme(), 51 origin.host(), 52 port, 53 false /* unique */, 54 false /* file */); 55 } 56 57 // static 58 DatabaseIdentifier DatabaseIdentifier::Parse(const std::string& identifier) { 59 if (!base::IsStringASCII(identifier)) 60 return DatabaseIdentifier(); 61 if (identifier.find("..") != std::string::npos) 62 return DatabaseIdentifier(); 63 char forbidden[] = {'\\', '/', ':' ,'\0'}; 64 if (identifier.find_first_of(forbidden, 0, arraysize(forbidden)) != 65 std::string::npos) { 66 return DatabaseIdentifier(); 67 } 68 69 size_t first_underscore = identifier.find_first_of('_'); 70 if (first_underscore == std::string::npos || first_underscore == 0) 71 return DatabaseIdentifier(); 72 73 size_t last_underscore = identifier.find_last_of('_'); 74 if (last_underscore == std::string::npos || 75 last_underscore == first_underscore || 76 last_underscore == identifier.length() - 1) 77 return DatabaseIdentifier(); 78 79 std::string scheme(identifier.data(), first_underscore); 80 if (scheme == "file") 81 return UniqueFileIdentifier(); 82 83 // This magical set of schemes is always treated as unique. 84 if (SchemeIsUnique(scheme)) 85 return DatabaseIdentifier(); 86 87 base::StringPiece port_str(identifier.begin() + last_underscore + 1, 88 identifier.end()); 89 int port = 0; 90 if (!base::StringToInt(port_str, &port) || port < 0 || port >= 1 << 16) 91 return DatabaseIdentifier(); 92 93 std::string hostname(identifier.data() + first_underscore + 1, 94 last_underscore - first_underscore - 1); 95 GURL url(scheme + "://" + hostname + "/"); 96 97 if (!url.IsStandard()) 98 hostname = ""; 99 100 // If a url doesn't parse cleanly or doesn't round trip, reject it. 101 if (!url.is_valid() || url.scheme() != scheme || url.host() != hostname) 102 return DatabaseIdentifier(); 103 104 return DatabaseIdentifier(scheme, hostname, port, false /* unique */, false); 105 } 106 107 DatabaseIdentifier::DatabaseIdentifier() 108 : port_(0), 109 is_unique_(true), 110 is_file_(false) { 111 } 112 113 DatabaseIdentifier::DatabaseIdentifier(const std::string& scheme, 114 const std::string& hostname, 115 int port, 116 bool is_unique, 117 bool is_file) 118 : scheme_(scheme), 119 hostname_(base::StringToLowerASCII(hostname)), 120 port_(port), 121 is_unique_(is_unique), 122 is_file_(is_file) { 123 } 124 125 DatabaseIdentifier::~DatabaseIdentifier() {} 126 127 std::string DatabaseIdentifier::ToString() const { 128 if (is_file_) 129 return "file__0"; 130 if (is_unique_) 131 return "__0"; 132 return scheme_ + "_" + hostname_ + "_" + base::IntToString(port_); 133 } 134 135 GURL DatabaseIdentifier::ToOrigin() const { 136 if (is_file_) 137 return GURL("file:///"); 138 if (is_unique_) 139 return GURL(); 140 if (port_ == 0) 141 return GURL(scheme_ + "://" + hostname_); 142 return GURL(scheme_ + "://" + hostname_ + ":" + base::IntToString(port_)); 143 } 144 145 } // namespace storage 146