Home | History | Annotate | Download | only in database
      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