From 226e5e787a1dc5372baff0348a00db09a9c810cd Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 18 Jun 2014 13:45:17 -0700 Subject: [PATCH] Add URLLoader for HTML5, other platforms TBD --- lime/net/NetConnection.hx | 0 lime/net/NetConnectionManager.hx | 0 lime/net/URLLoader.hx | 303 ++++++++++++++++++++++++++++++ lime/net/URLLoaderDataFormat.hx | 15 ++ lime/net/URLRequest.hx | 57 ++++++ lime/net/URLRequestHeader.hx | 24 +++ lime/net/URLRequestMethod.hx | 18 ++ lime/net/URLVariables.hx | 70 +++++++ templates/haxe/ApplicationMain.hx | 4 +- 9 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 lime/net/NetConnection.hx create mode 100644 lime/net/NetConnectionManager.hx create mode 100644 lime/net/URLLoader.hx create mode 100644 lime/net/URLLoaderDataFormat.hx create mode 100644 lime/net/URLRequest.hx create mode 100644 lime/net/URLRequestHeader.hx create mode 100644 lime/net/URLRequestMethod.hx create mode 100644 lime/net/URLVariables.hx diff --git a/lime/net/NetConnection.hx b/lime/net/NetConnection.hx new file mode 100644 index 000000000..e69de29bb diff --git a/lime/net/NetConnectionManager.hx b/lime/net/NetConnectionManager.hx new file mode 100644 index 000000000..e69de29bb diff --git a/lime/net/URLLoader.hx b/lime/net/URLLoader.hx new file mode 100644 index 000000000..b47cf3eac --- /dev/null +++ b/lime/net/URLLoader.hx @@ -0,0 +1,303 @@ +package lime.net; + + +import lime.app.Event; +import lime.utils.ByteArray; + +#if js +import js.html.EventTarget; +import js.html.XMLHttpRequest; +import js.Browser; +import js.Lib; +#end + + +class URLLoader { + + + public var bytesLoaded:Int; + public var bytesTotal:Int; + public var data:Dynamic; + public var dataFormat (default, set):URLLoaderDataFormat; + public var onComplete = new EventVoid> (); + public var onHTTPStatus = new EventInt->Void> (); + public var onIOError = new EventString->Void> (); + public var onOpen = new EventVoid> (); + public var onProgress = new EventInt->Int->Void> (); + public var onSecurityError = new EventString->Void> (); + + + public function new (request:URLRequest = null) { + + bytesLoaded = 0; + bytesTotal = 0; + dataFormat = URLLoaderDataFormat.TEXT; + + if (request != null) { + + load (request); + + } + + } + + + public function close ():Void { + + + + } + + + private dynamic function getData ():Dynamic { + + return null; + + } + + + public function load (request:URLRequest):Void { + + #if js + requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ()); + #end + + } + + + #if js + private function registerEvents (subject:EventTarget):Void { + + var self = this; + if (untyped __js__("typeof XMLHttpRequestProgressEvent") != __js__('"undefined"')) { + + subject.addEventListener ("progress", __onProgress, false); + + } + + untyped subject.onreadystatechange = function () { + + if (subject.readyState != 4) return; + + var s = try subject.status catch (e:Dynamic) null; + + if (s == untyped __js__("undefined")) { + + s = null; + + } + + if (s != null) { + + self.onHTTPStatus.dispatch (this, s); + + } + + //js.Lib.alert (s); + + if (s != null && s >= 200 && s < 400) { + + self.__onData (subject.response); + + } else { + + if (s == null) { + + self.onIOError.dispatch (this, "Failed to connect or resolve host"); + + } else if (s == 12029) { + + self.onIOError.dispatch (this, "Failed to connect to host"); + + } else if (s == 12007) { + + self.onIOError.dispatch (this, "Unknown host"); + + } else if (s == 0) { + + self.onIOError.dispatch (this, "Unable to make request (may be blocked due to cross-domain permissions)"); + self.onSecurityError.dispatch (this, "Unable to make request (may be blocked due to cross-domain permissions)"); + + } else { + + self.onIOError.dispatch (this, "Http Error #" + subject.status); + + } + + } + + }; + + } + + + private function requestUrl (url:String, method:String, data:Dynamic, requestHeaders:Array):Void { + + var xmlHttpRequest:XMLHttpRequest = untyped __new__("XMLHttpRequest"); + registerEvents (cast xmlHttpRequest); + var uri:Dynamic = ""; + + if (Std.is (data, ByteArray)) { + + var data:ByteArray = cast data; + + switch (dataFormat) { + + //case BINARY: uri = data.__getBuffer (); + default: uri = data.readUTFBytes (data.length); + + } + + } else if (Std.is (data, URLVariables)) { + + var data:URLVariables = cast data; + + for (p in Reflect.fields (data)) { + + if (uri.length != 0) uri += "&"; + uri += StringTools.urlEncode (p) + "=" + StringTools.urlEncode (Reflect.field (data, p)); + + } + + } else { + + if (data != null) { + + uri = data.toString (); + + } + + } + + try { + + if (method == "GET" && uri != null && uri != "") { + + var question = url.split ("?").length <= 1; + xmlHttpRequest.open (method, url + (if (question) "?" else "&") + uri, true); + uri = ""; + + } else { + + //js.Lib.alert ("open: " + method + ", " + url + ", true"); + xmlHttpRequest.open (method, url, true); + + } + + } catch (e:Dynamic) { + + onIOError.dispatch (this, e.toString ()); + return; + + } + + //js.Lib.alert ("dataFormat: " + dataFormat); + + switch (dataFormat) { + + case BINARY: untyped xmlHttpRequest.responseType = 'arraybuffer'; + default: + + } + + for (header in requestHeaders) { + + //js.Lib.alert ("setRequestHeader: " + header.name + ", " + header.value); + xmlHttpRequest.setRequestHeader (header.name, header.value); + + } + + //js.Lib.alert ("uri: " + uri); + + xmlHttpRequest.send (uri); + onOpen.dispatch (this); + + getData = function () { + + if (xmlHttpRequest.response != null) { + + return xmlHttpRequest.response; + + } else { + + return xmlHttpRequest.responseText; + + } + + }; + + } + #end + + + + + // Event Handlers + + + + + private function __onData (_):Void { + + #if js + var content:Dynamic = getData (); + + switch (dataFormat) { + + //case BINARY: this.data = ByteArray.__ofBuffer (content); + default: this.data = Std.string (content); + + } + #end + + onComplete.dispatch (this); + + } + + + private function __onProgress (event:XMLHttpRequestProgressEvent):Void { + + bytesLoaded = event.loaded; + bytesTotal = event.total; + + onProgress.dispatch (this, bytesLoaded, bytesTotal); + + } + + + + + + // Get & Set Methods + + + + + private function set_dataFormat (inputVal:URLLoaderDataFormat):URLLoaderDataFormat { + + #if js + // prevent inadvertently using typed arrays when they are unsupported + // @todo move these sorts of tests somewhere common in the vein of Modernizr + + if (inputVal == URLLoaderDataFormat.BINARY && !Reflect.hasField (Browser.window, "ArrayBuffer")) { + + dataFormat = URLLoaderDataFormat.TEXT; + + } else { + + dataFormat = inputVal; + + } + + return dataFormat; + #else + return inputVal; + #end + + } + + +} + + +typedef XMLHttpRequestProgressEvent = Dynamic; \ No newline at end of file diff --git a/lime/net/URLLoaderDataFormat.hx b/lime/net/URLLoaderDataFormat.hx new file mode 100644 index 000000000..0bb6026be --- /dev/null +++ b/lime/net/URLLoaderDataFormat.hx @@ -0,0 +1,15 @@ +package lime.net; #if !flash + + +enum URLLoaderDataFormat { + + BINARY; + TEXT; + VARIABLES; + +} + + +#else +typedef URLLoaderDataFormat = flash.net.URLLoaderDataFormat; +#end \ No newline at end of file diff --git a/lime/net/URLRequest.hx b/lime/net/URLRequest.hx new file mode 100644 index 000000000..91cbe669d --- /dev/null +++ b/lime/net/URLRequest.hx @@ -0,0 +1,57 @@ +package lime.net; #if !flash + + +import lime.utils.ByteArray; + + +class URLRequest { + + + public var contentType:String; + public var data:Dynamic; + public var method:String; + public var requestHeaders:Array; + public var url:String; + public var userAgent:String; + + + public function new (inURL:String = null) { + + if (inURL != null) { + + url = inURL; + + } + + requestHeaders = []; + method = URLRequestMethod.GET; + contentType = null; // "application/x-www-form-urlencoded"; + + } + + + public function formatRequestHeaders ():Array { + + var res = requestHeaders; + if (res == null) res = []; + + if (method == URLRequestMethod.GET || data == null) return res; + + if (Std.is (data, String) || Std.is (data, ByteArray)) { + + res = res.copy (); + res.push (new URLRequestHeader ("Content-Type", contentType != null ? contentType : "application/x-www-form-urlencoded")); + + } + + return res; + + } + + +} + + +#else +typedef URLRequest = flash.net.URLRequest; +#end \ No newline at end of file diff --git a/lime/net/URLRequestHeader.hx b/lime/net/URLRequestHeader.hx new file mode 100644 index 000000000..f86795ed9 --- /dev/null +++ b/lime/net/URLRequestHeader.hx @@ -0,0 +1,24 @@ +package lime.net; #if !flash + + +class URLRequestHeader { + + + public var name : String; + public var value : String; + + + public function new (name:String = "", value:String = "") { + + this.name = name; + this.value = value; + + } + + +} + + +#else +typedef URLRequestHeader = flash.net.URLRequestHeader; +#end \ No newline at end of file diff --git a/lime/net/URLRequestMethod.hx b/lime/net/URLRequestMethod.hx new file mode 100644 index 000000000..8af4ec1a5 --- /dev/null +++ b/lime/net/URLRequestMethod.hx @@ -0,0 +1,18 @@ +package lime.net; #if !flash + + +class URLRequestMethod { + + public static var DELETE:String = "DELETE"; + public static var GET:String = "GET"; + public static var HEAD:String = "HEAD"; + public static var OPTIONS:String = "OPTIONS"; + public static var POST:String = "POST"; + public static var PUT:String = "PUT"; + +} + + +#else +typedef URLRequestMethod = flash.net.URLRequestMethod; +#end \ No newline at end of file diff --git a/lime/net/URLVariables.hx b/lime/net/URLVariables.hx new file mode 100644 index 000000000..42d76e4ec --- /dev/null +++ b/lime/net/URLVariables.hx @@ -0,0 +1,70 @@ +package lime.net; #if !flash + + +class URLVariables implements Dynamic { + + + public function new (inEncoded:String = null) { + + if (inEncoded != null) { + + decode (inEncoded); + + } + + } + + + public function decode (inVars:String):Void { + + var fields = Reflect.fields (this); + + for (f in fields) { + + Reflect.deleteField (this, f); + + } + + var fields = inVars.split (";").join ("&").split ("&"); + + for (f in fields) { + + var eq = f.indexOf ("="); + + if (eq > 0) { + + Reflect.setField (this, StringTools.urlDecode (f.substr(0, eq)), StringTools.urlDecode (f.substr(eq + 1))); + + } else if (eq != 0) { + + Reflect.setField (this, StringTools.urlDecode (f), ""); + + } + + } + + } + + + public function toString ():String { + + var result = new Array (); + var fields = Reflect.fields (this); + + for (f in fields) { + + result.push (StringTools.urlEncode (f) + "=" + StringTools.urlEncode (Reflect.field (this, f))); + + } + + return result.join ("&"); + + } + + +} + + +#else +typedef URLVariables = flash.net.URLVariables; +#end \ No newline at end of file diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index a028a0108..1c61db807 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -38,8 +38,10 @@ class ApplicationMain { } - #if (js && munit) + #if js + #if munit embed (null, ::WIN_WIDTH::, ::WIN_HEIGHT::, "::WIN_FLASHBACKGROUND::"); + #end #else create (); #end