обо всем по-немногу...
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
Комментарии
![]() ![]() |
|
![]() ![]() |
|
За злоупотребление "_" хочется дать по рукам.
|
![]() ![]() |
|
Денис, да, получается я изобретаю велосипеды )
Илья, а где злоупотребление? приватные и протектед всегда с "_"..а вообще, это ты достал очередной топор для холивара ) |
![]() ![]() |
|
спасибо, очень интересно!
|
![]() ![]() |
|
in4core, а как правильно?
|
![]() ![]() |
|
Ну вообще-то только на форуме ломается. В IDE красиво в столбик.
|
![]() ![]() |
|
Цитата:
такой код читать не хочется
|
![]() ![]() |
|
alatar, спасибо, что поправил..имелось ввиду дебаг сессия в ИДЕ
|
![]() ![]() |
|
cleptoman, при выкладывании подобного кода на форум переводите табы в пробелы. тогда ничего не сломается.
|
![]() ![]() |
|
mayakwd, скорее уже тогда за отсутствие this. И вообще, не понимаю, зачем там protected. А вот за методы с подчеркиваем — да, обязательно по рукам.
|
![]() ![]() |
|
топик получился про "правописание")
спасибо за содержательные посты. |
![]() ![]() |
|
in4core, этот комментарий расположен под методом и относится к методу ниже. А он-то return имеет.
|
![]() ![]() |
|
я даже не знаю что ответить...нет, компилятор не ругается.
|
![]() ![]() |
|
КорДум, он про dispatchEvent, видимо
|
![]() ![]() |
|
Кстати действительно интересно, почему не ругается.
|
![]() ![]() |
|
Потому что выход из метода возможен двумя путями - либо по return, либо по throw (кстати, throw можно применять к любому объекту, не только к ошибке или исключению)
|
![]() ![]() |
|
Понятно, спасибо.
|
![]() ![]() |
|
Цитата:
За злоупотребление "_" хочется дать по рукам.
2 cleptoman: Это таким образом получилось достать Bitmap, а BitmapData из нее удачно достается? Т.е., чтобы получить битмапу, стадию можно пропустить? P.S. Стратегии IContentExtractor влепленные в класс на ровном месте весьма доставили ![]() |
|
Обновил(-а) expl 19.02.2011 в 02:36
|
![]() ![]() |
|
свой после переопределения не должен ничо коме эксепшна кидать. может я где чего не докурил, но так задумывалось.
больше интересен момент: Цитата:
Еще один интересный момент заключается в том, что, если убрать строку e.stopPropagation();, то каким то неведомым образом INIT редиспатчится выше, где в обработчике пытаюсь взять контент, которого еще и получаю фейл.
|
|
Обновил(-а) cleptoman 19.02.2011 в 08:52
|
![]() ![]() |
|
Обновил(-а) cleptoman 19.02.2011 в 08:49
|
![]() ![]() |
|
Цитата:
@expl, да достается. да, можно пропустить. да, в примере есть)
|
![]() ![]() |
|
димка, throw ничего не может возвращать ) но выкидывать null он может. я так сам делаю.
|
![]() ![]() |
|
Ээээ. Получается, что после нажатия кнопки "продолжить" в окошке, выброшенном дебаг-плеером, метод, возвращающий что-нибудь возвратит null?
|
![]() ![]() |
|
я ещё раз повторю. он ничего не вернёт. в лучшем случае undefined. но он ничего не вернёт. throw != return;
|
![]() ![]() |
|
тут фишка впринципе понятна, не пробовал могу ошибаться, но поидее
Дальше throw не пойдет. и трейса мы не увидим. Тоесть в нашем случае Да и кстати, даже Имеет свой return который наглядно ничего не вернет. но завершает функцию по окончанию чтения строк или выводу ошибки. В итоге void это тоже возвращаемая величина ))) |
|
Обновил(-а) in4core 22.02.2011 в 04:06
|
![]() ![]() |
|
Я понял. По throw просто прерывается исполнение кода. Ничего никуда не возвращается. Всем спасибо,
|
![]() ![]() |
|
@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
|
![]() ![]() |
|
![]() ![]() |
|
in4core, throw выбрасывает из стэка напроч. а return на уровень выше. а на счёт void я даже не хочу комментировать. научитесь читать что ли ...
|
![]() ![]() |
|
Цитата:
Вам же вернулось undefined! а это значение!. если бы ничего не вернулось тоесть пусто бы было, знеачит и возвращения нету.
|
![]() ![]() |
|
На всякий случай, все же, на 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
|
![]() ![]() |
|
![]() ![]() |
|
брррр. зачем выкидывать строковое значение альфы, а потом трэйсть numChildren?
|
![]() ![]() |
|
альфа - пережитки предыдущих извращений )
|
![]() ![]() |
|
без 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)