Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Бесполезности

обо всем по-немногу...
Оценить эту запись

UnsecurityDisplayLoader - обертка для несекьюрной загрузки дисплей контента

Запись от cleptoman размещена 12.02.2011 в 12:28
Обновил(-а) cleptoman 14.02.2011 в 08:58

Итак. Понадобилось в очередной раз "обмануть систему" и получить доступ к контенту, к которому с классическим подходом оного не дают. Т.е. нет возможности залить crossdomain.xml, а картинки на сервере страсть какие красивые.

Небольшое отступление:
Я, ни в коем случае, не пропагандирую использование контента без ведома владельца.Необходимо помнить, что у любого контента в сети есть владелец и есть законодательство РФ. Пусть оно и хромое, но тем не менее.

В дебаг-плеере, где безопасность игнорируется мы можем достучаться к любому контенту, который нам нужен. пробуем:

Код AS3:
var loadeer:Loader			= new Loader();
loadeer.contentLoaderInfo.addEventListener(Event.INIT, _handler);
loadeer.load(new URLRequest("http://img.yandex.net/i/www/logo.png")) //  надеюсь яндекс не обидится. я их лого использую для обучающих/ознакомительных целей, а не коммерческих.
 
function _handler(e:Event):void{
trace(e.target.loader.content); // [object Bitmap]
}
Ага, все работает. отлично. пробуем закинуть нашу незамысловатую SWF на хост и повторить процедуру. залили, открываем флэшку. Дебаг плагин нам выносит вердикт.

Цитата:
SecurityError: Error #2122: Нарушение изолированной среды: Loader.content: http://cleptoman.ru/test/dr.swf не может осуществить доступ к http://img.yandex.net/i/www/logo.png. Необходим файл политики, но, когда были загружены эти мультимедийные данные, флаг checkPolicyFile не был установлен.
Флаг ставить мы не будем. потому что точно знаем, что яндекс забыл внести наш домен в список разрешенных в свой кроссдомен (да, да, и такое бывает).

Ну что же, пора немного покурить интернеты. Долго курить не приходится, потому что вспомнил, что на флэшере Димарик проводил изыскания на эту тему, за что ему огромная благодарность и бронзовый памятник.)
Вдохновившись прочтенным закрадывается мыслишка накидать класс-обертку над лоадером для реализации идеи.

собсно продукт:

