Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: mojo/public/js/new_bindings/validator.js

Issue 2736273002: Mojo JS bindings: duplicate the bindings files into src/mojo/public/js/new_bindings. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/public/js/new_bindings/unicode.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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 define("mojo/public/js/validator", [
6 "mojo/public/js/codec",
7 ], function(codec) {
8
9 var validationError = {
10 NONE: 'VALIDATION_ERROR_NONE',
11 MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
12 ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
13 UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
14 UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
15 ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
16 UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
17 ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
18 UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
19 MESSAGE_HEADER_INVALID_FLAGS:
20 'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS',
21 MESSAGE_HEADER_MISSING_REQUEST_ID:
22 'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID',
23 DIFFERENT_SIZED_ARRAYS_IN_MAP:
24 'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
25 INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
26 UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
27 UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
28 };
29
30 var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
31
32 function isEnumClass(cls) {
33 return cls instanceof codec.Enum;
34 }
35
36 function isStringClass(cls) {
37 return cls === codec.String || cls === codec.NullableString;
38 }
39
40 function isHandleClass(cls) {
41 return cls === codec.Handle || cls === codec.NullableHandle;
42 }
43
44 function isInterfaceClass(cls) {
45 return cls instanceof codec.Interface;
46 }
47
48 function isInterfaceRequestClass(cls) {
49 return cls === codec.InterfaceRequest ||
50 cls === codec.NullableInterfaceRequest;
51 }
52
53 function isNullable(type) {
54 return type === codec.NullableString || type === codec.NullableHandle ||
55 type === codec.NullableInterface ||
56 type === codec.NullableInterfaceRequest ||
57 type instanceof codec.NullableArrayOf ||
58 type instanceof codec.NullablePointerTo;
59 }
60
61 function Validator(message) {
62 this.message = message;
63 this.offset = 0;
64 this.handleIndex = 0;
65 }
66
67 Object.defineProperty(Validator.prototype, "offsetLimit", {
68 get: function() { return this.message.buffer.byteLength; }
69 });
70
71 Object.defineProperty(Validator.prototype, "handleIndexLimit", {
72 get: function() { return this.message.handles.length; }
73 });
74
75 // True if we can safely allocate a block of bytes from start to
76 // to start + numBytes.
77 Validator.prototype.isValidRange = function(start, numBytes) {
78 // Only positive JavaScript integers that are less than 2^53
79 // (Number.MAX_SAFE_INTEGER) can be represented exactly.
80 if (start < this.offset || numBytes <= 0 ||
81 !Number.isSafeInteger(start) ||
82 !Number.isSafeInteger(numBytes))
83 return false;
84
85 var newOffset = start + numBytes;
86 if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
87 return false;
88
89 return true;
90 };
91
92 Validator.prototype.claimRange = function(start, numBytes) {
93 if (this.isValidRange(start, numBytes)) {
94 this.offset = start + numBytes;
95 return true;
96 }
97 return false;
98 };
99
100 Validator.prototype.claimHandle = function(index) {
101 if (index === codec.kEncodedInvalidHandleValue)
102 return true;
103
104 if (index < this.handleIndex || index >= this.handleIndexLimit)
105 return false;
106
107 // This is safe because handle indices are uint32.
108 this.handleIndex = index + 1;
109 return true;
110 };
111
112 Validator.prototype.validateEnum = function(offset, enumClass) {
113 // Note: Assumes that enums are always 32 bits! But this matches
114 // mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
115 var value = this.message.buffer.getInt32(offset);
116 return enumClass.validate(value);
117 }
118
119 Validator.prototype.validateHandle = function(offset, nullable) {
120 var index = this.message.buffer.getUint32(offset);
121
122 if (index === codec.kEncodedInvalidHandleValue)
123 return nullable ?
124 validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;
125
126 if (!this.claimHandle(index))
127 return validationError.ILLEGAL_HANDLE;
128
129 return validationError.NONE;
130 };
131
132 Validator.prototype.validateInterface = function(offset, nullable) {
133 return this.validateHandle(offset, nullable);
134 };
135
136 Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
137 return this.validateHandle(offset, nullable);
138 };
139
140 Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
141 if (!codec.isAligned(offset))
142 return validationError.MISALIGNED_OBJECT;
143
144 if (!this.isValidRange(offset, codec.kStructHeaderSize))
145 return validationError.ILLEGAL_MEMORY_RANGE;
146
147 var numBytes = this.message.buffer.getUint32(offset);
148
149 if (numBytes < minNumBytes)
150 return validationError.UNEXPECTED_STRUCT_HEADER;
151
152 if (!this.claimRange(offset, numBytes))
153 return validationError.ILLEGAL_MEMORY_RANGE;
154
155 return validationError.NONE;
156 };
157
158 Validator.prototype.validateStructVersion = function(offset, versionSizes) {
159 var numBytes = this.message.buffer.getUint32(offset);
160 var version = this.message.buffer.getUint32(offset + 4);
161
162 if (version <= versionSizes[versionSizes.length - 1].version) {
163 // Scan in reverse order to optimize for more recent versionSizes.
164 for (var i = versionSizes.length - 1; i >= 0; --i) {
165 if (version >= versionSizes[i].version) {
166 if (numBytes == versionSizes[i].numBytes)
167 break;
168 return validationError.UNEXPECTED_STRUCT_HEADER;
169 }
170 }
171 } else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
172 return validationError.UNEXPECTED_STRUCT_HEADER;
173 }
174
175 return validationError.NONE;
176 };
177
178 Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
179 var structVersion = this.message.buffer.getUint32(offset + 4);
180 return fieldVersion <= structVersion;
181 };
182
183 Validator.prototype.validateMessageHeader = function() {
184
185 var err = this.validateStructHeader(0, codec.kMessageHeaderSize);
186 if (err != validationError.NONE)
187 return err;
188
189 var numBytes = this.message.getHeaderNumBytes();
190 var version = this.message.getHeaderVersion();
191
192 var validVersionAndNumBytes =
193 (version == 0 && numBytes == codec.kMessageHeaderSize) ||
194 (version == 1 &&
195 numBytes == codec.kMessageWithRequestIDHeaderSize) ||
196 (version > 1 &&
197 numBytes >= codec.kMessageWithRequestIDHeaderSize);
198 if (!validVersionAndNumBytes)
199 return validationError.UNEXPECTED_STRUCT_HEADER;
200
201 var expectsResponse = this.message.expectsResponse();
202 var isResponse = this.message.isResponse();
203
204 if (version == 0 && (expectsResponse || isResponse))
205 return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
206
207 if (isResponse && expectsResponse)
208 return validationError.MESSAGE_HEADER_INVALID_FLAGS;
209
210 return validationError.NONE;
211 };
212
213 Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
214 if (this.message.isResponse() || this.message.expectsResponse()) {
215 return validationError.MESSAGE_HEADER_INVALID_FLAGS;
216 }
217 return validationError.NONE;
218 };
219
220 Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
221 if (this.message.isResponse() || !this.message.expectsResponse()) {
222 return validationError.MESSAGE_HEADER_INVALID_FLAGS;
223 }
224 return validationError.NONE;
225 };
226
227 Validator.prototype.validateMessageIsResponse = function() {
228 if (this.message.expectsResponse() || !this.message.isResponse()) {
229 return validationError.MESSAGE_HEADER_INVALID_FLAGS;
230 }
231 return validationError.NONE;
232 };
233
234 // Returns the message.buffer relative offset this pointer "points to",
235 // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
236 // pointer's value is not valid.
237 Validator.prototype.decodePointer = function(offset) {
238 var pointerValue = this.message.buffer.getUint64(offset);
239 if (pointerValue === 0)
240 return NULL_MOJO_POINTER;
241 var bufferOffset = offset + pointerValue;
242 return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
243 };
244
245 Validator.prototype.decodeUnionSize = function(offset) {
246 return this.message.buffer.getUint32(offset);
247 };
248
249 Validator.prototype.decodeUnionTag = function(offset) {
250 return this.message.buffer.getUint32(offset + 4);
251 };
252
253 Validator.prototype.validateArrayPointer = function(
254 offset, elementSize, elementType, nullable, expectedDimensionSizes,
255 currentDimension) {
256 var arrayOffset = this.decodePointer(offset);
257 if (arrayOffset === null)
258 return validationError.ILLEGAL_POINTER;
259
260 if (arrayOffset === NULL_MOJO_POINTER)
261 return nullable ?
262 validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
263
264 return this.validateArray(arrayOffset, elementSize, elementType,
265 expectedDimensionSizes, currentDimension);
266 };
267
268 Validator.prototype.validateStructPointer = function(
269 offset, structClass, nullable) {
270 var structOffset = this.decodePointer(offset);
271 if (structOffset === null)
272 return validationError.ILLEGAL_POINTER;
273
274 if (structOffset === NULL_MOJO_POINTER)
275 return nullable ?
276 validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
277
278 return structClass.validate(this, structOffset);
279 };
280
281 Validator.prototype.validateUnion = function(
282 offset, unionClass, nullable) {
283 var size = this.message.buffer.getUint32(offset);
284 if (size == 0) {
285 return nullable ?
286 validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
287 }
288
289 return unionClass.validate(this, offset);
290 };
291
292 Validator.prototype.validateNestedUnion = function(
293 offset, unionClass, nullable) {
294 var unionOffset = this.decodePointer(offset);
295 if (unionOffset === null)
296 return validationError.ILLEGAL_POINTER;
297
298 if (unionOffset === NULL_MOJO_POINTER)
299 return nullable ?
300 validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
301
302 return this.validateUnion(unionOffset, unionClass, nullable);
303 };
304
305 // This method assumes that the array at arrayPointerOffset has
306 // been validated.
307
308 Validator.prototype.arrayLength = function(arrayPointerOffset) {
309 var arrayOffset = this.decodePointer(arrayPointerOffset);
310 return this.message.buffer.getUint32(arrayOffset + 4);
311 };
312
313 Validator.prototype.validateMapPointer = function(
314 offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
315 // Validate the implicit map struct:
316 // struct {array<keyClass> keys; array<valueClass> values};
317 var structOffset = this.decodePointer(offset);
318 if (structOffset === null)
319 return validationError.ILLEGAL_POINTER;
320
321 if (structOffset === NULL_MOJO_POINTER)
322 return mapIsNullable ?
323 validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
324
325 var mapEncodedSize = codec.kStructHeaderSize + codec.kMapStructPayloadSize;
326 var err = this.validateStructHeader(structOffset, mapEncodedSize);
327 if (err !== validationError.NONE)
328 return err;
329
330 // Validate the keys array.
331 var keysArrayPointerOffset = structOffset + codec.kStructHeaderSize;
332 err = this.validateArrayPointer(
333 keysArrayPointerOffset, keyClass.encodedSize, keyClass, false, [0], 0);
334 if (err !== validationError.NONE)
335 return err;
336
337 // Validate the values array.
338 var valuesArrayPointerOffset = keysArrayPointerOffset + 8;
339 var valuesArrayDimensions = [0]; // Validate the actual length below.
340 if (valueClass instanceof codec.ArrayOf)
341 valuesArrayDimensions =
342 valuesArrayDimensions.concat(valueClass.dimensions());
343 var err = this.validateArrayPointer(valuesArrayPointerOffset,
344 valueClass.encodedSize,
345 valueClass,
346 valueIsNullable,
347 valuesArrayDimensions,
348 0);
349 if (err !== validationError.NONE)
350 return err;
351
352 // Validate the lengths of the keys and values arrays.
353 var keysArrayLength = this.arrayLength(keysArrayPointerOffset);
354 var valuesArrayLength = this.arrayLength(valuesArrayPointerOffset);
355 if (keysArrayLength != valuesArrayLength)
356 return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
357
358 return validationError.NONE;
359 };
360
361 Validator.prototype.validateStringPointer = function(offset, nullable) {
362 return this.validateArrayPointer(
363 offset, codec.Uint8.encodedSize, codec.Uint8, nullable, [0], 0);
364 };
365
366 // Similar to Array_Data<T>::Validate()
367 // mojo/public/cpp/bindings/lib/array_internal.h
368
369 Validator.prototype.validateArray =
370 function (offset, elementSize, elementType, expectedDimensionSizes,
371 currentDimension) {
372 if (!codec.isAligned(offset))
373 return validationError.MISALIGNED_OBJECT;
374
375 if (!this.isValidRange(offset, codec.kArrayHeaderSize))
376 return validationError.ILLEGAL_MEMORY_RANGE;
377
378 var numBytes = this.message.buffer.getUint32(offset);
379 var numElements = this.message.buffer.getUint32(offset + 4);
380
381 // Note: this computation is "safe" because elementSize <= 8 and
382 // numElements is a uint32.
383 var elementsTotalSize = (elementType === codec.PackedBool) ?
384 Math.ceil(numElements / 8) : (elementSize * numElements);
385
386 if (numBytes < codec.kArrayHeaderSize + elementsTotalSize)
387 return validationError.UNEXPECTED_ARRAY_HEADER;
388
389 if (expectedDimensionSizes[currentDimension] != 0 &&
390 numElements != expectedDimensionSizes[currentDimension]) {
391 return validationError.UNEXPECTED_ARRAY_HEADER;
392 }
393
394 if (!this.claimRange(offset, numBytes))
395 return validationError.ILLEGAL_MEMORY_RANGE;
396
397 // Validate the array's elements if they are pointers or handles.
398
399 var elementsOffset = offset + codec.kArrayHeaderSize;
400 var nullable = isNullable(elementType);
401
402 if (isHandleClass(elementType))
403 return this.validateHandleElements(elementsOffset, numElements, nullable);
404 if (isInterfaceClass(elementType))
405 return this.validateInterfaceElements(
406 elementsOffset, numElements, nullable);
407 if (isInterfaceRequestClass(elementType))
408 return this.validateInterfaceRequestElements(
409 elementsOffset, numElements, nullable);
410 if (isStringClass(elementType))
411 return this.validateArrayElements(
412 elementsOffset, numElements, codec.Uint8, nullable, [0], 0);
413 if (elementType instanceof codec.PointerTo)
414 return this.validateStructElements(
415 elementsOffset, numElements, elementType.cls, nullable);
416 if (elementType instanceof codec.ArrayOf)
417 return this.validateArrayElements(
418 elementsOffset, numElements, elementType.cls, nullable,
419 expectedDimensionSizes, currentDimension + 1);
420 if (isEnumClass(elementType))
421 return this.validateEnumElements(elementsOffset, numElements,
422 elementType.cls);
423
424 return validationError.NONE;
425 };
426
427 // Note: the |offset + i * elementSize| computation in the validateFooElements
428 // methods below is "safe" because elementSize <= 8, offset and
429 // numElements are uint32, and 0 <= i < numElements.
430
431 Validator.prototype.validateHandleElements =
432 function(offset, numElements, nullable) {
433 var elementSize = codec.Handle.encodedSize;
434 for (var i = 0; i < numElements; i++) {
435 var elementOffset = offset + i * elementSize;
436 var err = this.validateHandle(elementOffset, nullable);
437 if (err != validationError.NONE)
438 return err;
439 }
440 return validationError.NONE;
441 };
442
443 Validator.prototype.validateInterfaceElements =
444 function(offset, numElements, nullable) {
445 var elementSize = codec.Interface.prototype.encodedSize;
446 for (var i = 0; i < numElements; i++) {
447 var elementOffset = offset + i * elementSize;
448 var err = this.validateInterface(elementOffset, nullable);
449 if (err != validationError.NONE)
450 return err;
451 }
452 return validationError.NONE;
453 };
454
455 Validator.prototype.validateInterfaceRequestElements =
456 function(offset, numElements, nullable) {
457 var elementSize = codec.InterfaceRequest.encodedSize;
458 for (var i = 0; i < numElements; i++) {
459 var elementOffset = offset + i * elementSize;
460 var err = this.validateInterfaceRequest(elementOffset, nullable);
461 if (err != validationError.NONE)
462 return err;
463 }
464 return validationError.NONE;
465 };
466
467 // The elementClass parameter is the element type of the element arrays.
468 Validator.prototype.validateArrayElements =
469 function(offset, numElements, elementClass, nullable,
470 expectedDimensionSizes, currentDimension) {
471 var elementSize = codec.PointerTo.prototype.encodedSize;
472 for (var i = 0; i < numElements; i++) {
473 var elementOffset = offset + i * elementSize;
474 var err = this.validateArrayPointer(
475 elementOffset, elementClass.encodedSize, elementClass, nullable,
476 expectedDimensionSizes, currentDimension);
477 if (err != validationError.NONE)
478 return err;
479 }
480 return validationError.NONE;
481 };
482
483 Validator.prototype.validateStructElements =
484 function(offset, numElements, structClass, nullable) {
485 var elementSize = codec.PointerTo.prototype.encodedSize;
486 for (var i = 0; i < numElements; i++) {
487 var elementOffset = offset + i * elementSize;
488 var err =
489 this.validateStructPointer(elementOffset, structClass, nullable);
490 if (err != validationError.NONE)
491 return err;
492 }
493 return validationError.NONE;
494 };
495
496 Validator.prototype.validateEnumElements =
497 function(offset, numElements, enumClass) {
498 var elementSize = codec.Enum.prototype.encodedSize;
499 for (var i = 0; i < numElements; i++) {
500 var elementOffset = offset + i * elementSize;
501 var err = this.validateEnum(elementOffset, enumClass);
502 if (err != validationError.NONE)
503 return err;
504 }
505 return validationError.NONE;
506 };
507
508 var exports = {};
509 exports.validationError = validationError;
510 exports.Validator = Validator;
511 return exports;
512 });
OLDNEW
« no previous file with comments | « mojo/public/js/new_bindings/unicode.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698