Merge branch 'urlloader_curl' into all

This commit is contained in:
MrCdK
2014-08-27 04:38:47 +02:00
4 changed files with 222 additions and 12 deletions

View File

@@ -11,6 +11,14 @@ import js.Browser;
import js.Lib;
#end
#if lime_curl
import lime.net.curl.CURL;
import lime.net.curl.CURLEasy;
import lime.net.curl.CURLCode;
import lime.net.curl.CURLInfo;
import lime.net.curl.CURLOption;
#end
class URLLoader {
@@ -26,13 +34,22 @@ class URLLoader {
public var onProgress = new Event<URLLoader->Int->Int->Void> ();
public var onSecurityError = new Event<URLLoader->String->Void> ();
#if lime_curl
private var __curl:CURL;
private var __data:String;
#end
public function new (request:URLRequest = null) {
bytesLoaded = 0;
bytesTotal = 0;
dataFormat = URLLoaderDataFormat.TEXT;
#if lime_curl
__data = "";
__curl = CURLEasy.init();
#end
if (request != null) {
load (request);
@@ -44,7 +61,9 @@ class URLLoader {
public function close ():Void {
#if lime_curl
CURLEasy.cleanup(__curl);
#end
}
@@ -60,6 +79,8 @@ class URLLoader {
#if js
requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ());
#elseif lime_curl
requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ());
#end
}
@@ -227,6 +248,144 @@ class URLLoader {
};
}
#elseif lime_curl
private function prepareData(data:Dynamic):ByteArray {
var uri:ByteArray = new ByteArray();
if (Std.is (data, ByteArray)) {
var data:ByteArray = cast data;
uri = data;
} else if (Std.is (data, URLVariables)) {
var data:URLVariables = cast data;
var tmp:String = "";
for (p in Reflect.fields (data)) {
if (tmp.length != 0) tmp += "&";
tmp += StringTools.urlEncode (p) + "=" + StringTools.urlEncode (Reflect.field (data, p));
}
uri.writeUTFBytes(tmp);
} else {
if (data != null) {
uri.writeUTFBytes(Std.string(data));
}
}
return uri;
}
private function requestUrl (url:String, method:URLRequestMethod, data:Dynamic, requestHeaders:Array<URLRequestHeader>):Void {
var uri = prepareData(data);
uri.position = 0;
__data = "";
bytesLoaded = 0;
bytesTotal = 0;
CURLEasy.reset(__curl);
CURLEasy.setopt(__curl, URL, url);
switch(method) {
case HEAD:
CURLEasy.setopt(__curl, NOBODY, true);
case GET:
CURLEasy.setopt(__curl, HTTPGET, true);
case POST:
CURLEasy.setopt(__curl, POST, true);
CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri));
CURLEasy.setopt(__curl, POSTFIELDSIZE, uri.length);
CURLEasy.setopt(__curl, INFILESIZE, uri.length);
case PUT:
CURLEasy.setopt(__curl, UPLOAD, true);
CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri));
CURLEasy.setopt(__curl, INFILESIZE, uri.length);
case _:
CURLEasy.setopt(__curl, CUSTOMREQUEST, cast method);
CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri));
CURLEasy.setopt(__curl, INFILESIZE, uri.length);
}
var headers:Array<String> = [];
headers.push("Expect: "); // removes the default cURL value
for (requestHeader in requestHeaders) {
headers.push('${requestHeader.name}: ${requestHeader.value}');
}
CURLEasy.setopt(__curl, HTTPHEADER, headers);
CURLEasy.setopt(__curl, PROGRESSFUNCTION, progressFunction);
CURLEasy.setopt(__curl, WRITEFUNCTION, writeFunction);
CURLEasy.setopt(__curl, HEADERFUNCTION, headerFunction);
CURLEasy.setopt(__curl, SSL_VERIFYPEER, false);
CURLEasy.setopt(__curl, SSL_VERIFYHOST, false);
CURLEasy.setopt(__curl, USERAGENT, "libcurl-agent/1.0");
var result = CURLEasy.perform(__curl);
var responseCode = CURLEasy.getinfo(__curl, RESPONSE_CODE);
if (result == CURLCode.OK) {
/*
switch(dataFormat) {
case BINARY: this.data = __data;
default: this.data = __data.asString();
}
*/
this.data = __data;
onHTTPStatus.dispatch (this, Std.parseInt(responseCode));
onComplete.dispatch (this);
} else {
onIOError.dispatch (this, "Problem with curl: " + result);
}
}
private function writeFunction (output:String, size:Int, nmemb:Int):Int {
__data += output;
return size * nmemb;
}
private function headerFunction (output:String, size:Int, nmemb:Int):Int {
// TODO
return size * nmemb;
}
private function progressFunction (dltotal:Float, dlnow:Float, uptotal:Float, upnow:Float):Int {
if(upnow>bytesLoaded || dlnow>bytesTotal) {
if(upnow > bytesLoaded) bytesLoaded = Std.int(upnow);
if(dlnow > bytesTotal) bytesTotal = Std.int(dlnow);
onProgress.dispatch(this, bytesLoaded, bytesTotal);
}
return 0;
}
private function readFunction(max:Int, input:ByteArray):String {
return input == null ? "" : input.readUTFBytes(Std.int(Math.min(max, input.length - input.position)));
}
#end