Код AS3:
package ru.cleptoman.net {
	import flash.display.MovieClip;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
 
	[Event(name = "open", type = "flash.events.Event.OPEN")]
	[Event(name = "complete", type = "flash.events.Event.COMPLETE")]
	[Event(name = "init", type = "flash.events.Event.INIT")]
	[Event(name = "progress", type = "flash.events.ProgressEvent.PROGRESS")]
	[Event(name = "securityError", type = "flash.events.SecurityErrorEvent.SECURITY_ERROR")]
	[Event(name = "ioError", type = "flash.events.IOErrorEvent.IO_ERROR")]
 
	/**
	 * @langversion 	Action Script 3.0
	 * @see				http://cleptoman.free-lance.ru
	 * @author 			Kutov Aleksey aka cleptoman
	 * @version 		0.02
	 * @playerversion	9
	 * Класс-надстройка над Loader. Предназначен для загрузки медийного контента форматов JPEG,GIF,PNG,SWF при необходимости игнорируя политику безопасности Flash Player.
	 */
	public class UnsecurityDisplayLoader extends EventDispatcher{
 
		protected var _loader:Loader;
		protected var _parameters:Object;
		protected var _loading:Boolean;
		protected var _isAfterFirstError:Boolean;
		protected var _content:DisplayObject;
		protected var _extractor:IContentExtractor;
 
		public function UnsecurityDisplayLoader() {
			super();
		}
 
		private function _create():void {
			_loader						= new Loader();
			_configHandlers();
		}
 
		private function _removeHandlers():void {
			var li:LoaderInfo			= _loader.contentLoaderInfo;
			li.removeEventListener(Event.COMPLETE, _onHandler);
			li.removeEventListener(Event.INIT, _onHandler);
			li.removeEventListener(ProgressEvent.PROGRESS, _onHandler);
			li.removeEventListener(Event.OPEN, _onHandler);
			li.removeEventListener(IOErrorEvent.IO_ERROR, _onHandler);
			li.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, _onHandler);
		}
 
		private function _configHandlers():void {
			var li:LoaderInfo			= _loader.contentLoaderInfo;
			li.addEventListener(Event.COMPLETE, _onHandler);
			li.addEventListener(Event.INIT, _onHandler);
			li.addEventListener(ProgressEvent.PROGRESS, _onHandler);
			li.addEventListener(Event.OPEN, _onHandler);
			li.addEventListener(IOErrorEvent.IO_ERROR, _onHandler);
			li.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _onHandler);
		}
 
		private function _skipLoad():void {
			if (_loader && _loading) {
				_loader.close();
			}
			_extractor					= null;
			_content					= null;
			_isAfterFirstError			= false;
			_parameters					= null;
			_loading					= false;
		}
 
		/**
		 * Пробуем достучаться до content у LoaderInfo. если не получается, то грузим байты методом loadBytes. Пробуем еще раз. если не получается, то думаем,что делать дальше с ексепшном )
		 * @param	e
		 */
 
		private function _onHandler(e:Event):void {
			if (e.type === Event.INIT) {
				if (_isAfterFirstError) {
					_content			= _extractor.extract(_loader.content);
					_isAfterFirstError			= false;
				}else{
					try{
						_content		= _loader.content;
					}catch (err:SecurityError) {
						_extractor				= (_loader.contentLoaderInfo.contentType.substring(0,5) === "image") ? new BitmapExtractor() : new MovieClipExtractor();
						_isAfterFirstError		= true;
						_loader.loadBytes(_loader.contentLoaderInfo.bytes);
						e.stopPropagation();
						return;
					}
					_parameters		= _loader.contentLoaderInfo.parameters;
				}
				_loading					= false;
			}
 
			if (e.type === ProgressEvent.PROGRESS && _isAfterFirstError) {
				return;
			}
			super.dispatchEvent(e);
		}
 
		public override function dispatchEvent (event:Event) : Boolean {
			throw new Error("Класс не реализует данный метод");
		}
 
		/**
		 * @return Возвращает последний объект, переданный в URLReqest#data в метод load. Не равен content.loaderInfo.parameters, если загрузка прошла игнорируя безопасность.
		 */
 
		public function get parameters():Object { return _parameters; }
 
 
		/**
		 * @return Возвращает медийный контент. Если загрузка произошла игнорируя политику безопасности, то content.loaderInfo.contentType для объектов будет application/x-shockwave-flash, а не image/jpeg.
		 */
		public function get content():DisplayObject { 
			return _content; 
		}
		/**
		 * @return Возвращает состояние: происходит загрузка в данный момент или нет.
		 */
		public function get loading():Boolean { return _loading; }
 
		public function load(request:URLRequest,context:LoaderContext = null):void {
			_skipLoad();
			if (!_loader) {
				_create();
			}
 
			_parameters				= request.data;
			_loader.load(request,context);
			_loading				= true;
		}
		public function loadBytes(bytes:ByteArray):void {
			_skipLoad();
			if (!_loader) {
				_create();
			}
			_parameters				= _loader.contentLoaderInfo.parameters;
			_loader.loadBytes(bytes);
			_loading				= true;
		}
		public function unload():void {
			_skipLoad();
			if(_loader){
				_loader.unload();
			}
		}
		public function unloadAndStop(gc:Boolean = true):void {
			_skipLoad();
			if(_loader){
				_loader.unloadAndStop(gc);
			}
		}
		public function close():void {
			_skipLoad();
		}
 
		/**
		 * Удаляет внутренние ссылки на используемые объекты. сохраните ссылку на полученный в ходе загрузки content перед вызовом метода
		 */
		public function destroy():void {
			if (_loader) {
				_skipLoad();
				_removeHandlers();
				_loader				= null;
			}
		}
 
 
	}
 
}
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
interface IContentExtractor {
	function extract(content:DisplayObject):DisplayObject;
}
class BitmapExtractor implements IContentExtractor {
	public function extract(content:DisplayObject):DisplayObject {
		return (content as DisplayObjectContainer).getChildAt(0);
	}
}
class MovieClipExtractor implements IContentExtractor {
	public function extract(content:DisplayObject):DisplayObject {
		return content;
	}
}
пример применения:
Код AS3:
package {
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import ru.cleptoman.net.UnsecurityDisplayLoader;
 
 
 
	/**
	 * ...
	 * @author Kutov Aleksey aka cleptoman
	 */
	public class Main extends Sprite {
 
		public function Main():void {
			if (stage) init();
			else stage.addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void {
			super.removeEventListener(Event.ADDED_TO_STAGE, init);
 
			var loader:UnsecurityDisplayLoader = new UnsecurityDisplayLoader();
			loader.addEventListener(Event.INIT, _onComplete);
			var req:URLRequest		= new URLRequest("http://img.yandex.net/i/www/logo.png");
			loader.load(req);
 
		}
 
		private function _onComplete(e:Event):void {
			var loader:UnsecurityDisplayLoader = e.target as UnsecurityDisplayLoader;
			this.addChild(new Bitmap((loader.content as Bitmap).bitmapData));
 
		}
 
	}
 
}
ну и линк, где можно посмотреть

класс особо в коментариях не нуждается. основной интерес, возможно, представляет метод _onHandler, обработчик событий.

Код AS3:
private function _onHandler(e:Event):void {
	if (e.type === Event.INIT) {
		if (_isAfterFirstError) {
			_content			= _extractor.extract(_loader.content);
			_isAfterFirstError			= false;
		}else{
			try{
				_content		= _loader.content;
			}catch (err:SecurityError) {
				_extractor				= (_loader.contentLoaderInfo.contentType.substring(0,5) === "image") ? new BitmapExtractor() : new MovieClipExtractor();
				_isAfterFirstError		= true;
				_loader.loadBytes(_loader.contentLoaderInfo.bytes);
				e.stopPropagation();
				return;
			}
			_parameters		= _loader.contentLoaderInfo.parameters;
		}
		_loading					= false;
	}
 
	if (e.type === ProgressEvent.PROGRESS && _isAfterFirstError) {
		return;
	}
	super.dispatchEvent(e);
}

Итак:

По событию INIT смотрим флаг _isAfterFirstError. если он false, значит ошибок безопасности еще не было, отработает блок else. Тут интересней. Как упоминалось выше в примере, в случае нарушения изолированной среды нам выкинет SecurityError.
Это и используем. если выполнился блок try - дальше все идет по плану. Если нет, то отработает catch блок: выставит флаг _isAfterFirstError в true и попробует загрузить полученные байты (благо лоадерИнфо нам их оставил, за что ему и спасибо).
Интересный момент с конвертацией из Bitmap в MovieClip при загрузке байтов картинки. Он описан в вдохновении. Я , исходя из contentType выбираю нужное поведение, которое будет работать чуть ниже.
Еще один интересный момент заключается в том, что, если убрать строку e.stopPropagation();, то каким то неведомым образом INIT редиспатчится выше, где в обработчике пытаюсь взять контент, которого еще и получаю фейл. Если кому-то будет не лень покурить этот момент - будет супер.
Теперь при следующем INIT с нашим флагом _isAfterFirstError == true мы используем экземпляр _extractor, выбраный чуть выше.

Свойство parameters в случае с несекьюрной загрузкой будет просто хранилищем параметров, переданных в метод load и никакого отношения к LoaderInfo#parameters иметь не будет. Эдакий легализованный вагон с гестарбайтерами в составе поезда ФМС ). потому тут надо быть аккуратным или попросту удалить это свойство.
Собственно, полезность метода loadBytes тоже под вопросом.

Вот и все.

Выражаю благодарности dimarik за идею и Psycho Tiger за предварительную рецензию).

