1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2007 Adobe Systems Incorporated 5// All Rights Reserved. 6// 7// NOTICE: Adobe permits you to use, modify, and distribute this file 8// in accordance with the terms of the license agreement accompanying it. 9// 10//////////////////////////////////////////////////////////////////////////////// 11 12package mx.core 13{ 14 15import flash.display.Loader; 16import flash.events.Event; 17import flash.events.ErrorEvent; 18import flash.events.ProgressEvent; 19import flash.events.IOErrorEvent; 20import flash.events.SecurityErrorEvent; 21import flash.net.URLRequest; 22import flash.net.URLLoader; 23import flash.net.URLLoaderDataFormat; 24import flash.system.LoaderContext; 25import flash.system.ApplicationDomain; 26import flash.system.LoaderContext; 27import flash.system.Security; 28import flash.system.SecurityDomain; 29import flash.utils.ByteArray; 30//import flash.utils.getTimer; // PERFORMANCE_INFO 31 32import mx.core.RSLData; 33import mx.events.RSLEvent; 34import mx.utils.SHA256; 35import mx.utils.LoaderUtil; 36 37[ExcludeClass] 38 39/** 40 * @private 41 * Cross-domain RSL Item Class. 42 * 43 * The rsls are typically located on a different host than the loader. 44 * There are signed and unsigned Rsls, both have a digest to confirm the 45 * correct rsl is loaded. 46 * Signed Rsls are loaded by setting the digest of the URLRequest. 47 * Unsigned Rsls are check using actionScript to calculate a sha-256 hash of 48 * the loaded bytes and compare them to the expected digest. 49 * 50 */ 51public class CrossDomainRSLItem extends RSLItem 52{ 53 include "../core/Version.as"; 54 55 //-------------------------------------------------------------------------- 56 // 57 // Variables 58 // 59 //-------------------------------------------------------------------------- 60 61 private var rsls:Array = []; // of type RSLInstanceData 62// private var rslUrls:Array; // first url is the primary url in the url parameter, others are failovers 63// private var policyFileUrls:Array; // optional policy files, parallel array to rslUrls 64// private var digests:Array; // option rsl digest, parallel array to rslUrls 65// private var isSigned:Array; // each entry is a boolean value. "true" if the rsl in the parallel array is signed 66// private var hashTypes:Array; // type of hash used to create the digest 67 private var urlIndex:int = 0; // index into url being loaded in rslsUrls and other parallel arrays 68 69 // this reference to the loader keeps the loader from being garbage 70 // collected before the complete event can be sent. 71 private var loadBytesLoader:Loader; 72 73// private var startTime:int; // PERFORMANCE_INFO 74 75 //-------------------------------------------------------------------------- 76 // 77 // Constructor 78 // 79 //-------------------------------------------------------------------------- 80 81 /** 82 * Create a cross-domain RSL item to load. 83 * 84 * @param rsls Array of Objects. Each Object describes and RSL to load. 85 * The first Object in the Array is the primary RSL and the others are 86 * failover RSLs. 87 * @param rootURL provides the url used to locate relative RSL urls. 88 * @param moduleFactory The module factory that is loading the RSLs. The 89 * RSLs will be loaded into the application domain of the given module factory. 90 * If a module factory is not specified, then the RSLs will be loaded into the 91 * application domain of where the CrossDomainRSLItem class was first loaded. 92 * 93 * @langversion 3.0 94 * @playerversion Flash 9 95 * @playerversion AIR 1.1 96 * @productversion Flex 3 97 */ 98 public function CrossDomainRSLItem(rsls:Array, 99 rootURL:String = null, 100 moduleFactory:IFlexModuleFactory = null) 101 { 102 super(rsls[0].rslURL, rootURL, moduleFactory); 103 104 this.rsls = rsls; 105 106 // startTime = getTimer(); // PERFORMANCE_INFO 107 } 108 109 110 //-------------------------------------------------------------------------- 111 // 112 // Properties 113 // 114 //-------------------------------------------------------------------------- 115 116 117 /** 118 * Get the RSLData for the current RSL. This could be the primary RSL or one 119 * of the failover RSLs. 120 * 121 * @langversion 3.0 122 * @playerversion Flash 9 123 * @playerversion AIR 1.1 124 * @productversion Flex 3 125 */ 126 private function get currentRSLData():RSLData 127 { 128 return RSLData(rsls[urlIndex]); 129 } 130 131 //-------------------------------------------------------------------------- 132 // 133 // Overridden Methods 134 // 135 //-------------------------------------------------------------------------- 136 137 138 /** 139 * 140 * Load an RSL. 141 * 142 * @param progressHandler receives ProgressEvent.PROGRESS events, may be null 143 * @param completeHandler receives Event.COMPLETE events, may be null 144 * @param ioErrorHandler receives IOErrorEvent.IO_ERROR events, may be null 145 * @param securityErrorHandler receives SecurityErrorEvent.SECURITY_ERROR events, may be null 146 * @param rslErrorHandler receives RSLEvent.RSL_ERROR events, may be null 147 * 148 * 149 * @langversion 3.0 150 * @playerversion Flash 9 151 * @playerversion AIR 1.1 152 * @productversion Flex 3 153 */ 154 override public function load(progressHandler:Function, 155 completeHandler:Function, 156 ioErrorHandler:Function, 157 securityErrorHandler:Function, 158 rslErrorHandler:Function):void 159 { 160 chainedProgressHandler = progressHandler; 161 chainedCompleteHandler = completeHandler; 162 chainedIOErrorHandler = ioErrorHandler; 163 chainedSecurityErrorHandler = securityErrorHandler; 164 chainedRSLErrorHandler = rslErrorHandler; 165 166 167/* 168 // Debug loading of swf files 169 170 trace("begin load of " + url); 171 if (Security.sandboxType == Security.REMOTE) 172 { 173 trace(" in REMOTE sandbox"); 174 } 175 else if (Security.sandboxType == Security.LOCAL_TRUSTED) 176 { 177 trace(" in LOCAL_TRUSTED sandbox"); 178 } 179 else if (Security.sandboxType == Security.LOCAL_WITH_FILE) 180 { 181 trace(" in LOCAL_WITH_FILE sandbox"); 182 } 183 else if (Security.sandboxType == Security.LOCAL_WITH_NETWORK) 184 { 185 trace(" in LOCAL_WITH_NETWORK sandbox"); 186 } 187* 188* @langversion 3.0 189* @playerversion Flash 9 190* @playerversion AIR 1.1 191* @productversion Flex 3 192*/ 193 194 var rslData:RSLData = currentRSLData; 195 urlRequest = new URLRequest(LoaderUtil.createAbsoluteURL(rootURL, rslData.rslURL)); 196 197 var loader:URLLoader = new URLLoader(); 198 loader.dataFormat = URLLoaderDataFormat.BINARY; 199 200 // We needs to listen to certain events. 201 202 loader.addEventListener( 203 ProgressEvent.PROGRESS, itemProgressHandler); 204 205 loader.addEventListener( 206 Event.COMPLETE, itemCompleteHandler); 207 208 loader.addEventListener( 209 IOErrorEvent.IO_ERROR, itemErrorHandler); 210 211 loader.addEventListener( 212 SecurityErrorEvent.SECURITY_ERROR, itemErrorHandler); 213 214 if (rslData.policyFileURL != "") 215 { 216 Security.loadPolicyFile(rslData.policyFileURL); 217 } 218 219 if (rslData.isSigned) 220 { 221 // load a signed rsl by specifying the digest 222 urlRequest.digest = rslData.digest; 223 } 224 225// trace("start load of " + urlRequest.url + " at " + (getTimer() - startTime)); // PERFORMANCE_INFO 226 227 loader.load(urlRequest); 228 } 229 230 231 232 //-------------------------------------------------------------------------- 233 // 234 // Methods 235 // 236 //-------------------------------------------------------------------------- 237 238 /** 239 * @private 240 * Complete the load of the cross-domain rsl by loading it into the current 241 * application domain. The load was started by loadCdRSL. 242 * 243 * @param - urlLoader from the complete event. 244 * 245 * @return - true if the load was completed successfully or unsuccessfully, 246 * false if the load of a failover rsl was started 247 */ 248 private function completeCdRslLoad(urlLoader:URLLoader):Boolean 249 { 250 // handle player bug #204244, complete event without data after an error 251 if (urlLoader == null || urlLoader.data == null || ByteArray(urlLoader.data).bytesAvailable == 0) 252 { 253 return true; 254 } 255 256 // load the bytes into the current application domain. 257 loadBytesLoader = new Loader(); 258 var context:LoaderContext = new LoaderContext(); 259 var rslData:RSLData = currentRSLData; 260 261 if (rslData.moduleFactory) 262 { 263 context.applicationDomain = rslData.moduleFactory.info()["currentDomain"]; 264 } 265 else if (moduleFactory) 266 { 267 context.applicationDomain = moduleFactory.info()["currentDomain"]; 268 } 269 else 270 { 271 context.applicationDomain = ApplicationDomain.currentDomain; 272 } 273 274 context.securityDomain = null; 275 276 // Set the allowCodeImport flag so we can load the RSL without a security error. 277 context.allowCodeImport = true; 278 279 // verify the digest, if any, is correct 280 if (rslData.digest != null && rslData.verifyDigest) 281 { 282 var verifiedDigest:Boolean = false; 283 if (!rslData.isSigned) 284 { 285 // verify an unsigned rsl 286 if (rslData.hashType == SHA256.TYPE_ID) 287 { 288 // get the bytes from the rsl and calculate the hash 289 var rslDigest:String = null; 290 if (urlLoader.data != null) 291 { 292 rslDigest = SHA256.computeDigest(urlLoader.data); 293 } 294 295 if (rslDigest == rslData.digest) 296 { 297 verifiedDigest = true; 298 } 299 } 300 } 301 else 302 { 303 // signed rsls are verified by the player 304 verifiedDigest = true; 305 } 306 307 if (!verifiedDigest) 308 { 309 // failover to the next rsl, if one exists 310 // no failover to load, all the rsls have failed to load 311 // report an error. 312 // B Feature: externalize error message 313 var hasFailover:Boolean = hasFailover(); 314 var rslError:ErrorEvent = new ErrorEvent(RSLEvent.RSL_ERROR); 315 rslError.text = "Flex Error #1001: Digest mismatch with RSL " + 316 urlRequest.url + 317 ". Redeploy the matching RSL or relink your application with the matching library."; 318 itemErrorHandler(rslError); 319 320 return !hasFailover; 321 } 322 } 323 324 // load the rsl into memory 325 loadBytesLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadBytesCompleteHandler); 326 loadBytesLoader.loadBytes(urlLoader.data, context); 327 return true; 328 } 329 330 331 /** 332 * Does the current url being processed have a failover? 333 * 334 * @return true if a failover url exists, false otherwise. 335 * 336 * @langversion 3.0 337 * @playerversion Flash 9 338 * @playerversion AIR 1.1 339 * @productversion Flex 3 340 */ 341 public function hasFailover():Boolean 342 { 343 return (rsls.length > (urlIndex + 1)); 344 } 345 346 347 /** 348 * Load the next url from the list of failover urls. 349 * 350 * @langversion 3.0 351 * @playerversion Flash 9 352 * @playerversion AIR 1.1 353 * @productversion Flex 3 354 */ 355 public function loadFailover():void 356 { 357 // try to load the failover from the same node again 358 if (urlIndex < rsls.length) 359 { 360 trace("Failed to load RSL " + currentRSLData.rslURL); 361 trace("Failing over to RSL " + RSLData(rsls[urlIndex+1]).rslURL); 362 urlIndex++; // move to failover url 363 url = currentRSLData.rslURL; 364 load(chainedProgressHandler, 365 chainedCompleteHandler, 366 chainedIOErrorHandler, 367 chainedSecurityErrorHandler, 368 chainedRSLErrorHandler); 369 } 370 } 371 372 //-------------------------------------------------------------------------- 373 // 374 // Overridden Event Handlers 375 // 376 //-------------------------------------------------------------------------- 377 378 /** 379 * @private 380 */ 381 override public function itemCompleteHandler(event:Event):void 382 { 383// trace("complete load of " + url + " at " + (getTimer() - startTime)); // PERFORMANCE_INFO 384 385 // complete loading the cross-domain rsl by calling loadBytes. 386 completeCdRslLoad(event.target as URLLoader); 387 } 388 389 /** 390 * @private 391 */ 392 override public function itemErrorHandler(event:ErrorEvent):void 393 { 394// trace("error loading " + url + " at " + (getTimer() - startTime)); // PERFORMANCE_INFO 395 396 // if a failover exists, try to load it. Otherwise call super() 397 // for default error handling. 398 if (hasFailover()) 399 { 400 trace(decodeURI(event.text)); 401 loadFailover(); 402 } 403 else 404 { 405 super.itemErrorHandler(event); 406 } 407 } 408 409 410 /** 411 * loader.loadBytes() has a complete event. 412 * Done loading this rsl into memory. Call the completeHandler 413 * to start loading the next rsl. 414 * 415 * @private 416 */ 417 private function loadBytesCompleteHandler(event:Event):void 418 { 419 loadBytesLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadBytesCompleteHandler); 420 loadBytesLoader = null; 421 super.itemCompleteHandler(event); 422 } 423 424} 425}