View File

@@ -24,7 +24,7 @@
<set name="OUTPUT_DIR" value="../ndll" unless="OUTPUT_DIR" />
<set name="NATIVE_TOOLKIT_PATH" value="lib" unless="NATIVE_TOOLKIT_PATH" />
<set name="LIBCURL_SSL" value="1" />
<set name="NATIVE_TOOLKIT_CURL_SSL" value="1" />
<files id="lime">

View File

@@ -1,5 +1,6 @@
#include <curl/curl.h>
#include <hx/CFFI.h>
#include <string.h>
namespace lime {
@@ -157,7 +158,7 @@ namespace lime {
}
static size_t rw_callback (void *ptr, size_t size, size_t nmemb, void *userp) {
static size_t write_callback (void *ptr, size_t size, size_t nmemb, void *userp) {
AutoGCRoot* callback = (AutoGCRoot*)userp;
@@ -171,6 +172,37 @@ namespace lime {
return val_int (val_call3 (callback->get (), str, alloc_int (size), alloc_int (nmemb)));
}
static size_t read_callback (void *buffer, size_t size, size_t nmemb, void *userp) {
AutoGCRoot* callback = (AutoGCRoot*)userp;
size_t bytes = size * nmemb;
const char *input = val_string (val_call1 (callback->get (), alloc_int (bytes)));
size_t length = strlen(input);
if(length <= bytes) bytes = length;
memcpy(buffer, input, bytes);
return bytes;
}
static size_t progress_callback (void *userp, double dltotal, double dlnow, double ultotal, double ulnow) {
AutoGCRoot* callback = (AutoGCRoot*)userp;
value vals[] = {
alloc_float(dltotal),
alloc_float(dlnow),
alloc_float(ultotal),
alloc_float(ulnow),
};
return val_int (val_callN (callback->get (), vals, 4));
}
value lime_curl_easy_setopt (value handle, value option, value parameter) {
@@ -366,12 +398,8 @@ namespace lime {
case CURLOPT_OPENSOCKETDATA:
case CURLOPT_CLOSESOCKETFUNCTION:
case CURLOPT_CLOSESOCKETDATA:
case CURLOPT_PROGRESSFUNCTION:
case CURLOPT_PROGRESSDATA:
case CURLOPT_XFERINFOFUNCTION:
//case CURLOPT_XFERINFODATA:
case CURLOPT_HEADERFUNCTION:
case CURLOPT_HEADERDATA:
case CURLOPT_DEBUGFUNCTION:
case CURLOPT_DEBUGDATA:
case CURLOPT_SSL_CTX_FUNCTION:
@@ -406,13 +434,36 @@ namespace lime {
//case CURLOPT_READDATA:
//case CURLOPT_WRITEDATA:
//case CURLOPT_HEADERDATA:
//case CURLOPT_PROGRESSDATA:
case CURLOPT_READFUNCTION:
{
AutoGCRoot* callback = new AutoGCRoot (parameter);
code = curl_easy_setopt (curl, type, read_callback);
curl_easy_setopt (curl, CURLOPT_READDATA, callback);
break;
}
case CURLOPT_WRITEFUNCTION:
{
AutoGCRoot* callback = new AutoGCRoot (parameter);
code = curl_easy_setopt (curl, type, rw_callback);
curl_easy_setopt (curl, type == CURLOPT_READFUNCTION ? CURLOPT_READDATA : CURLOPT_WRITEDATA, callback);
code = curl_easy_setopt (curl, type, write_callback);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, callback);
break;
}
case CURLOPT_HEADERFUNCTION:
{
AutoGCRoot* callback = new AutoGCRoot (parameter);
code = curl_easy_setopt (curl, type, write_callback);
curl_easy_setopt (curl, CURLOPT_HEADERDATA, callback);
break;
}
case CURLOPT_PROGRESSFUNCTION:
{
AutoGCRoot* callback = new AutoGCRoot (parameter);
code = curl_easy_setopt (curl, type, progress_callback);
curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, callback);
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, false);
break;
}