Если кому пригодится - хорошо. Не пригодится - значит название моего блога выбрано удачно ).

п.с. Ага, сбаянил)
Вложения
Тип файла: zip _dr.zip (65.5 Кб, 226 просмотров)
Всего комментариев 70

Комментарии

Старый 22.02.2011 16:46 cleptoman вне форума
cleptoman
 
Аватар для cleptoman
ну об этом демагогия с предыдущей страницы ))
Старый 22.02.2011 16:48 ChuwY вне форума
ChuwY
 
Аватар для ChuwY
Да. Действительно, стоило читать больше.
Извините за ньюбизм.
Сижу сейчас как дурак и думаю, где же можно это похитрее применить
Старый 23.02.2011 00:24 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Я давно этого ждал. BlooDHounD vs in4core. Спасибо!

@Блуд, вот ты сказал что throw иногда выкидывает null. Имеешь ввиду throw null? А зачем такое может понадобится?
Старый 23.02.2011 00:49 in4core вне форума
in4core
 
Аватар для in4core
Цитата:
Я давно этого ждал. BlooDHounD vs in4core. Спасибо!
Мы стараемся чтобы форум привлекал все больше посетителей ))) мы смеемся потому, что...
Старый 23.02.2011 01:05 TanaTiX вне форума
TanaTiX
 
