1/*
2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "IDBFactory.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "Document.h"
32#include "IDBBindingUtilities.h"
33#include "IDBConnectionProxy.h"
34#include "IDBDatabaseIdentifier.h"
35#include "IDBKey.h"
36#include "IDBOpenDBRequest.h"
37#include "Logging.h"
38#include "Page.h"
39#include "ScriptExecutionContext.h"
40#include "SecurityOrigin.h"
41
42
43namespace WebCore {
44using namespace JSC;
45
46static bool shouldThrowSecurityException(ScriptExecutionContext& context)
47{
48 ASSERT(is<Document>(context) || context.isWorkerGlobalScope());
49 if (is<Document>(context)) {
50 Document& document = downcast<Document>(context);
51 if (!document.frame())
52 return true;
53 if (!document.page())
54 return true;
55 }
56
57 if (!context.securityOrigin()->canAccessDatabase(context.topOrigin()))
58 return true;
59
60 return false;
61}
62
63Ref<IDBFactory> IDBFactory::create(IDBClient::IDBConnectionProxy& connectionProxy)
64{
65 return adoptRef(*new IDBFactory(connectionProxy));
66}
67
68IDBFactory::IDBFactory(IDBClient::IDBConnectionProxy& connectionProxy)
69 : m_connectionProxy(connectionProxy)
70{
71}
72
73IDBFactory::~IDBFactory() = default;
74
75ExceptionOr<Ref<IDBOpenDBRequest>> IDBFactory::open(ScriptExecutionContext& context, const String& name, Optional<uint64_t> version)
76{
77 LOG(IndexedDB, "IDBFactory::open");
78
79 if (version && !version.value())
80 return Exception { TypeError, "IDBFactory.open() called with a version of 0"_s };
81
82 return openInternal(context, name, version.valueOr(0));
83}
84
85ExceptionOr<Ref<IDBOpenDBRequest>> IDBFactory::openInternal(ScriptExecutionContext& context, const String& name, uint64_t version)
86{
87 if (name.isNull())
88 return Exception { TypeError, "IDBFactory.open() called without a database name"_s };
89
90 if (shouldThrowSecurityException(context))
91 return Exception { SecurityError, "IDBFactory.open() called in an invalid security context"_s };
92
93 ASSERT(context.securityOrigin());
94 IDBDatabaseIdentifier databaseIdentifier(name, context.sessionID(), SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() });
95 if (!databaseIdentifier.isValid())
96 return Exception { TypeError, "IDBFactory.open() called with an invalid security origin"_s };
97
98 LOG(IndexedDBOperations, "IDB opening database: %s %" PRIu64, name.utf8().data(), version);
99
100 return m_connectionProxy->openDatabase(context, databaseIdentifier, version);
101}
102
103ExceptionOr<Ref<IDBOpenDBRequest>> IDBFactory::deleteDatabase(ScriptExecutionContext& context, const String& name)
104{
105 LOG(IndexedDB, "IDBFactory::deleteDatabase - %s", name.utf8().data());
106
107 if (name.isNull())
108 return Exception { TypeError, "IDBFactory.deleteDatabase() called without a database name"_s };
109
110 if (shouldThrowSecurityException(context))
111 return Exception { SecurityError, "IDBFactory.deleteDatabase() called in an invalid security context"_s };
112
113 ASSERT(context.securityOrigin());
114 IDBDatabaseIdentifier databaseIdentifier(name, context.sessionID(), SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() });
115 if (!databaseIdentifier.isValid())
116 return Exception { TypeError, "IDBFactory.deleteDatabase() called with an invalid security origin"_s };
117
118 LOG(IndexedDBOperations, "IDB deleting database: %s", name.utf8().data());
119
120 return m_connectionProxy->deleteDatabase(context, databaseIdentifier);
121}
122
123ExceptionOr<short> IDBFactory::cmp(ExecState& execState, JSValue firstValue, JSValue secondValue)
124{
125 auto first = scriptValueToIDBKey(execState, firstValue);
126 if (!first->isValid())
127 return Exception { DataError, "Failed to execute 'cmp' on 'IDBFactory': The parameter is not a valid key."_s };
128
129 auto second = scriptValueToIDBKey(execState, secondValue);
130 if (!second->isValid())
131 return Exception { DataError, "Failed to execute 'cmp' on 'IDBFactory': The parameter is not a valid key."_s };
132
133 return first->compare(second.get());
134}
135
136void IDBFactory::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, Function<void (const Vector<String>&)>&& callback)
137{
138 m_connectionProxy->getAllDatabaseNames(mainFrameOrigin, openingOrigin, WTFMove(callback));
139}
140
141} // namespace WebCore
142
143#endif // ENABLE(INDEXED_DATABASE)
144