这是一个两部分问题。我正在构建一个flash图像查看器,作为一个便携式的年龄限制模块(暴力视频游戏)。基本上,它将从CDN加载任意数量的图像,并要求用户在查看之前输入他们的生日。简单的东西。问题是,根据公司政策,我们不能允许通过任何嗅探手段直接访问这些图像(例如,在Webkit / Firebug中观察您的资源/网络选项卡,或者如果我们以这种方式加载它们,则观看XHR)。所以,我希望得到你对这个问题的最佳方法的看法。
首先,我想有一个服务器端脚本,通过传递一个可以解密但带有动态盐的var来加载图像(例如通过PHP),例如,使用一种不太可能被发现的方法(例如,将盐嵌入整个字符串中),但这会破坏CDN的目的,因为所有请求都将被地理定位到服务器。
然后我认为通过套接字加载图像将是一个很好的解决方案,但是,我在将二进制图像(删除响应标头后)转换为位图时遇到了问题。
还有更好的方法吗?我知道实际上不可能完全阻止内容被链接到(例如有人可以截取闪存)但我的目标只是采取措施防止这种情况通过本地方式发生。任何想法将不胜感激。下面是套接字代码(删除了不相关的部分),如果这有帮助的话。
package com.std.socket {
import flash.system.Security;
import flash.net.Socket;
import flash.events.*;
import flash.errors.*;
import flash.display.Bitmap;
import flash.display.MovieClip;
import flash.display.Loader;
import flash.utils.ByteArray;
public class SocketRequest {
private var root:MovieClip;
private var sock:Socket;
private var data:ByteArray = new ByteArray();
private var request:Object = {
'host': null,
'port': null,
'uri': null,
'callback': null,
'response_parts': [] };
public function SocketRequest(root:MovieClip, host:String, port:int, uri:String, callback:Function):void {
Security.allowDomain('*');
Security.loadPolicyFile('http://foo.bar/crossdomain.xml');
this.request.root = root;
this.request.host = host;
this.request.port = port;
this.request.uri = uri;
this.sock = new Socket();
this.sock.addEventListener(Event.CONNECT, this.evt_socketConnect);
this.sock.addEventListener(Event.CLOSE, this.evt_socketClose);
this.sock.addEventListener(ProgressEvent.SOCKET_DATA, this.evt_socketResponse);
this.sock.connect(this.request.host, this.request.port);
}
private function evt_socketConnect(evt:Event):void {
// Send the request headers
this.sock.writeUTFBytes('GET ' + this.request.uri + " HTTP/1.1\n");
this.sock.writeUTFBytes('Host: ' + this.request.host + ':' + this.request.port + "\n\n");
}
private function evt_socketClose(evt:Event):void {
// Since this is an image, just split on header \r\n and get the last member
var response:Array = this.request.response_parts.join('').split("\r\n");
var body:String = response[response.length - 1];
var loader = new Loader();
var ba:ByteArray = new ByteArray();
var mc:MovieClip = new MovieClip();
this.data.writeMultiByte(body, 'utf-8');
loader.loadBytes(this.data);
mc.addChild(loader);
// Pass the resulting MovieClip back to the caller
if(typeof(this.request.callback) == 'function')
this.request.callback.apply(this.request.root, [mc])
}
private function evt_socketResponse(evt:ProgressEvent):void {
if(!this.sock.bytesAvailable)
return;
this.request.response_parts.push(this.sock.readUTFBytes(this.sock.bytesAvailable));
}
}
}
正如我写的那样,我在考虑SocketRequest::evt_socketResponse()
,this.sock.readUTFBytes()
位应该是:
this.request.response_parts.push(this.sock.readBytes(this.data, this.data.length, evt.bytesLoaded));
然后从this.data
删除标题,但TBH我不是超级ByteArray-savvy。有没有人有任何想法?
答案 0 :(得分:3)
您的代码看起来有些问题。
首先,您正在使用read / writeUTF8Bytes。这对二进制数据不起作用。你需要read / writeBytes。
其次,标题由\r\n\r\n
序列终止,而不是\r\n
。
我将如何做到这一点:
private function evt_socketClose(evt:Event):void {
_buffer.position = 0;
var pos:int = 0;
while(_buffer.bytesAvailable >= 4) {
if(_buffer.readUnsignedByte() == 0xd && _buffer.readUnsignedByte() == 0xa
&& _buffer.readUnsignedByte() == 0xd && _buffer.readUnsignedByte() == 0xa) {
var bodyBytes:ByteArray = new ByteArray();
bodyBytes.writeBytes(_buffer,_buffer.position);
var loader:Loader = new Loader();
var mc:MovieClip = new MovieClip();
loader.loadBytes(bodyBytes);
mc.addChild(loader);
if(this.request.callback is Function) {
this.request.callback.apply(this.request.root, [mc]);
}
// this return isn't really neccesary...
return;
}
}
}
private var _buffer:ByteArray = new ByteArray();
private function evt_socketResponse(evt:ProgressEvent):void {
if(!this.sock.bytesAvailable) {
return;
}
var bytesToRead:uint = this.sock.bytesAvailable;
this.sock.readBytes(_buffer,_buffer.position,bytesToRead);
_buffer.position += bytesToRead;
}
基本上,当您收到数据时,将其存储在缓冲区中。数据完成后,您将开始读取此缓冲区,直到找到标题的末尾(\r\n\r\n
或0xd,0xa,0xd,0xa
)。此时,缓冲区位置是正文/有效负载的第一个字节。因此,您从该点到结尾读取缓冲区并将其存储在ByteArray中。然后将此ByteArray传递给Loader::loadBytes
,如果您加载的是有效图像或swf,则应加载它。