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 "webkit/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
11namespace webkit_database {
12
13// static
14std::string GetIdentifierFromOrigin(const GURL& origin) {
15  return DatabaseIdentifier::CreateFromOrigin(origin).ToString();
16}
17
18// static
19GURL GetOriginFromIdentifier(const std::string& identifier) {
20  return DatabaseIdentifier::Parse(identifier).ToOrigin();
21}
22
23static bool SchemeIsUnique(const std::string& scheme) {
24  return scheme == "about" || scheme == "data" || scheme == "javascript";
25}
26
27// static
28const DatabaseIdentifier DatabaseIdentifier::UniqueFileIdentifier() {
29  return DatabaseIdentifier("", "", 0, true, true);
30}
31
32// static
33DatabaseIdentifier 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_parse::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_parse::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
58DatabaseIdentifier DatabaseIdentifier::Parse(const std::string& identifier) {
59  if (!IsStringASCII(identifier))
60    return DatabaseIdentifier();
61
62  size_t first_underscore = identifier.find_first_of('_');
63  if (first_underscore == std::string::npos || first_underscore == 0)
64    return DatabaseIdentifier();
65
66  size_t last_underscore = identifier.find_last_of('_');
67  if (last_underscore == std::string::npos ||
68      last_underscore == first_underscore ||
69      last_underscore == identifier.length() - 1)
70    return DatabaseIdentifier();
71
72  std::string scheme(identifier.data(), first_underscore);
73  if (scheme == "file")
74    return UniqueFileIdentifier();
75
76  // This magical set of schemes is always treated as unique.
77  if (SchemeIsUnique(scheme))
78    return DatabaseIdentifier();
79
80  base::StringPiece port_str(identifier.begin() + last_underscore + 1,
81                             identifier.end());
82  int port = 0;
83  if (!base::StringToInt(port_str, &port) || port < 0 || port >= 1 << 16)
84    return DatabaseIdentifier();
85
86  std::string hostname(identifier.data() + first_underscore + 1,
87                       last_underscore - first_underscore - 1);
88  GURL url(scheme + "://" + hostname + "/");
89
90  if (!url.IsStandard())
91    hostname = "";
92
93  // If a url doesn't parse cleanly or doesn't round trip, reject it.
94  if (!url.is_valid() || url.scheme() != scheme || url.host() != hostname)
95    return DatabaseIdentifier();
96
97  return DatabaseIdentifier(scheme, hostname, port, false /* unique */, false);
98}
99
100DatabaseIdentifier::DatabaseIdentifier()
101    : port_(0),
102      is_unique_(true),
103      is_file_(false) {
104}
105
106DatabaseIdentifier::DatabaseIdentifier(const std::string& scheme,
107                                       const std::string& hostname,
108                                       int port,
109                                       bool is_unique,
110                                       bool is_file)
111    : scheme_(scheme),
112      hostname_(StringToLowerASCII(hostname)),
113      port_(port),
114      is_unique_(is_unique),
115      is_file_(is_file) {
116}
117
118DatabaseIdentifier::~DatabaseIdentifier() {}
119
120std::string DatabaseIdentifier::ToString() const {
121  if (is_file_)
122    return "file__0";
123  if (is_unique_)
124    return "__0";
125  return scheme_ + "_" + hostname_ + "_" + base::IntToString(port_);
126}
127
128GURL DatabaseIdentifier::ToOrigin() const {
129  if (is_file_)
130    return GURL("file:///");
131  if (is_unique_)
132    return GURL();
133  if (port_ == 0)
134    return GURL(scheme_ + "://" + hostname_);
135  return GURL(scheme_ + "://" + hostname_ + ":" + base::IntToString(port_));
136}
137
138}  // namespace webkit_database
139