Аватар для TanaTiX
Цитата:
Мы стараемся чтобы форум привлекал все больше посетителей ))) мы смеемся потому, что...
...почему-то сразу вспоминается детская шутка про клоунов.
Старый 23.02.2011 01:16 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
Psycho Tiger, я такого не говорил. понадобится может когда лень писать много кода. у меня такое бывает. пишу распределённую систему из большого количества классов. публик доступ есть только к одному методу ( чёрный ящик ). неважно что будут выкидывать внутренние методы, главное что разработчику выведется, что он идиот.
Код AS3:
function method1(){
	throw null
}
 
function method2(){
	throw null
}
 
try {
	method1();
	method2();
} catch ( e:* ) {
	throw new RealError();
}
Старый 23.02.2011 01:32 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Хм, понятно )
Я никогда не ленюсь выкидывать ошибки с мало-мальским описанием что не так. При дебаге вне IDE помогает, если в окне RTE показывается недопустимое значение (из за которого и вылетели).
Спасибо за ответ.
Старый 23.02.2011 04:51 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
возможно ты не заметил, но я тоже выкидываю.
Старый 23.02.2011 12:03 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Я имею ввиду что я всегда в случае чего выкидываю RealError сразу, с подробным описанием проблемы, а не просто констатируя факт что юзер ошибся.
Старый 23.02.2011 15:20 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
а толку? =)
Старый 23.02.2011 16:39 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
В дебаг версии толку действительно нет, а вот в браузере мы не поймём, в каком из двух методов произошел эксепш.
Старый 23.02.2011 20:16 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Ага, именно. unhandled error ловлю и хоть примерно можно понять, из за чего оно произошло. Я не Бог ведь )
Старый 23.02.2011 20:33 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
мдя ... вы кажись не понимаете. ну да ладно.
Старый 23.02.2011 22:50 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Блуд, тогда объясни пожалуйста.
Старый 23.02.2011 23:46 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
да я уже написал всё на предыдущей странице.
Старый 24.02.2011 03:41 in4core вне форума
in4core
 
Аватар для in4core
Богу не свойственно объяснять, ему свойственно делать..............
Старый 24.02.2011 04:52 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
@in4core, конкретно в вашем случае любые объяснения бесполезны.
Цитата:
Сообщение от BlooDHounD
понадобится может когда лень писать много кода. у меня такое бывает. пишу распределённую систему из большого количества классов. публик доступ есть только к одному методу ( чёрный ящик ). неважно что будут выкидывать внутренние методы.
Старый 24.02.2011 20:03 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Ну да, я понял о чем ты. Наверное, не правильно высказал свои мысли, ну да ладно.
Старый 05.04.2011 17:16 kitsela вне форума
kitsela
здраствуйте, вот интересует, а что поменять, что б грузило HTML страницу???
Старый 05.04.2011 19:42 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Loader на URLLoader. =)
 

 


Часовой пояс GMT +4, время: 21:17.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.