From 840bade50b095168e49992d1f8614ec189498c12 Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Mon, 18 Jul 2011 21:02:54 +0900 Subject: Adding event.text to error message on IoError and SecurityError. --- flash-src/WebSocket.as | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'flash-src') diff --git a/flash-src/WebSocket.as b/flash-src/WebSocket.as index 813f517..43b274a 100644 --- a/flash-src/WebSocket.as +++ b/flash-src/WebSocket.as @@ -208,9 +208,11 @@ public class WebSocket extends EventDispatcher { private function onSocketIoError(event:IOErrorEvent):void { var message:String; if (readyState == CONNECTING) { - message = "cannot connect to Web Socket server at " + url + " (IoError)"; + message = "cannot connect to Web Socket server at " + url + " (IoError: " + event.text + ")"; } else { - message = "error communicating with Web Socket server at " + url + " (IoError)"; + message = + "error communicating with Web Socket server at " + url + + " (IoError: " + event.text + ")"; } onError(message); } @@ -219,10 +221,12 @@ public class WebSocket extends EventDispatcher { var message:String; if (readyState == CONNECTING) { message = - "cannot connect to Web Socket server at " + url + " (SecurityError)\n" + + "cannot connect to Web Socket server at " + url + " (SecurityError: " + event.text + ")\n" + "make sure the server is running and Flash socket policy file is correctly placed"; } else { - message = "error communicating with Web Socket server at " + url + " (SecurityError)"; + message = + "error communicating with Web Socket server at " + url + + " (SecurityError: " + event.text + ")"; } onError(message); } -- cgit v1.2.1 From 179a0a97c23061d555672c367bda78bd7d84e2ac Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Sat, 6 Aug 2011 23:06:56 +0900 Subject: Fixing import. --- flash-src/WebSocketMainInsecure.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'flash-src') diff --git a/flash-src/WebSocketMainInsecure.as b/flash-src/WebSocketMainInsecure.as index ea377be..ea4f496 100644 --- a/flash-src/WebSocketMainInsecure.as +++ b/flash-src/WebSocketMainInsecure.as @@ -5,7 +5,7 @@ package { -import flash.system.*; +import flash.system.Security; public class WebSocketMainInsecure extends WebSocketMain { -- cgit v1.2.1 From cf1ad5327834853b753f3206bfbfddc743f5b26c Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Sat, 6 Aug 2011 23:48:06 +0900 Subject: Moving Flash classes to package net.gimite.websocket. --- flash-src/IWebSocketLogger.as | 8 - flash-src/WebSocket.as | 468 --------------------- flash-src/WebSocketEvent.as | 33 -- flash-src/WebSocketMain.as | 150 ------- flash-src/WebSocketMainInsecure.as | 19 - flash-src/build.sh | 4 +- flash-src/net/gimite/websocket/IWebSocketLogger.as | 11 + flash-src/net/gimite/websocket/WebSocket.as | 468 +++++++++++++++++++++ flash-src/net/gimite/websocket/WebSocketEvent.as | 33 ++ flash-src/net/gimite/websocket/WebSocketMain.as | 150 +++++++ .../net/gimite/websocket/WebSocketMainInsecure.as | 19 + 11 files changed, 683 insertions(+), 680 deletions(-) delete mode 100644 flash-src/IWebSocketLogger.as delete mode 100644 flash-src/WebSocket.as delete mode 100644 flash-src/WebSocketEvent.as delete mode 100644 flash-src/WebSocketMain.as delete mode 100644 flash-src/WebSocketMainInsecure.as create mode 100644 flash-src/net/gimite/websocket/IWebSocketLogger.as create mode 100644 flash-src/net/gimite/websocket/WebSocket.as create mode 100644 flash-src/net/gimite/websocket/WebSocketEvent.as create mode 100644 flash-src/net/gimite/websocket/WebSocketMain.as create mode 100644 flash-src/net/gimite/websocket/WebSocketMainInsecure.as (limited to 'flash-src') diff --git a/flash-src/IWebSocketLogger.as b/flash-src/IWebSocketLogger.as deleted file mode 100644 index 24f4ef7..0000000 --- a/flash-src/IWebSocketLogger.as +++ /dev/null @@ -1,8 +0,0 @@ -package { - -public interface IWebSocketLogger { - function log(message:String):void; - function error(message:String):void; -} - -} diff --git a/flash-src/WebSocket.as b/flash-src/WebSocket.as deleted file mode 100644 index 43b274a..0000000 --- a/flash-src/WebSocket.as +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright: Hiroshi Ichikawa -// License: New BSD License -// Reference: http://dev.w3.org/html5/websockets/ -// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 - -package { - -import com.adobe.net.proxies.RFC2817Socket; -import com.gsolo.encryption.MD5; -import com.hurlant.crypto.tls.TLSConfig; -import com.hurlant.crypto.tls.TLSEngine; -import com.hurlant.crypto.tls.TLSSecurityParameters; -import com.hurlant.crypto.tls.TLSSocket; - -import flash.display.*; -import flash.events.*; -import flash.external.*; -import flash.net.*; -import flash.system.*; -import flash.utils.*; - -import mx.controls.*; -import mx.core.*; -import mx.events.*; -import mx.utils.*; - -public class WebSocket extends EventDispatcher { - - private static var CONNECTING:int = 0; - private static var OPEN:int = 1; - private static var CLOSING:int = 2; - private static var CLOSED:int = 3; - - private var id:int; - private var rawSocket:Socket; - private var tlsSocket:TLSSocket; - private var tlsConfig:TLSConfig; - private var socket:Socket; - private var url:String; - private var scheme:String; - private var host:String; - private var port:uint; - private var path:String; - private var origin:String; - private var requestedProtocols:Array; - private var acceptedProtocol:String; - private var buffer:ByteArray = new ByteArray(); - private var headerState:int = 0; - private var readyState:int = CONNECTING; - private var cookie:String; - private var headers:String; - private var noiseChars:Array; - private var expectedDigest:String; - private var logger:IWebSocketLogger; - - public function WebSocket( - id:int, url:String, protocols:Array, origin:String, - proxyHost:String, proxyPort:int, - cookie:String, headers:String, - logger:IWebSocketLogger) { - this.logger = logger; - this.id = id; - initNoiseChars(); - this.url = url; - var m:Array = url.match(/^(\w+):\/\/([^\/:]+)(:(\d+))?(\/.*)?(\?.*)?$/); - if (!m) fatal("SYNTAX_ERR: invalid url: " + url); - this.scheme = m[1]; - this.host = m[2]; - var defaultPort:int = scheme == "wss" ? 443 : 80; - this.port = parseInt(m[4]) || defaultPort; - this.path = (m[5] || "/") + (m[6] || ""); - this.origin = origin; - this.requestedProtocols = protocols; - this.cookie = cookie; - // if present and not the empty string, headers MUST end with \r\n - // headers should be zero or more complete lines, for example - // "Header1: xxx\r\nHeader2: yyyy\r\n" - this.headers = headers; - - if (proxyHost != null && proxyPort != 0){ - if (scheme == "wss") { - fatal("wss with proxy is not supported"); - } - var proxySocket:RFC2817Socket = new RFC2817Socket(); - proxySocket.setProxyInfo(proxyHost, proxyPort); - proxySocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); - rawSocket = socket = proxySocket; - } else { - rawSocket = new Socket(); - if (scheme == "wss") { - tlsConfig= new TLSConfig(TLSEngine.CLIENT, - null, null, null, null, null, - TLSSecurityParameters.PROTOCOL_VERSION); - tlsConfig.trustAllCertificates = true; - tlsConfig.ignoreCommonNameMismatch = true; - tlsSocket = new TLSSocket(); - tlsSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); - socket = tlsSocket; - } else { - rawSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); - socket = rawSocket; - } - } - rawSocket.addEventListener(Event.CLOSE, onSocketClose); - rawSocket.addEventListener(Event.CONNECT, onSocketConnect); - rawSocket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError); - rawSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError); - rawSocket.connect(host, port); - } - - /** - * @return This WebSocket's ID. - */ - public function getId():int { - return this.id; - } - - /** - * @return this WebSocket's readyState. - */ - public function getReadyState():int { - return this.readyState; - } - - public function getAcceptedProtocol():String { - return this.acceptedProtocol; - } - - public function send(encData:String):int { - var data:String = decodeURIComponent(encData); - if (readyState == OPEN) { - socket.writeByte(0x00); - socket.writeUTFBytes(data); - socket.writeByte(0xff); - socket.flush(); - logger.log("sent: " + data); - return -1; - } else if (readyState == CLOSING || readyState == CLOSED) { - var bytes:ByteArray = new ByteArray(); - bytes.writeUTFBytes(data); - return bytes.length; // not sure whether it should include \x00 and \xff - } else { - fatal("invalid state"); - return 0; - } - } - - public function close(isError:Boolean = false):void { - logger.log("close"); - try { - if (readyState == OPEN && !isError) { - socket.writeByte(0xff); - socket.writeByte(0x00); - socket.flush(); - } - socket.close(); - } catch (ex:Error) { } - readyState = CLOSED; - this.dispatchEvent(new WebSocketEvent(isError ? "error" : "close")); - } - - private function onSocketConnect(event:Event):void { - logger.log("connected"); - - if (scheme == "wss") { - logger.log("starting SSL/TLS"); - tlsSocket.startTLS(rawSocket, host, tlsConfig); - } - - var defaultPort:int = scheme == "wss" ? 443 : 80; - var hostValue:String = host + (port == defaultPort ? "" : ":" + port); - var key1:String = generateKey(); - var key2:String = generateKey(); - var key3:String = generateKey3(); - expectedDigest = getSecurityDigest(key1, key2, key3); - var opt:String = ""; - if (requestedProtocols.length > 0) { - opt += "Sec-WebSocket-Protocol: " + requestedProtocols.join(",") + "\r\n"; - } - // if caller passes additional headers they must end with "\r\n" - if (headers) opt += headers; - - var req:String = StringUtil.substitute( - "GET {0} HTTP/1.1\r\n" + - "Upgrade: WebSocket\r\n" + - "Connection: Upgrade\r\n" + - "Host: {1}\r\n" + - "Origin: {2}\r\n" + - "Cookie: {3}\r\n" + - "Sec-WebSocket-Key1: {4}\r\n" + - "Sec-WebSocket-Key2: {5}\r\n" + - "{6}" + - "\r\n", - path, hostValue, origin, cookie, key1, key2, opt); - logger.log("request header:\n" + req); - socket.writeUTFBytes(req); - logger.log("sent key3: " + key3); - writeBytes(key3); - socket.flush(); - } - - private function onSocketClose(event:Event):void { - logger.log("closed"); - readyState = CLOSED; - this.dispatchEvent(new WebSocketEvent("close")); - } - - private function onSocketIoError(event:IOErrorEvent):void { - var message:String; - if (readyState == CONNECTING) { - message = "cannot connect to Web Socket server at " + url + " (IoError: " + event.text + ")"; - } else { - message = - "error communicating with Web Socket server at " + url + - " (IoError: " + event.text + ")"; - } - onError(message); - } - - private function onSocketSecurityError(event:SecurityErrorEvent):void { - var message:String; - if (readyState == CONNECTING) { - message = - "cannot connect to Web Socket server at " + url + " (SecurityError: " + event.text + ")\n" + - "make sure the server is running and Flash socket policy file is correctly placed"; - } else { - message = - "error communicating with Web Socket server at " + url + - " (SecurityError: " + event.text + ")"; - } - onError(message); - } - - private function onError(message:String):void { - if (readyState == CLOSED) return; - logger.error(message); - close(readyState != CONNECTING); - } - - private function onSocketData(event:ProgressEvent):void { - var pos:int = buffer.length; - socket.readBytes(buffer, pos); - for (; pos < buffer.length; ++pos) { - if (headerState < 4) { - // try to find "\r\n\r\n" - if ((headerState == 0 || headerState == 2) && buffer[pos] == 0x0d) { - ++headerState; - } else if ((headerState == 1 || headerState == 3) && buffer[pos] == 0x0a) { - ++headerState; - } else { - headerState = 0; - } - if (headerState == 4) { - var headerStr:String = readUTFBytes(buffer, 0, pos + 1); - logger.log("response header:\n" + headerStr); - if (!validateHeader(headerStr)) return; - removeBufferBefore(pos + 1); - pos = -1; - } - } else if (headerState == 4) { - if (pos == 15) { - var replyDigest:String = readBytes(buffer, 0, 16); - logger.log("reply digest: " + replyDigest); - if (replyDigest != expectedDigest) { - onError("digest doesn't match: " + replyDigest + " != " + expectedDigest); - return; - } - headerState = 5; - removeBufferBefore(pos + 1); - pos = -1; - readyState = OPEN; - this.dispatchEvent(new WebSocketEvent("open")); - } - } else { - if (buffer[pos] == 0xff && pos > 0) { - if (buffer[0] != 0x00) { - onError("data must start with \\x00"); - return; - } - var data:String = readUTFBytes(buffer, 1, pos - 1); - logger.log("received: " + data); - this.dispatchEvent(new WebSocketEvent("message", encodeURIComponent(data))); - removeBufferBefore(pos + 1); - pos = -1; - } else if (pos == 1 && buffer[0] == 0xff && buffer[1] == 0x00) { // closing - logger.log("received closing packet"); - removeBufferBefore(pos + 1); - pos = -1; - close(); - } - } - } - } - - private function validateHeader(headerStr:String):Boolean { - var lines:Array = headerStr.split(/\r\n/); - if (!lines[0].match(/^HTTP\/1.1 101 /)) { - onError("bad response: " + lines[0]); - return false; - } - var header:Object = {}; - var lowerHeader:Object = {}; - for (var i:int = 1; i < lines.length; ++i) { - if (lines[i].length == 0) continue; - var m:Array = lines[i].match(/^(\S+): (.*)$/); - if (!m) { - onError("failed to parse response header line: " + lines[i]); - return false; - } - header[m[1].toLowerCase()] = m[2]; - lowerHeader[m[1].toLowerCase()] = m[2].toLowerCase(); - } - if (lowerHeader["upgrade"] != "websocket") { - onError("invalid Upgrade: " + header["Upgrade"]); - return false; - } - if (lowerHeader["connection"] != "upgrade") { - onError("invalid Connection: " + header["Connection"]); - return false; - } - if (!lowerHeader["sec-websocket-origin"]) { - if (lowerHeader["websocket-origin"]) { - onError( - "The WebSocket server speaks old WebSocket protocol, " + - "which is not supported by web-socket-js. " + - "It requires WebSocket protocol 76 or later. " + - "Try newer version of the server if available."); - } else { - onError("header Sec-WebSocket-Origin is missing"); - } - return false; - } - var resOrigin:String = lowerHeader["sec-websocket-origin"]; - if (resOrigin != origin) { - onError("origin doesn't match: '" + resOrigin + "' != '" + origin + "'"); - return false; - } - if (requestedProtocols.length > 0) { - acceptedProtocol = header["sec-websocket-protocol"]; - if (requestedProtocols.indexOf(acceptedProtocol) < 0) { - onError("protocol doesn't match: '" + - acceptedProtocol + "' not in '" + requestedProtocols.join(",") + "'"); - return false; - } - } - return true; - } - - private function removeBufferBefore(pos:int):void { - if (pos == 0) return; - var nextBuffer:ByteArray = new ByteArray(); - buffer.position = pos; - buffer.readBytes(nextBuffer); - buffer = nextBuffer; - } - - private function initNoiseChars():void { - noiseChars = new Array(); - for (var i:int = 0x21; i <= 0x2f; ++i) { - noiseChars.push(String.fromCharCode(i)); - } - for (var j:int = 0x3a; j <= 0x7a; ++j) { - noiseChars.push(String.fromCharCode(j)); - } - } - - private function generateKey():String { - var spaces:uint = randomInt(1, 12); - var max:uint = uint.MAX_VALUE / spaces; - var number:uint = randomInt(0, max); - var key:String = (number * spaces).toString(); - var noises:int = randomInt(1, 12); - var pos:int; - for (var i:int = 0; i < noises; ++i) { - var char:String = noiseChars[randomInt(0, noiseChars.length - 1)]; - pos = randomInt(0, key.length); - key = key.substr(0, pos) + char + key.substr(pos); - } - for (var j:int = 0; j < spaces; ++j) { - pos = randomInt(1, key.length - 1); - key = key.substr(0, pos) + " " + key.substr(pos); - } - return key; - } - - private function generateKey3():String { - var key3:String = ""; - for (var i:int = 0; i < 8; ++i) { - key3 += String.fromCharCode(randomInt(0, 255)); - } - return key3; - } - - private function getSecurityDigest(key1:String, key2:String, key3:String):String { - var bytes1:String = keyToBytes(key1); - var bytes2:String = keyToBytes(key2); - return MD5.rstr_md5(bytes1 + bytes2 + key3); - } - - private function keyToBytes(key:String):String { - var keyNum:uint = parseInt(key.replace(/[^\d]/g, "")); - var spaces:uint = 0; - for (var i:int = 0; i < key.length; ++i) { - if (key.charAt(i) == " ") ++spaces; - } - var resultNum:uint = keyNum / spaces; - var bytes:String = ""; - for (var j:int = 3; j >= 0; --j) { - bytes += String.fromCharCode((resultNum >> (j * 8)) & 0xff); - } - return bytes; - } - - // Writes byte sequence to socket. - // bytes is String in special format where bytes[i] is i-th byte, not i-th character. - private function writeBytes(bytes:String):void { - for (var i:int = 0; i < bytes.length; ++i) { - socket.writeByte(bytes.charCodeAt(i)); - } - } - - // Reads specified number of bytes from buffer, and returns it as special format String - // where bytes[i] is i-th byte (not i-th character). - private function readBytes(buffer:ByteArray, start:int, numBytes:int):String { - buffer.position = start; - var bytes:String = ""; - for (var i:int = 0; i < numBytes; ++i) { - // & 0xff is to make \x80-\xff positive number. - bytes += String.fromCharCode(buffer.readByte() & 0xff); - } - return bytes; - } - - private function readUTFBytes(buffer:ByteArray, start:int, numBytes:int):String { - buffer.position = start; - var data:String = ""; - for(var i:int = start; i < start + numBytes; ++i) { - // Workaround of a bug of ByteArray#readUTFBytes() that bytes after "\x00" is discarded. - if (buffer[i] == 0x00) { - data += buffer.readUTFBytes(i - buffer.position) + "\x00"; - buffer.position = i + 1; - } - } - data += buffer.readUTFBytes(start + numBytes - buffer.position); - return data; - } - - private function randomInt(min:uint, max:uint):uint { - return min + Math.floor(Math.random() * (Number(max) - min + 1)); - } - - private function fatal(message:String):void { - logger.error(message); - throw message; - } - - // for debug - private function dumpBytes(bytes:String):void { - var output:String = ""; - for (var i:int = 0; i < bytes.length; ++i) { - output += bytes.charCodeAt(i).toString() + ", "; - } - logger.log(output); - } - -} - -} diff --git a/flash-src/WebSocketEvent.as b/flash-src/WebSocketEvent.as deleted file mode 100644 index 598eeb2..0000000 --- a/flash-src/WebSocketEvent.as +++ /dev/null @@ -1,33 +0,0 @@ -package { - -import flash.events.Event; - -/** - * This class represents a generic websocket event. It contains the standard "type" - * parameter as well as a "message" parameter. - */ -public class WebSocketEvent extends Event { - - public static const OPEN:String = "open"; - public static const CLOSE:String = "close"; - public static const MESSAGE:String = "message"; - public static const ERROR:String = "error"; - - public var message:String; - - public function WebSocketEvent( - type:String, message:String = null, bubbles:Boolean = false, cancelable:Boolean = false) { - super(type, bubbles, cancelable); - this.message = message; - } - - public override function clone():Event { - return new WebSocketEvent(this.type, this.message, this.bubbles, this.cancelable); - } - - public override function toString():String { - return "WebSocketEvent: " + this.type + ": " + this.message; - } -} - -} diff --git a/flash-src/WebSocketMain.as b/flash-src/WebSocketMain.as deleted file mode 100644 index 1bf3d7e..0000000 --- a/flash-src/WebSocketMain.as +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright: Hiroshi Ichikawa -// License: New BSD License -// Reference: http://dev.w3.org/html5/websockets/ -// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 - -package { - -import flash.display.Sprite; -import flash.external.ExternalInterface; -import flash.system.Security; -import flash.utils.setTimeout; - -import mx.utils.URLUtil; - -/** - * Provides JavaScript API of WebSocket. - */ -public class WebSocketMain extends Sprite implements IWebSocketLogger{ - - private var callerUrl:String; - private var debug:Boolean = false; - private var manualPolicyFileLoaded:Boolean = false; - private var webSockets:Array = []; - private var eventQueue:Array = []; - - public function WebSocketMain() { - ExternalInterface.addCallback("setCallerUrl", setCallerUrl); - ExternalInterface.addCallback("setDebug", setDebug); - ExternalInterface.addCallback("create", create); - ExternalInterface.addCallback("send", send); - ExternalInterface.addCallback("close", close); - ExternalInterface.addCallback("loadManualPolicyFile", loadManualPolicyFile); - ExternalInterface.addCallback("receiveEvents", receiveEvents); - ExternalInterface.call("WebSocket.__onFlashInitialized"); - } - - public function setCallerUrl(url:String):void { - callerUrl = url; - } - - public function setDebug(val:Boolean):void { - debug = val; - } - - private function loadDefaultPolicyFile(wsUrl:String):void { - var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843"; - log("policy file: " + policyUrl); - Security.loadPolicyFile(policyUrl); - } - - public function loadManualPolicyFile(policyUrl:String):void { - log("policy file: " + policyUrl); - Security.loadPolicyFile(policyUrl); - manualPolicyFileLoaded = true; - } - - public function log(message:String):void { - if (debug) { - ExternalInterface.call("WebSocket.__log", encodeURIComponent("[WebSocket] " + message)); - } - } - - public function error(message:String):void { - ExternalInterface.call("WebSocket.__error", encodeURIComponent("[WebSocket] " + message)); - } - - private function parseEvent(event:WebSocketEvent):Object { - var webSocket:WebSocket = event.target as WebSocket; - var eventObj:Object = {}; - eventObj.type = event.type; - eventObj.webSocketId = webSocket.getId(); - eventObj.readyState = webSocket.getReadyState(); - eventObj.protocol = webSocket.getAcceptedProtocol(); - if (event.message !== null) { - eventObj.message = event.message; - } - return eventObj; - } - - public function create( - webSocketId:int, - url:String, protocols:Array, - proxyHost:String = null, proxyPort:int = 0, - headers:String = null):void { - if (!manualPolicyFileLoaded) { - loadDefaultPolicyFile(url); - } - var newSocket:WebSocket = new WebSocket( - webSocketId, url, protocols, getOrigin(), proxyHost, proxyPort, - getCookie(url), headers, this); - newSocket.addEventListener("open", onSocketEvent); - newSocket.addEventListener("close", onSocketEvent); - newSocket.addEventListener("error", onSocketEvent); - newSocket.addEventListener("message", onSocketEvent); - webSockets[webSocketId] = newSocket; - } - - public function send(webSocketId:int, encData:String):int { - var webSocket:WebSocket = webSockets[webSocketId]; - return webSocket.send(encData); - } - - public function close(webSocketId:int):void { - var webSocket:WebSocket = webSockets[webSocketId]; - webSocket.close(); - } - - public function receiveEvents():Object { - var result:Object = eventQueue; - eventQueue = []; - return result; - } - - private function getOrigin():String { - return (URLUtil.getProtocol(this.callerUrl) + "://" + - URLUtil.getServerNameWithPort(this.callerUrl)).toLowerCase(); - } - - private function getCookie(url:String):String { - if (URLUtil.getServerName(url).toLowerCase() == - URLUtil.getServerName(this.callerUrl).toLowerCase()) { - return ExternalInterface.call("function(){return document.cookie}"); - } else { - return ""; - } - } - - /** - * Socket event handler. - */ - public function onSocketEvent(event:WebSocketEvent):void { - var eventObj:Object = parseEvent(event); - eventQueue.push(eventObj); - processEvents(); - } - - /** - * Process our event queue. If javascript is unresponsive, set - * a timeout and try again. - */ - public function processEvents():void { - if (eventQueue.length == 0) return; - if (!ExternalInterface.call("WebSocket.__onFlashEvent")) { - setTimeout(processEvents, 500); - } - } - -} - -} diff --git a/flash-src/WebSocketMainInsecure.as b/flash-src/WebSocketMainInsecure.as deleted file mode 100644 index ea4f496..0000000 --- a/flash-src/WebSocketMainInsecure.as +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright: Hiroshi Ichikawa -// License: New BSD License -// Reference: http://dev.w3.org/html5/websockets/ -// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 - -package { - -import flash.system.Security; - -public class WebSocketMainInsecure extends WebSocketMain { - - public function WebSocketMainInsecure() { - Security.allowDomain("*"); - super(); - } - -} - -} diff --git a/flash-src/build.sh b/flash-src/build.sh index 598674a..4d33853 100755 --- a/flash-src/build.sh +++ b/flash-src/build.sh @@ -3,8 +3,8 @@ # You need Flex 4 SDK: # http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4 -mxmlc -static-link-runtime-shared-libraries -target-player=10.0.0 -output=../WebSocketMain.swf WebSocketMain.as && -mxmlc -static-link-runtime-shared-libraries -output=../WebSocketMainInsecure.swf WebSocketMainInsecure.as && +mxmlc -static-link-runtime-shared-libraries -target-player=10.0.0 -output=../WebSocketMain.swf -source-path=. net/gimite/websocket/WebSocketMain.as && +mxmlc -static-link-runtime-shared-libraries -output=../WebSocketMainInsecure.swf -source-path=. net/gimite/websocket/WebSocketMainInsecure.as && cd .. && zip WebSocketMainInsecure.zip WebSocketMainInsecure.swf && rm WebSocketMainInsecure.swf diff --git a/flash-src/net/gimite/websocket/IWebSocketLogger.as b/flash-src/net/gimite/websocket/IWebSocketLogger.as new file mode 100644 index 0000000..c3384f3 --- /dev/null +++ b/flash-src/net/gimite/websocket/IWebSocketLogger.as @@ -0,0 +1,11 @@ +// Copyright: Hiroshi Ichikawa +// License: New BSD License + +package net.gimite.websocket { + +public interface IWebSocketLogger { + function log(message:String):void; + function error(message:String):void; +} + +} diff --git a/flash-src/net/gimite/websocket/WebSocket.as b/flash-src/net/gimite/websocket/WebSocket.as new file mode 100644 index 0000000..f043b60 --- /dev/null +++ b/flash-src/net/gimite/websocket/WebSocket.as @@ -0,0 +1,468 @@ +// Copyright: Hiroshi Ichikawa +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 + +package net.gimite.websocket { + +import com.adobe.net.proxies.RFC2817Socket; +import com.gsolo.encryption.MD5; +import com.hurlant.crypto.tls.TLSConfig; +import com.hurlant.crypto.tls.TLSEngine; +import com.hurlant.crypto.tls.TLSSecurityParameters; +import com.hurlant.crypto.tls.TLSSocket; + +import flash.display.*; +import flash.events.*; +import flash.external.*; +import flash.net.*; +import flash.system.*; +import flash.utils.*; + +import mx.controls.*; +import mx.core.*; +import mx.events.*; +import mx.utils.*; + +public class WebSocket extends EventDispatcher { + + private static var CONNECTING:int = 0; + private static var OPEN:int = 1; + private static var CLOSING:int = 2; + private static var CLOSED:int = 3; + + private var id:int; + private var rawSocket:Socket; + private var tlsSocket:TLSSocket; + private var tlsConfig:TLSConfig; + private var socket:Socket; + private var url:String; + private var scheme:String; + private var host:String; + private var port:uint; + private var path:String; + private var origin:String; + private var requestedProtocols:Array; + private var acceptedProtocol:String; + private var buffer:ByteArray = new ByteArray(); + private var headerState:int = 0; + private var readyState:int = CONNECTING; + private var cookie:String; + private var headers:String; + private var noiseChars:Array; + private var expectedDigest:String; + private var logger:IWebSocketLogger; + + public function WebSocket( + id:int, url:String, protocols:Array, origin:String, + proxyHost:String, proxyPort:int, + cookie:String, headers:String, + logger:IWebSocketLogger) { + this.logger = logger; + this.id = id; + initNoiseChars(); + this.url = url; + var m:Array = url.match(/^(\w+):\/\/([^\/:]+)(:(\d+))?(\/.*)?(\?.*)?$/); + if (!m) fatal("SYNTAX_ERR: invalid url: " + url); + this.scheme = m[1]; + this.host = m[2]; + var defaultPort:int = scheme == "wss" ? 443 : 80; + this.port = parseInt(m[4]) || defaultPort; + this.path = (m[5] || "/") + (m[6] || ""); + this.origin = origin; + this.requestedProtocols = protocols; + this.cookie = cookie; + // if present and not the empty string, headers MUST end with \r\n + // headers should be zero or more complete lines, for example + // "Header1: xxx\r\nHeader2: yyyy\r\n" + this.headers = headers; + + if (proxyHost != null && proxyPort != 0){ + if (scheme == "wss") { + fatal("wss with proxy is not supported"); + } + var proxySocket:RFC2817Socket = new RFC2817Socket(); + proxySocket.setProxyInfo(proxyHost, proxyPort); + proxySocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); + rawSocket = socket = proxySocket; + } else { + rawSocket = new Socket(); + if (scheme == "wss") { + tlsConfig= new TLSConfig(TLSEngine.CLIENT, + null, null, null, null, null, + TLSSecurityParameters.PROTOCOL_VERSION); + tlsConfig.trustAllCertificates = true; + tlsConfig.ignoreCommonNameMismatch = true; + tlsSocket = new TLSSocket(); + tlsSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); + socket = tlsSocket; + } else { + rawSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData); + socket = rawSocket; + } + } + rawSocket.addEventListener(Event.CLOSE, onSocketClose); + rawSocket.addEventListener(Event.CONNECT, onSocketConnect); + rawSocket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError); + rawSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError); + rawSocket.connect(host, port); + } + + /** + * @return This WebSocket's ID. + */ + public function getId():int { + return this.id; + } + + /** + * @return this WebSocket's readyState. + */ + public function getReadyState():int { + return this.readyState; + } + + public function getAcceptedProtocol():String { + return this.acceptedProtocol; + } + + public function send(encData:String):int { + var data:String = decodeURIComponent(encData); + if (readyState == OPEN) { + socket.writeByte(0x00); + socket.writeUTFBytes(data); + socket.writeByte(0xff); + socket.flush(); + logger.log("sent: " + data); + return -1; + } else if (readyState == CLOSING || readyState == CLOSED) { + var bytes:ByteArray = new ByteArray(); + bytes.writeUTFBytes(data); + return bytes.length; // not sure whether it should include \x00 and \xff + } else { + fatal("invalid state"); + return 0; + } + } + + public function close(isError:Boolean = false):void { + logger.log("close"); + try { + if (readyState == OPEN && !isError) { + socket.writeByte(0xff); + socket.writeByte(0x00); + socket.flush(); + } + socket.close(); + } catch (ex:Error) { } + readyState = CLOSED; + this.dispatchEvent(new WebSocketEvent(isError ? "error" : "close")); + } + + private function onSocketConnect(event:Event):void { + logger.log("connected"); + + if (scheme == "wss") { + logger.log("starting SSL/TLS"); + tlsSocket.startTLS(rawSocket, host, tlsConfig); + } + + var defaultPort:int = scheme == "wss" ? 443 : 80; + var hostValue:String = host + (port == defaultPort ? "" : ":" + port); + var key1:String = generateKey(); + var key2:String = generateKey(); + var key3:String = generateKey3(); + expectedDigest = getSecurityDigest(key1, key2, key3); + var opt:String = ""; + if (requestedProtocols.length > 0) { + opt += "Sec-WebSocket-Protocol: " + requestedProtocols.join(",") + "\r\n"; + } + // if caller passes additional headers they must end with "\r\n" + if (headers) opt += headers; + + var req:String = StringUtil.substitute( + "GET {0} HTTP/1.1\r\n" + + "Upgrade: WebSocket\r\n" + + "Connection: Upgrade\r\n" + + "Host: {1}\r\n" + + "Origin: {2}\r\n" + + "Cookie: {3}\r\n" + + "Sec-WebSocket-Key1: {4}\r\n" + + "Sec-WebSocket-Key2: {5}\r\n" + + "{6}" + + "\r\n", + path, hostValue, origin, cookie, key1, key2, opt); + logger.log("request header:\n" + req); + socket.writeUTFBytes(req); + logger.log("sent key3: " + key3); + writeBytes(key3); + socket.flush(); + } + + private function onSocketClose(event:Event):void { + logger.log("closed"); + readyState = CLOSED; + this.dispatchEvent(new WebSocketEvent("close")); + } + + private function onSocketIoError(event:IOErrorEvent):void { + var message:String; + if (readyState == CONNECTING) { + message = "cannot connect to Web Socket server at " + url + " (IoError: " + event.text + ")"; + } else { + message = + "error communicating with Web Socket server at " + url + + " (IoError: " + event.text + ")"; + } + onError(message); + } + + private function onSocketSecurityError(event:SecurityErrorEvent):void { + var message:String; + if (readyState == CONNECTING) { + message = + "cannot connect to Web Socket server at " + url + " (SecurityError: " + event.text + ")\n" + + "make sure the server is running and Flash socket policy file is correctly placed"; + } else { + message = + "error communicating with Web Socket server at " + url + + " (SecurityError: " + event.text + ")"; + } + onError(message); + } + + private function onError(message:String):void { + if (readyState == CLOSED) return; + logger.error(message); + close(readyState != CONNECTING); + } + + private function onSocketData(event:ProgressEvent):void { + var pos:int = buffer.length; + socket.readBytes(buffer, pos); + for (; pos < buffer.length; ++pos) { + if (headerState < 4) { + // try to find "\r\n\r\n" + if ((headerState == 0 || headerState == 2) && buffer[pos] == 0x0d) { + ++headerState; + } else if ((headerState == 1 || headerState == 3) && buffer[pos] == 0x0a) { + ++headerState; + } else { + headerState = 0; + } + if (headerState == 4) { + var headerStr:String = readUTFBytes(buffer, 0, pos + 1); + logger.log("response header:\n" + headerStr); + if (!validateHeader(headerStr)) return; + removeBufferBefore(pos + 1); + pos = -1; + } + } else if (headerState == 4) { + if (pos == 15) { + var replyDigest:String = readBytes(buffer, 0, 16); + logger.log("reply digest: " + replyDigest); + if (replyDigest != expectedDigest) { + onError("digest doesn't match: " + replyDigest + " != " + expectedDigest); + return; + } + headerState = 5; + removeBufferBefore(pos + 1); + pos = -1; + readyState = OPEN; + this.dispatchEvent(new WebSocketEvent("open")); + } + } else { + if (buffer[pos] == 0xff && pos > 0) { + if (buffer[0] != 0x00) { + onError("data must start with \\x00"); + return; + } + var data:String = readUTFBytes(buffer, 1, pos - 1); + logger.log("received: " + data); + this.dispatchEvent(new WebSocketEvent("message", encodeURIComponent(data))); + removeBufferBefore(pos + 1); + pos = -1; + } else if (pos == 1 && buffer[0] == 0xff && buffer[1] == 0x00) { // closing + logger.log("received closing packet"); + removeBufferBefore(pos + 1); + pos = -1; + close(); + } + } + } + } + + private function validateHeader(headerStr:String):Boolean { + var lines:Array = headerStr.split(/\r\n/); + if (!lines[0].match(/^HTTP\/1.1 101 /)) { + onError("bad response: " + lines[0]); + return false; + } + var header:Object = {}; + var lowerHeader:Object = {}; + for (var i:int = 1; i < lines.length; ++i) { + if (lines[i].length == 0) continue; + var m:Array = lines[i].match(/^(\S+): (.*)$/); + if (!m) { + onError("failed to parse response header line: " + lines[i]); + return false; + } + header[m[1].toLowerCase()] = m[2]; + lowerHeader[m[1].toLowerCase()] = m[2].toLowerCase(); + } + if (lowerHeader["upgrade"] != "websocket") { + onError("invalid Upgrade: " + header["Upgrade"]); + return false; + } + if (lowerHeader["connection"] != "upgrade") { + onError("invalid Connection: " + header["Connection"]); + return false; + } + if (!lowerHeader["sec-websocket-origin"]) { + if (lowerHeader["websocket-origin"]) { + onError( + "The WebSocket server speaks old WebSocket protocol, " + + "which is not supported by web-socket-js. " + + "It requires WebSocket protocol 76 or later. " + + "Try newer version of the server if available."); + } else { + onError("header Sec-WebSocket-Origin is missing"); + } + return false; + } + var resOrigin:String = lowerHeader["sec-websocket-origin"]; + if (resOrigin != origin) { + onError("origin doesn't match: '" + resOrigin + "' != '" + origin + "'"); + return false; + } + if (requestedProtocols.length > 0) { + acceptedProtocol = header["sec-websocket-protocol"]; + if (requestedProtocols.indexOf(acceptedProtocol) < 0) { + onError("protocol doesn't match: '" + + acceptedProtocol + "' not in '" + requestedProtocols.join(",") + "'"); + return false; + } + } + return true; + } + + private function removeBufferBefore(pos:int):void { + if (pos == 0) return; + var nextBuffer:ByteArray = new ByteArray(); + buffer.position = pos; + buffer.readBytes(nextBuffer); + buffer = nextBuffer; + } + + private function initNoiseChars():void { + noiseChars = new Array(); + for (var i:int = 0x21; i <= 0x2f; ++i) { + noiseChars.push(String.fromCharCode(i)); + } + for (var j:int = 0x3a; j <= 0x7a; ++j) { + noiseChars.push(String.fromCharCode(j)); + } + } + + private function generateKey():String { + var spaces:uint = randomInt(1, 12); + var max:uint = uint.MAX_VALUE / spaces; + var number:uint = randomInt(0, max); + var key:String = (number * spaces).toString(); + var noises:int = randomInt(1, 12); + var pos:int; + for (var i:int = 0; i < noises; ++i) { + var char:String = noiseChars[randomInt(0, noiseChars.length - 1)]; + pos = randomInt(0, key.length); + key = key.substr(0, pos) + char + key.substr(pos); + } + for (var j:int = 0; j < spaces; ++j) { + pos = randomInt(1, key.length - 1); + key = key.substr(0, pos) + " " + key.substr(pos); + } + return key; + } + + private function generateKey3():String { + var key3:String = ""; + for (var i:int = 0; i < 8; ++i) { + key3 += String.fromCharCode(randomInt(0, 255)); + } + return key3; + } + + private function getSecurityDigest(key1:String, key2:String, key3:String):String { + var bytes1:String = keyToBytes(key1); + var bytes2:String = keyToBytes(key2); + return MD5.rstr_md5(bytes1 + bytes2 + key3); + } + + private function keyToBytes(key:String):String { + var keyNum:uint = parseInt(key.replace(/[^\d]/g, "")); + var spaces:uint = 0; + for (var i:int = 0; i < key.length; ++i) { + if (key.charAt(i) == " ") ++spaces; + } + var resultNum:uint = keyNum / spaces; + var bytes:String = ""; + for (var j:int = 3; j >= 0; --j) { + bytes += String.fromCharCode((resultNum >> (j * 8)) & 0xff); + } + return bytes; + } + + // Writes byte sequence to socket. + // bytes is String in special format where bytes[i] is i-th byte, not i-th character. + private function writeBytes(bytes:String):void { + for (var i:int = 0; i < bytes.length; ++i) { + socket.writeByte(bytes.charCodeAt(i)); + } + } + + // Reads specified number of bytes from buffer, and returns it as special format String + // where bytes[i] is i-th byte (not i-th character). + private function readBytes(buffer:ByteArray, start:int, numBytes:int):String { + buffer.position = start; + var bytes:String = ""; + for (var i:int = 0; i < numBytes; ++i) { + // & 0xff is to make \x80-\xff positive number. + bytes += String.fromCharCode(buffer.readByte() & 0xff); + } + return bytes; + } + + private function readUTFBytes(buffer:ByteArray, start:int, numBytes:int):String { + buffer.position = start; + var data:String = ""; + for(var i:int = start; i < start + numBytes; ++i) { + // Workaround of a bug of ByteArray#readUTFBytes() that bytes after "\x00" is discarded. + if (buffer[i] == 0x00) { + data += buffer.readUTFBytes(i - buffer.position) + "\x00"; + buffer.position = i + 1; + } + } + data += buffer.readUTFBytes(start + numBytes - buffer.position); + return data; + } + + private function randomInt(min:uint, max:uint):uint { + return min + Math.floor(Math.random() * (Number(max) - min + 1)); + } + + private function fatal(message:String):void { + logger.error(message); + throw message; + } + + // for debug + private function dumpBytes(bytes:String):void { + var output:String = ""; + for (var i:int = 0; i < bytes.length; ++i) { + output += bytes.charCodeAt(i).toString() + ", "; + } + logger.log(output); + } + +} + +} diff --git a/flash-src/net/gimite/websocket/WebSocketEvent.as b/flash-src/net/gimite/websocket/WebSocketEvent.as new file mode 100644 index 0000000..aa17cac --- /dev/null +++ b/flash-src/net/gimite/websocket/WebSocketEvent.as @@ -0,0 +1,33 @@ +package net.gimite.websocket { + +import flash.events.Event; + +/** + * This class represents a generic websocket event. It contains the standard "type" + * parameter as well as a "message" parameter. + */ +public class WebSocketEvent extends Event { + + public static const OPEN:String = "open"; + public static const CLOSE:String = "close"; + public static const MESSAGE:String = "message"; + public static const ERROR:String = "error"; + + public var message:String; + + public function WebSocketEvent( + type:String, message:String = null, bubbles:Boolean = false, cancelable:Boolean = false) { + super(type, bubbles, cancelable); + this.message = message; + } + + public override function clone():Event { + return new WebSocketEvent(this.type, this.message, this.bubbles, this.cancelable); + } + + public override function toString():String { + return "WebSocketEvent: " + this.type + ": " + this.message; + } +} + +} diff --git a/flash-src/net/gimite/websocket/WebSocketMain.as b/flash-src/net/gimite/websocket/WebSocketMain.as new file mode 100644 index 0000000..28cd66d --- /dev/null +++ b/flash-src/net/gimite/websocket/WebSocketMain.as @@ -0,0 +1,150 @@ +// Copyright: Hiroshi Ichikawa +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 + +package net.gimite.websocket { + +import flash.display.Sprite; +import flash.external.ExternalInterface; +import flash.system.Security; +import flash.utils.setTimeout; + +import mx.utils.URLUtil; + +/** + * Provides JavaScript API of WebSocket. + */ +public class WebSocketMain extends Sprite implements IWebSocketLogger{ + + private var callerUrl:String; + private var debug:Boolean = false; + private var manualPolicyFileLoaded:Boolean = false; + private var webSockets:Array = []; + private var eventQueue:Array = []; + + public function WebSocketMain() { + ExternalInterface.addCallback("setCallerUrl", setCallerUrl); + ExternalInterface.addCallback("setDebug", setDebug); + ExternalInterface.addCallback("create", create); + ExternalInterface.addCallback("send", send); + ExternalInterface.addCallback("close", close); + ExternalInterface.addCallback("loadManualPolicyFile", loadManualPolicyFile); + ExternalInterface.addCallback("receiveEvents", receiveEvents); + ExternalInterface.call("WebSocket.__onFlashInitialized"); + } + + public function setCallerUrl(url:String):void { + callerUrl = url; + } + + public function setDebug(val:Boolean):void { + debug = val; + } + + private function loadDefaultPolicyFile(wsUrl:String):void { + var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843"; + log("policy file: " + policyUrl); + Security.loadPolicyFile(policyUrl); + } + + public function loadManualPolicyFile(policyUrl:String):void { + log("policy file: " + policyUrl); + Security.loadPolicyFile(policyUrl); + manualPolicyFileLoaded = true; + } + + public function log(message:String):void { + if (debug) { + ExternalInterface.call("WebSocket.__log", encodeURIComponent("[WebSocket] " + message)); + } + } + + public function error(message:String):void { + ExternalInterface.call("WebSocket.__error", encodeURIComponent("[WebSocket] " + message)); + } + + private function parseEvent(event:WebSocketEvent):Object { + var webSocket:WebSocket = event.target as WebSocket; + var eventObj:Object = {}; + eventObj.type = event.type; + eventObj.webSocketId = webSocket.getId(); + eventObj.readyState = webSocket.getReadyState(); + eventObj.protocol = webSocket.getAcceptedProtocol(); + if (event.message !== null) { + eventObj.message = event.message; + } + return eventObj; + } + + public function create( + webSocketId:int, + url:String, protocols:Array, + proxyHost:String = null, proxyPort:int = 0, + headers:String = null):void { + if (!manualPolicyFileLoaded) { + loadDefaultPolicyFile(url); + } + var newSocket:WebSocket = new WebSocket( + webSocketId, url, protocols, getOrigin(), proxyHost, proxyPort, + getCookie(url), headers, this); + newSocket.addEventListener("open", onSocketEvent); + newSocket.addEventListener("close", onSocketEvent); + newSocket.addEventListener("error", onSocketEvent); + newSocket.addEventListener("message", onSocketEvent); + webSockets[webSocketId] = newSocket; + } + + public function send(webSocketId:int, encData:String):int { + var webSocket:WebSocket = webSockets[webSocketId]; + return webSocket.send(encData); + } + + public function close(webSocketId:int):void { + var webSocket:WebSocket = webSockets[webSocketId]; + webSocket.close(); + } + + public function receiveEvents():Object { + var result:Object = eventQueue; + eventQueue = []; + return result; + } + + private function getOrigin():String { + return (URLUtil.getProtocol(this.callerUrl) + "://" + + URLUtil.getServerNameWithPort(this.callerUrl)).toLowerCase(); + } + + private function getCookie(url:String):String { + if (URLUtil.getServerName(url).toLowerCase() == + URLUtil.getServerName(this.callerUrl).toLowerCase()) { + return ExternalInterface.call("function(){return document.cookie}"); + } else { + return ""; + } + } + + /** + * Socket event handler. + */ + public function onSocketEvent(event:WebSocketEvent):void { + var eventObj:Object = parseEvent(event); + eventQueue.push(eventObj); + processEvents(); + } + + /** + * Process our event queue. If javascript is unresponsive, set + * a timeout and try again. + */ + public function processEvents():void { + if (eventQueue.length == 0) return; + if (!ExternalInterface.call("WebSocket.__onFlashEvent")) { + setTimeout(processEvents, 500); + } + } + +} + +} diff --git a/flash-src/net/gimite/websocket/WebSocketMainInsecure.as b/flash-src/net/gimite/websocket/WebSocketMainInsecure.as new file mode 100644 index 0000000..e845839 --- /dev/null +++ b/flash-src/net/gimite/websocket/WebSocketMainInsecure.as @@ -0,0 +1,19 @@ +// Copyright: Hiroshi Ichikawa +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 + +package net.gimite.websocket { + +import flash.system.Security; + +public class WebSocketMainInsecure extends WebSocketMain { + + public function WebSocketMainInsecure() { + Security.allowDomain("*"); + super(); + } + +} + +} -- cgit v1.2.1 From 734625062581438b019967330028848c1b8b531f Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Sun, 7 Aug 2011 11:00:36 +0900 Subject: Adding Ant build file to build SWF and SWC files. --- flash-src/.gitignore | 1 + flash-src/build.properties.sample | 2 ++ flash-src/build.sh | 2 ++ flash-src/build.xml | 65 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 flash-src/.gitignore create mode 100644 flash-src/build.properties.sample create mode 100644 flash-src/build.xml (limited to 'flash-src') diff --git a/flash-src/.gitignore b/flash-src/.gitignore new file mode 100644 index 0000000..56fb545 --- /dev/null +++ b/flash-src/.gitignore @@ -0,0 +1 @@ +build.properties diff --git a/flash-src/build.properties.sample b/flash-src/build.properties.sample new file mode 100644 index 0000000..6ae8786 --- /dev/null +++ b/flash-src/build.properties.sample @@ -0,0 +1,2 @@ +# Point this to your Flex SDK directory. +FLEX_HOME=/usr/local/share/flex_sdk_4 diff --git a/flash-src/build.sh b/flash-src/build.sh index 4d33853..0fb02a5 100755 --- a/flash-src/build.sh +++ b/flash-src/build.sh @@ -1,5 +1,7 @@ #!/bin/sh +# A script to build WebSocketMain.swf and WebSocketMainInsecure.zip. + # You need Flex 4 SDK: # http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4 diff --git a/flash-src/build.xml b/flash-src/build.xml new file mode 100644 index 0000000..967ff89 --- /dev/null +++ b/flash-src/build.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + true + 10 + + + + + + + + + true + 10 + + + + + + + + + true + + + + + + + + \ No newline at end of file -- cgit v1.2.1 From efec7adc76d8905c5fec001e5eef89e0c85e09b9 Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Sun, 14 Aug 2011 16:56:36 +0900 Subject: Fixing build.xml syntax error. --- flash-src/build.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'flash-src') diff --git a/flash-src/build.xml b/flash-src/build.xml index 967ff89..6ab810a 100644 --- a/flash-src/build.xml +++ b/flash-src/build.xml @@ -1,3 +1,5 @@ + + - -- cgit v1.2.1 From ed0622a890de811eb6d766d5c5a9a62d726f0593 Mon Sep 17 00:00:00 2001 From: Hiroshi Ichikawa Date: Sun, 14 Aug 2011 21:45:09 +0900 Subject: Setting static-link-runtime-shared-libraries to false for swc file to avoid errors, per issue #86 . --- flash-src/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'flash-src') diff --git a/flash-src/build.xml b/flash-src/build.xml index 6ab810a..9f42796 100644 --- a/flash-src/build.xml +++ b/flash-src/build.xml @@ -54,7 +54,7 @@ strict="true" accessible="false" fork="true" - static-link-runtime-shared-libraries="true"> + static-link-runtime-shared-libraries="false"> true -- cgit v1.2.1