blob: 608d0f9ad2951b1cf714be168d2550db7757681e [file] [log] [blame]
pwnallde422a82017-02-08 01:30:141<!doctype html>
2<meta charset=utf-8>
3<title>IndexedDB: Exceptions thrown during key conversion</title>
4<script src="/resources/testharness.js"></script>
5<script src="/resources/testharnessreport.js"></script>
6<script src="support.js"></script>
7<script>
8
9// Convenience function for tests that only need to run code in onupgradeneeded.
10function indexeddb_upgrade_only_test(upgrade_callback, description) {
11 indexeddb_test(upgrade_callback, t => { t.done(); }, description);
12}
13
14// Key that throws during conversion.
15function throwing_key(name) {
16 var throws = [];
17 throws.length = 1;
18 Object.defineProperty(throws, '0', {get: function() {
19 var err = new Error('throwing from getter');
20 err.name = name;
21 throw err;
22 }, enumerable: true});
23 return throws;
24}
25
26var valid_key = [];
27var invalid_key = {};
28
29// Calls method on receiver with the specified number of args (default 1)
30// and asserts that the method fails appropriately (rethrowing if
31// conversion throws, or DataError if not a valid key), and that
32// the first argument is fully processed before the second argument
33// (if appropriate).
34function check_method(receiver, method, args) {
35 args = args || 1;
36 if (args < 2) {
37 assert_throws({name:'getter'}, () => {
38 receiver[method](throwing_key('getter'));
39 }, 'key conversion with throwing getter should rethrow');
40
41 assert_throws('DataError', () => {
42 receiver[method](invalid_key);
43 }, 'key conversion with invalid key should throw DataError');
44 } else {
45 assert_throws({name:'getter 1'}, () => {
46 receiver[method](throwing_key('getter 1'), throwing_key('getter 2'));
47 }, 'first key conversion with throwing getter should rethrow');
48
49 assert_throws('DataError', () => {
50 receiver[method](invalid_key, throwing_key('getter 2'));
51 }, 'first key conversion with invalid key should throw DataError');
52
53 assert_throws({name:'getter 2'}, () => {
54 receiver[method](valid_key, throwing_key('getter 2'));
55 }, 'second key conversion with throwing getter should rethrow');
56
57 assert_throws('DataError', () => {
58 receiver[method](valid_key, invalid_key);
59 }, 'second key conversion with invalid key should throw DataError');
60 }
61}
62
63// Static key comparison utility on IDBFactory.
64test(t => {
65 check_method(indexedDB, 'cmp', 2);
66}, 'IDBFactory cmp() static with throwing/invalid keys');
67
68// Continue methods on IDBCursor.
69indexeddb_upgrade_only_test((t, db) => {
70 var store = db.createObjectStore('store');
71 store.put('a', 1).onerror = t.unreached_func('put should succeed');
72
73 var request = store.openCursor();
74 request.onerror = t.unreached_func('openCursor should succeed');
75 request.onsuccess = t.step_func(() => {
76 var cursor = request.result;
77 assert_not_equals(cursor, null, 'cursor should find a value');
78 check_method(cursor, 'continue');
79 });
80}, 'IDBCursor continue() method with throwing/invalid keys');
81
82indexeddb_upgrade_only_test((t, db) => {
83 var store = db.createObjectStore('store');
84 var index = store.createIndex('index', 'prop');
85 store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed');
86
87 var request = index.openCursor();
88 request.onerror = t.unreached_func('openCursor should succeed');
89 request.onsuccess = t.step_func(() => {
90 var cursor = request.result;
91 assert_not_equals(cursor, null, 'cursor should find a value');
92
93 check_method(cursor, 'continuePrimaryKey', 2);
94 });
95}, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys');
96
97// Mutation methods on IDBCursor.
98indexeddb_upgrade_only_test((t, db) => {
99 var store = db.createObjectStore('store', {keyPath: 'prop'});
100 store.put({prop: 1}).onerror = t.unreached_func('put should succeed');
101
102 var request = store.openCursor();
103 request.onerror = t.unreached_func('openCursor should succeed');
104 request.onsuccess = t.step_func(() => {
105 var cursor = request.result;
106 assert_not_equals(cursor, null, 'cursor should find a value');
107
108 var value = {};
109 value.prop = throwing_key('getter');
110 assert_throws({name: 'getter'}, () => {
111 cursor.update(value);
112 }, 'throwing getter should rethrow during clone');
113
114 // Throwing from the getter during key conversion is
115 // not possible since (1) a clone is used, (2) only own
116 // properties are cloned, and (3) only own properties
117 // are used for key path evaluation.
118
119 value.prop = invalid_key;
120 assert_throws('DataError', () => {
121 cursor.update(value);
122 }, 'key conversion with invalid key should throw DataError');
123 });
124}, 'IDBCursor update() method with throwing/invalid keys');
125
126// Static constructors on IDBKeyRange
127['only', 'lowerBound', 'upperBound'].forEach(method => {
128 test(t => {
129 check_method(IDBKeyRange, method);
130 }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys');
131});
132
133test(t => {
134 check_method(IDBKeyRange, 'bound', 2);
135}, 'IDBKeyRange bound() static with throwing/invalid keys');
136
137// Insertion methods on IDBObjectStore.
138['add', 'put'].forEach(method => {
139 indexeddb_upgrade_only_test((t, db) => {
140 var out_of_line = db.createObjectStore('out-of-line keys');
141 var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'});
142
143 assert_throws({name:'getter'}, () => {
144 out_of_line[method]('value', throwing_key('getter'));
145 }, 'key conversion with throwing getter should rethrow');
146
147 assert_throws('DataError', () => {
148 out_of_line[method]('value', invalid_key);
149 }, 'key conversion with invalid key should throw DataError');
150
151 var value = {};
152 value.prop = throwing_key('getter');
153 assert_throws({name:'getter'}, () => {
154 in_line[method](value);
155 }, 'throwing getter should rethrow during clone');
156
157 // Throwing from the getter during key conversion is
158 // not possible since (1) a clone is used, (2) only own
159 // properties are cloned, and (3) only own properties
160 // are used for key path evaluation.
161
162 value.prop = invalid_key;
163 assert_throws('DataError', () => {
164 in_line[method](value);
165 }, 'key conversion with invalid key should throw DataError');
166 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
167});
168
169// Generic (key-or-key-path) methods on IDBObjectStore.
170[
171 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
172 'openKeyCursor'
173].forEach(method => {
174 indexeddb_upgrade_only_test((t, db) => {
175 var store = db.createObjectStore('store');
176
177 check_method(store, method);
178 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
179});
180
181// Generic (key-or-key-path) methods on IDBIndex.
182[
183 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
184 'openKeyCursor'
185].forEach(method => {
186 indexeddb_upgrade_only_test((t, db) => {
187 var store = db.createObjectStore('store');
188 var index = store.createIndex('index', 'keyPath');
189
190 check_method(index, method);
191 }, `IDBIndex ${method}() method with throwing/invalid keys`);
192});
193
194</script>