обо всем по-немногу...
UnsecurityDisplayLoader - обертка для несекьюрной загрузки дисплей контента
Итак. Понадобилось в очередной раз "обмануть систему" и получить доступ к контенту, к которому с классическим подходом оного не дают. Т.е. нет возможности залить crossdomain.xml, а картинки на сервере страсть какие красивые.
Небольшое отступление:
Я, ни в коем случае, не пропагандирую использование контента без ведома владельца.Необходимо помнить, что у любого контента в сети есть владелец и есть законодательство РФ. Пусть оно и хромое, но тем не менее.
В дебаг-плеере, где безопасность игнорируется мы можем достучаться к любому контенту, который нам нужен. пробуем:
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] }
Цитата:
SecurityError: Error #2122: Нарушение изолированной среды: Loader.content: http://cleptoman.ru/test/dr.swf не может осуществить доступ к http://img.yandex.net/i/www/logo.png. Необходим файл политики, но, когда были загружены эти мультимедийные данные, флаг checkPolicyFile не был установлен.
Ну что же, пора немного покурить интернеты. Долго курить не приходится, потому что вспомнил, что на флэшере Димарик проводил изыскания на эту тему, за что ему огромная благодарность и бронзовый памятник.)
Вдохновившись прочтенным закрадывается мыслишка накидать класс-обертку над лоадером для реализации идеи.
собсно продукт:
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; } }
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, обработчик событий.
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 за предварительную рецензию).
Если кому пригодится - хорошо. Не пригодится - значит название моего блога выбрано удачно ).
п.с. Ага, сбаянил)
Всего комментариев 70
Комментарии
12.02.2011 20:48 | |
14.02.2011 04:15 | |
За злоупотребление "_" хочется дать по рукам.
|
14.02.2011 11:08 | |
Денис, да, получается я изобретаю велосипеды )
Илья, а где злоупотребление? приватные и протектед всегда с "_"..а вообще, это ты достал очередной топор для холивара ) |
14.02.2011 11:46 | |
спасибо, очень интересно!
|
14.02.2011 14:06 | |
in4core, а как правильно?
|
14.02.2011 15:22 | |
Ну вообще-то только на форуме ломается. В IDE красиво в столбик.
|
14.02.2011 15:56 | |
Цитата:
такой код читать не хочется
|
14.02.2011 15:57 | |
alatar, спасибо, что поправил..имелось ввиду дебаг сессия в ИДЕ
|
15.02.2011 01:45 | |
cleptoman, при выкладывании подобного кода на форум переводите табы в пробелы. тогда ничего не сломается.
|
15.02.2011 11:22 | |
mayakwd, скорее уже тогда за отсутствие this. И вообще, не понимаю, зачем там protected. А вот за методы с подчеркиваем — да, обязательно по рукам.
|
15.02.2011 12:05 | |
топик получился про "правописание")
спасибо за содержательные посты. |
15.02.2011 16:40 | |
in4core, этот комментарий расположен под методом и относится к методу ниже. А он-то return имеет.
|
15.02.2011 16:48 | |
я даже не знаю что ответить...нет, компилятор не ругается.
|
15.02.2011 16:49 | |
КорДум, он про dispatchEvent, видимо
|
15.02.2011 17:36 | |
Кстати действительно интересно, почему не ругается.
|
15.02.2011 17:39 | |
Потому что выход из метода возможен двумя путями - либо по return, либо по throw (кстати, throw можно применять к любому объекту, не только к ошибке или исключению)
|
15.02.2011 18:24 | |
Понятно, спасибо.
|
19.02.2011 02:17 | |
Цитата:
За злоупотребление "_" хочется дать по рукам.
2 cleptoman: Это таким образом получилось достать Bitmap, а BitmapData из нее удачно достается? Т.е., чтобы получить битмапу, стадию можно пропустить? P.S. Стратегии IContentExtractor влепленные в класс на ровном месте весьма доставили |
|
Обновил(-а) expl 19.02.2011 в 02:36
|
19.02.2011 08:39 | |
свой после переопределения не должен ничо коме эксепшна кидать. может я где чего не докурил, но так задумывалось.
больше интересен момент: Цитата:
Еще один интересный момент заключается в том, что, если убрать строку e.stopPropagation();, то каким то неведомым образом INIT редиспатчится выше, где в обработчике пытаюсь взять контент, которого еще и получаю фейл.
|
|
Обновил(-а) cleptoman 19.02.2011 в 08:52
|
19.02.2011 08:40 | |
Обновил(-а) cleptoman 19.02.2011 в 08:49
|
19.02.2011 14:10 | |
Цитата:
@expl, да достается. да, можно пропустить. да, в примере есть)
|
22.02.2011 00:32 | |
димка, throw ничего не может возвращать ) но выкидывать null он может. я так сам делаю.
|
22.02.2011 01:17 | |
Ээээ. Получается, что после нажатия кнопки "продолжить" в окошке, выброшенном дебаг-плеером, метод, возвращающий что-нибудь возвратит null?
|
22.02.2011 01:59 | |
я ещё раз повторю. он ничего не вернёт. в лучшем случае undefined. но он ничего не вернёт. throw != return;
|
22.02.2011 04:01 | |
тут фишка впринципе понятна, не пробовал могу ошибаться, но поидее
Дальше throw не пойдет. и трейса мы не увидим. Тоесть в нашем случае Да и кстати, даже Имеет свой return который наглядно ничего не вернет. но завершает функцию по окончанию чтения строк или выводу ошибки. В итоге void это тоже возвращаемая величина ))) |
|
Обновил(-а) in4core 22.02.2011 в 04:06
|
22.02.2011 11:09 | |
Я понял. По throw просто прерывается исполнение кода. Ничего никуда не возвращается. Всем спасибо,
|
22.02.2011 12:31 | |
@BlooDHounD я все верно написал.
Такой же, а причем тут уровень выше непонятно. я такого не говорил. function test() { trace('1'); trace('2'); throw new Error('someerror') trace('ok') } function test() { trace('1'); trace('2'); return; trace('ok') } Цитата:
void - не "величина", и уж тем более не "возвращаемая". void - специальный тип данных, который содержит единственное значение undefined.
int тип данных а 555 значение.... безсмысленный разговор. Если хотите указать на ошибки, милости просим, но вот спам разводить не стоит |
|
Обновил(-а) in4core 22.02.2011 в 12:40
|
22.02.2011 13:17 | |
22.02.2011 13:45 | |
in4core, throw выбрасывает из стэка напроч. а return на уровень выше. а на счёт void я даже не хочу комментировать. научитесь читать что ли ...
|
22.02.2011 14:58 | |
Цитата:
Вам же вернулось undefined! а это значение!. если бы ничего не вернулось тоесть пусто бы было, знеачит и возвращения нету.
|
22.02.2011 15:28 | |
На всякий случай, все же, на 2х языках, с пояснением про void (нужное выделено)
На английском: Цитата:
void Special Type
Usage functionName():void {} Language Version: ActionScript 3.0 Runtime Versions: Flash Player 9 Specifies that a function cannot return any value. The void type is a special type that contains exactly one value: undefined. It is special in that its use is limited to the return type of a function. You cannot use void as a type annotation for a property. Цитата:
void Специальный тип
Применение functionName():void {} Язык версии : ActionScript 3.0 Версии среды выполнения: Flash Player 9 Показывает, что функции не удается возвратить какое-либо значение. Тип void является особым типом, содержащим только одно значение: undefined. Его особенность заключается в том, его использование ограничивается возвращаемым функцией значением. Void нельзя использовать в качестве типа аннотации для свойства. |
|
Обновил(-а) i.o. 22.02.2011 в 15:40
|
22.02.2011 15:47 | |
22.02.2011 15:56 | |
брррр. зачем выкидывать строковое значение альфы, а потом трэйсть numChildren?
|
22.02.2011 15:57 | |
альфа - пережитки предыдущих извращений )
|
22.02.2011 16:20 | |
без try не бывает catch. я вообще потерял нить ваших извращений. то что throw выкидывает что угодно - это известный факт. но чего вы тут добиться пытаетесь?
|
Последние записи от cleptoman
- Starling Builder. Дождались? (28.10.2015)
- Starling. Particles. StarMaker... (05.12.2012)
- FLVEncoder (02.08.2011)
- UnsecurityDisplayLoader - обертка для несекьюрной загрузки дисплей контента (12.02.2011)
- ASDoc Comment Injector (08.02.2011)