| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 define("mojo/public/js/bindings/validator", [ | 5 define("mojo/public/js/bindings/validator", [ |
| 6 "mojo/public/js/bindings/codec", | 6 "mojo/public/js/bindings/codec", |
| 7 ], function(codec) { | 7 ], function(codec) { |
| 8 | 8 |
| 9 var validationError = { | 9 var validationError = { |
| 10 NONE: 'VALIDATION_ERROR_NONE', | 10 NONE: 'VALIDATION_ERROR_NONE', |
| 11 MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT', | 11 MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT', |
| 12 ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE', | 12 ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE', |
| 13 UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER', | 13 UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER', |
| 14 UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER', | 14 UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER', |
| 15 ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE', | 15 ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE', |
| 16 UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE', |
| 16 ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER', | 17 ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER', |
| 18 UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER', |
| 17 MESSAGE_HEADER_INVALID_FLAG_COMBINATION: | 19 MESSAGE_HEADER_INVALID_FLAG_COMBINATION: |
| 18 'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION', | 20 'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION', |
| 19 MESSAGE_HEADER_MISSING_REQUEST_ID: | 21 MESSAGE_HEADER_MISSING_REQUEST_ID: |
| 20 'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID' | 22 'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID' |
| 21 }; | 23 }; |
| 22 | 24 |
| 23 var NULL_MOJO_POINTER = "NULL_MOJO_POINTER"; | 25 var NULL_MOJO_POINTER = "NULL_MOJO_POINTER"; |
| 24 | 26 |
| 27 function isStringClass(cls) { |
| 28 return cls === codec.String || cls === codec.NullableString; |
| 29 } |
| 30 |
| 31 function isHandleClass(cls) { |
| 32 return cls === codec.Handle || cls === codec.NullableHandle; |
| 33 } |
| 34 |
| 35 function isNullable(type) { |
| 36 return type === codec.NullableString || type === codec.NullableHandle || |
| 37 type instanceof codec.NullableArrayOf || |
| 38 type instanceof codec.NullablePointerTo; |
| 39 } |
| 40 |
| 25 function Validator(message) { | 41 function Validator(message) { |
| 26 this.message = message; | 42 this.message = message; |
| 27 this.offset = 0; | 43 this.offset = 0; |
| 28 this.handleIndex = 0; | 44 this.handleIndex = 0; |
| 29 } | 45 } |
| 30 | 46 |
| 31 Object.defineProperty(Validator.prototype, "offsetLimit", { | 47 Object.defineProperty(Validator.prototype, "offsetLimit", { |
| 32 get: function() { return this.message.buffer.byteLength; } | 48 get: function() { return this.message.buffer.byteLength; } |
| 33 }); | 49 }); |
| 34 | 50 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 return true; | 82 return true; |
| 67 | 83 |
| 68 if (index < this.handleIndex || index >= this.handleIndexLimit) | 84 if (index < this.handleIndex || index >= this.handleIndexLimit) |
| 69 return false; | 85 return false; |
| 70 | 86 |
| 71 // This is safe because handle indices are uint32. | 87 // This is safe because handle indices are uint32. |
| 72 this.handleIndex = index + 1; | 88 this.handleIndex = index + 1; |
| 73 return true; | 89 return true; |
| 74 } | 90 } |
| 75 | 91 |
| 76 Validator.prototype.validateHandle = function(offset) { | 92 Validator.prototype.validateHandle = function(offset, nullable) { |
| 77 var index = this.message.buffer.getUint32(offset); | 93 var index = this.message.buffer.getUint32(offset); |
| 94 |
| 95 if (index === codec.kEncodedInvalidHandleValue) |
| 96 return nullable ? |
| 97 validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE; |
| 98 |
| 78 if (!this.claimHandle(index)) | 99 if (!this.claimHandle(index)) |
| 79 return validationError.ILLEGAL_HANDLE; | 100 return validationError.ILLEGAL_HANDLE; |
| 80 return validationError.NONE; | 101 return validationError.NONE; |
| 81 } | 102 } |
| 82 | 103 |
| 83 Validator.prototype.validateStructHeader = | 104 Validator.prototype.validateStructHeader = |
| 84 function(offset, minNumBytes, minNumFields) { | 105 function(offset, minNumBytes, minNumFields) { |
| 85 if (!codec.isAligned(offset)) | 106 if (!codec.isAligned(offset)) |
| 86 return validationError.MISALIGNED_OBJECT; | 107 return validationError.MISALIGNED_OBJECT; |
| 87 | 108 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the | 154 // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the |
| 134 // pointer's value is not valid. | 155 // pointer's value is not valid. |
| 135 Validator.prototype.decodePointer = function(offset) { | 156 Validator.prototype.decodePointer = function(offset) { |
| 136 var pointerValue = this.message.buffer.getUint64(offset); | 157 var pointerValue = this.message.buffer.getUint64(offset); |
| 137 if (pointerValue === 0) | 158 if (pointerValue === 0) |
| 138 return NULL_MOJO_POINTER; | 159 return NULL_MOJO_POINTER; |
| 139 var bufferOffset = offset + pointerValue; | 160 var bufferOffset = offset + pointerValue; |
| 140 return Number.isSafeInteger(bufferOffset) ? bufferOffset : null; | 161 return Number.isSafeInteger(bufferOffset) ? bufferOffset : null; |
| 141 } | 162 } |
| 142 | 163 |
| 143 Validator.prototype.validateArrayPointer = | 164 Validator.prototype.validateArrayPointer = function( |
| 144 function(offset, elementSize, expectedElementCount, elementType) { | 165 offset, elementSize, expectedElementCount, elementType, nullable) { |
| 145 var arrayOffset = this.decodePointer(offset); | 166 var arrayOffset = this.decodePointer(offset); |
| 146 if (arrayOffset === null) | 167 if (arrayOffset === null) |
| 147 return validationError.ILLEGAL_POINTER; | 168 return validationError.ILLEGAL_POINTER; |
| 169 |
| 148 if (arrayOffset === NULL_MOJO_POINTER) | 170 if (arrayOffset === NULL_MOJO_POINTER) |
| 149 return validationError.NONE; | 171 return nullable ? |
| 172 validationError.NONE : validationError.UNEXPECTED_NULL_POINTER; |
| 173 |
| 150 return this.validateArray( | 174 return this.validateArray( |
| 151 arrayOffset, elementSize, expectedElementCount, elementType); | 175 arrayOffset, elementSize, expectedElementCount, elementType); |
| 152 } | 176 } |
| 153 | 177 |
| 154 Validator.prototype.validateStructPointer = function(offset, structClass) { | 178 Validator.prototype.validateStructPointer = function( |
| 179 offset, structClass, nullable) { |
| 155 var structOffset = this.decodePointer(offset); | 180 var structOffset = this.decodePointer(offset); |
| 156 if (structOffset === null) | 181 if (structOffset === null) |
| 157 return validationError.ILLEGAL_POINTER; | 182 return validationError.ILLEGAL_POINTER; |
| 183 |
| 158 if (structOffset === NULL_MOJO_POINTER) | 184 if (structOffset === NULL_MOJO_POINTER) |
| 159 return validationError.NONE; | 185 return nullable ? |
| 186 validationError.NONE : validationError.UNEXPECTED_NULL_POINTER; |
| 187 |
| 160 return structClass.validate(this, structOffset); | 188 return structClass.validate(this, structOffset); |
| 161 } | 189 } |
| 162 | 190 |
| 163 Validator.prototype.validateStringPointer = function(offset) { | 191 Validator.prototype.validateStringPointer = function(offset) { |
| 164 return this.validateArrayPointer( | 192 return this.validateArrayPointer( |
| 165 offset, codec.Uint8.encodedSize, 0, codec.Uint8); | 193 offset, codec.Uint8.encodedSize, 0, codec.Uint8); |
| 166 } | 194 } |
| 167 | 195 |
| 168 // Similar to Array_Data<T>::Validate() | 196 // Similar to Array_Data<T>::Validate() |
| 169 // mojo/public/cpp/bindings/lib/array_internal.h | 197 // mojo/public/cpp/bindings/lib/array_internal.h |
| (...skipping 19 matching lines...) Expand all Loading... |
| 189 | 217 |
| 190 if (expectedElementCount != 0 && numElements != expectedElementCount) | 218 if (expectedElementCount != 0 && numElements != expectedElementCount) |
| 191 return validationError.UNEXPECTED_ARRAY_HEADER; | 219 return validationError.UNEXPECTED_ARRAY_HEADER; |
| 192 | 220 |
| 193 if (!this.claimRange(offset, numBytes)) | 221 if (!this.claimRange(offset, numBytes)) |
| 194 return validationError.ILLEGAL_MEMORY_RANGE; | 222 return validationError.ILLEGAL_MEMORY_RANGE; |
| 195 | 223 |
| 196 // Validate the array's elements if they are pointers or handles. | 224 // Validate the array's elements if they are pointers or handles. |
| 197 | 225 |
| 198 var elementsOffset = offset + codec.kArrayHeaderSize; | 226 var elementsOffset = offset + codec.kArrayHeaderSize; |
| 199 if (elementType === codec.Handle) | 227 var nullable = isNullable(elementType); |
| 200 return this.validateHandleElements(elementsOffset, numElements); | 228 |
| 229 if (isHandleClass(elementType)) |
| 230 return this.validateHandleElements(elementsOffset, numElements, nullable); |
| 231 if (isStringClass(elementType)) |
| 232 return this.validateArrayElements( |
| 233 elementsOffset, numElements, codec.Uint8, nullable) |
| 201 if (elementType instanceof codec.PointerTo) | 234 if (elementType instanceof codec.PointerTo) |
| 202 return this.validateStructElements( | 235 return this.validateStructElements( |
| 203 elementsOffset, numElements, elementType.cls); | 236 elementsOffset, numElements, elementType.cls, nullable); |
| 204 if (elementType instanceof codec.String) | |
| 205 return this.validateArrayElements( | |
| 206 elementsOffset, numElements, codec.Uint8); | |
| 207 if (elementType instanceof codec.ArrayOf) | 237 if (elementType instanceof codec.ArrayOf) |
| 208 return this.validateArrayElements( | 238 return this.validateArrayElements( |
| 209 elementsOffset, numElements, elementType.cls); | 239 elementsOffset, numElements, elementType.cls, nullable); |
| 210 | 240 |
| 211 return validationError.NONE; | 241 return validationError.NONE; |
| 212 } | 242 } |
| 213 | 243 |
| 214 // Note: the |offset + i * elementSize| computation in the validateFooElements | 244 // Note: the |offset + i * elementSize| computation in the validateFooElements |
| 215 // methods below is "safe" because elementSize <= 8, offset and | 245 // methods below is "safe" because elementSize <= 8, offset and |
| 216 // numElements are uint32, and 0 <= i < numElements. | 246 // numElements are uint32, and 0 <= i < numElements. |
| 217 | 247 |
| 218 Validator.prototype.validateHandleElements = function(offset, numElements) { | 248 Validator.prototype.validateHandleElements = |
| 249 function(offset, numElements, nullable) { |
| 219 var elementSize = codec.Handle.encodedSize; | 250 var elementSize = codec.Handle.encodedSize; |
| 220 for (var i = 0; i < numElements; i++) { | 251 for (var i = 0; i < numElements; i++) { |
| 221 var index = this.message.buffer.getUint32(offset + i * elementSize); | 252 var elementOffset = offset + i * elementSize; |
| 222 if (!this.claimHandle(index)) | 253 var err = this.validateHandle(elementOffset, nullable); |
| 223 return validationError.ILLEGAL_HANDLE; | 254 if (err != validationError.NONE) |
| 255 return err; |
| 224 } | 256 } |
| 225 return validationError.NONE; | 257 return validationError.NONE; |
| 226 } | 258 } |
| 227 | 259 |
| 228 // The elementClass parameter is the element type of the element arrays. | 260 // The elementClass parameter is the element type of the element arrays. |
| 229 Validator.prototype.validateArrayElements = | 261 Validator.prototype.validateArrayElements = |
| 230 function(offset, numElements, elementClass) { | 262 function(offset, numElements, elementClass, nullable) { |
| 231 var elementSize = codec.PointerTo.prototype.encodedSize; | 263 var elementSize = codec.PointerTo.prototype.encodedSize; |
| 232 for (var i = 0; i < numElements; i++) { | 264 for (var i = 0; i < numElements; i++) { |
| 233 var elementOffset = offset + i * elementSize; | 265 var elementOffset = offset + i * elementSize; |
| 234 var err = this.validateArrayPointer( | 266 var err = this.validateArrayPointer( |
| 235 elementOffset, elementClass.encodedSize, 0, elementClass); | 267 elementOffset, elementClass.encodedSize, 0, elementClass, nullable); |
| 236 if (err != validationError.NONE) | 268 if (err != validationError.NONE) |
| 237 return err; | 269 return err; |
| 238 } | 270 } |
| 239 return validationError.NONE; | 271 return validationError.NONE; |
| 240 } | 272 } |
| 241 | 273 |
| 242 Validator.prototype.validateStructElements = | 274 Validator.prototype.validateStructElements = |
| 243 function(offset, numElements, structClass) { | 275 function(offset, numElements, structClass, nullable) { |
| 244 var elementSize = codec.PointerTo.prototype.encodedSize; | 276 var elementSize = codec.PointerTo.prototype.encodedSize; |
| 245 for (var i = 0; i < numElements; i++) { | 277 for (var i = 0; i < numElements; i++) { |
| 246 var elementOffset = offset + i * elementSize; | 278 var elementOffset = offset + i * elementSize; |
| 247 var err = this.validateStructPointer(elementOffset, structClass); | 279 var err = |
| 280 this.validateStructPointer(elementOffset, structClass, nullable); |
| 248 if (err != validationError.NONE) | 281 if (err != validationError.NONE) |
| 249 return err; | 282 return err; |
| 250 } | 283 } |
| 251 return validationError.NONE; | 284 return validationError.NONE; |
| 252 } | 285 } |
| 253 | 286 |
| 254 var exports = {}; | 287 var exports = {}; |
| 255 exports.validationError = validationError; | 288 exports.validationError = validationError; |
| 256 exports.Validator = Validator; | 289 exports.Validator = Validator; |
| 257 return exports; | 290 return exports; |
| 258 }); | 291 }); |
| OLD | NEW |