diff --git a/lime/net/URLLoader.hx b/lime/net/URLLoader.hx index faf186dd5..432711380 100644 --- a/lime/net/URLLoader.hx +++ b/lime/net/URLLoader.hx @@ -253,7 +253,6 @@ class URLLoader { private function prepareData(data:Dynamic):ByteArray { var uri:ByteArray = new ByteArray(); - if (Std.is (data, ByteArray)) { var data:ByteArray = cast data; @@ -270,14 +269,14 @@ class URLLoader { } - uri.writeUTF(tmp); + uri.writeUTFBytes(tmp); } else { if (data != null) { - uri.writeUTF(Std.string(data)); + uri.writeUTFBytes(Std.string(data)); } @@ -290,8 +289,12 @@ class URLLoader { private function requestUrl (url:String, method:URLRequestMethod, data:Dynamic, requestHeaders:Array):Void { var uri = prepareData(data); + uri.position = 0; __data = ""; + bytesLoaded = 0; + bytesTotal = 0; + CURLEasy.reset(__curl); CURLEasy.setopt(__curl, URL, url); @@ -302,16 +305,21 @@ class URLLoader { CURLEasy.setopt(__curl, HTTPGET, true); case POST: CURLEasy.setopt(__curl, POST, true); - CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, _, _, uri)); + 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, 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, READFUNCTION, readFunction.bind(_, uri)); + CURLEasy.setopt(__curl, INFILESIZE, uri.length); } var headers:Array = []; + headers.push("Expect: "); // removes the default cURL value for (requestHeader in requestHeaders) { headers.push('${requestHeader.name}: ${requestHeader.value}'); @@ -320,11 +328,14 @@ class URLLoader { 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, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20120101 Firefox/29.0"); + CURLEasy.setopt(__curl, USERAGENT, "libcurl-agent/1.0"); var result = CURLEasy.perform(__curl); @@ -339,32 +350,40 @@ class URLLoader { } */ this.data = __data; - onComplete.dispatch (this); onHTTPStatus.dispatch (this, Std.parseInt(responseCode)); + onComplete.dispatch (this); } else { onIOError.dispatch (this, "Problem with curl: " + result); } } - private function writeFunction (output:String, chunks:Int, length:Int):Int { + private function writeFunction (output:String, size:Int, nmemb:Int):Int { __data += output; - return chunks * length; + return size * nmemb; } - private function readFunction (output:String, chunks:Int, length:Int, input:ByteArray):Int { + private function headerFunction (output:String, size:Int, nmemb:Int):Int { - var chunk = chunks * length; - var inputTotal = input.length - input.position; - if(inputTotal < chunk) { - output += input.readUTFBytes(inputTotal); - return 0; + // 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); } - output += input.readUTFBytes(chunk); - return chunk; + 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 diff --git a/project/src/net/curl/CURLBindings.cpp b/project/src/net/curl/CURLBindings.cpp index aed4a510d..ccee50e94 100644 --- a/project/src/net/curl/CURLBindings.cpp +++ b/project/src/net/curl/CURLBindings.cpp @@ -1,5 +1,6 @@ #include #include +#include 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; }