views:

945

answers:

2

In Adobe AIR 1.5, I'm using URLLoader to upload a video in 1 MB chunks. It uploads 1 MB, waits for the Event.COMPLETE event, and then uploads the next chunk. The server-side code knows how to construct the video from these chunks.

Usually, it works fine. However, sometimes it just stops without throwing any errors or dispatching any events. This is an example of what is shown in a log that I create:

Uploading chunk of size: 1000000
HTTP_RESPONSE_STATUS dispatched: 200
HTTP_STATUS dispatched: 200
Completed chunk 1 of 108

Uploading chunk of size: 1000000
HTTP_RESPONSE_STATUS ...

etc...

Most of the time, it completes all of the chunks fine. However, sometimes, it just fails in the middle:

Completed chunk 2 of 108
Uploading chunk of size: 1000000

... and nothing else, and no network activity.

Through debugging, I can tell that it does successfully call urlLoader.load(). When it fails, it just seems to stall, calling load(), and then calling the UIComponent's callLaterDispatcher() and then nothing.

Does anyone have any idea why this could be happening? I'm setting up my URLLoader like this:

urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, chunkComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
urlLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, responseStatusHandler);
urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, statusHandler);
urlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler);

And I'm re-using it for each chunk. No events get called when it doesn't succeed, and urlLoader.load() doesn't throw any exceptions. When it succeeds, HTTP_RESPONSE_STATUS, HTTP_STATUS, and PROGRESS events are dispatched.

Thanks!

Edit: One thing that might be helpful is that, we have the same upload functionality implemented in .NET. In .NET, the request.GetResponse() method sometimes throws an exception, complaining that the connection was closed unexpectedly. We catch the exception if this happens, and try that chunk again, until it succeeds. I'm looking to implement something similar here, but there are no exceptions being thrown or error events being dispatched.

More detailed code example below. The URLLoader is setup as described above. The readAgain variable just makes it skip reading a new set of bytes in the file stream (ie: it tries to send the old one again) ... however, it never catches any exceptions, because none are ever thrown.

private function uploadSegment():void
{
    .... prepare byte array, setup url ...

    // Create a URL request
    var urlRequest:URLRequest = new URLRequest();
    urlRequest.url = _url + "?" + paramStr; 
    urlRequest.method = URLRequestMethod.POST;
    urlRequest.data = byteArray;
    urlRequest.useCache = false;
    urlRequest.requestHeaders.push(new URLRequestHeader('Cache-Control', 'no-cache'));

    try
    {
        urlLoader.load(urlRequest);
    }
    catch (e:Error)
    {
        Logger.error("Failed to upload chunk. Caught exception. Trying again.");
        readAgain = true;
        uploadSegment();
        return;
    }

    readAgain = false;
}
+1  A: 

Have you tried signing up for 'Event.OPEN' to see if the connection is opening correctly? If you're doing this per chunk - perhaps that event or lack thereof would help?

[Edit]

Can you also try setting useCache to false on your URLRequest?

[Edit]

I assume you're urlLoader is globally referenced... If not, while you're waiting for async behavior, something evil like GC might hurt you ... But - skipping that, if you call 'bytesTotal' while you're waiting for something to happen - does it always return zero?

[More]

Also - check the URL in the cases where NOTHING happens - because online I've found some mention that if the server is unreachable there are no events fired (though there is some argument around that)...

Gabriel
Good idea... I just tried, and yes, the Event.OPEN event does get dispatched, but after that it just hangs.
Rhys Causey
Hmmmm... So Normally, you're getting 'Open' then 'Progress' / 'Status' ... but when it fails - you're just getting 'Open' and then nothing? And the call to 'load' give you no exception?
Gabriel
Yes, exactly... normally, I get OPEN, PROGRESS / STATUS, COMPLETE. When it fails, I just get OPEN. It fails on different chunks seemingly randomly. I'm thinking that the connection opens, but gets interrupted or closed after that, and unfortunately, nothing is being dispatched or thrown to catch the problem...
Rhys Causey
Can you try to set 'useCache' to false on the URLRequest?
Gabriel
Also, could be useful to see how you're setting the request / loader... Not sure if that's feasible (to post additional code).
Gabriel
Of particular interest would be the try...catch - and the setup the request / loader.
Gabriel
Added a little bit of additional code, tried useCache = true, and no difference
Rhys Causey
Sorry, I meant useCache = false :)
Rhys Causey