The task was to implement a download manager with resume download support. Because of security policy we cant add and change HTTP headers (in this case Range: header) we cand complete this task with standard set of classes.
The decision was to use the SOCKET. Using SOCKET you can send any type of HTTP requests and working with responses.
Here is a some set of source code which is demonstrace how to use SOCKET to implement resume download and how to write received data. Sample class is in attached archive.
_socket.addEventListener( Event.CLOSE, socketClose ); //
=== COMPLETE
_socket.addEventListener( Event.CONNECT, socketConnect );
_socket.addEventListener( IOErrorEvent.IO_ERROR,
uStreamIOErrorHandler );
_socket.addEventListener(
SecurityErrorEvent.SECURITY_ERROR, uStreamSecurityErrorHandler );
_socket.addEventListener( ProgressEvent.SOCKET_DATA,
socketData ); // === PROGRESS
public function downloadFile ( $fileURL:String,
$fileName:String, $pathToSave:String ) : void
{
_isBusy
= true;
// _pathToTarget is path to file on
server
// i.e. /getFile?myfile.jpg
// NOTE it cant be an url or anything,
depends on serve config
_pathToTarget =
"/getFile?" + $fileURL.split( "/getFile?")[1];
_host
= URLUtil.getServerName(
$fileURL );
var fl : File = new File().resolvePath(
$pathToSave + File.separator + $fileName );
// PATH TO YOU DOWNLOAD FILE
var fl : File = new File().resolvePath(
$pathToSave + File.separator + $fileName );
if ( fl.exists )
{
// position from
download will be started
_downloadFromBytes = fl.size;
// indicates is
headers from socket data wah removed or not
_headerRemoved = false;
// creating file
stream to append downloaded data
_fileStream = new
FileStream();
_fileStream.open( fl,
FileMode.APPEND );
// check is socket is
connected already
if (
_socket.connected )
{
sendRequest();
}
else
{
//
connecting to your host and port
//
i.e. host http://www.mydomain.com
//
i.e. post 80
_socket.connect( _host, _port );
}
}
else
{
// if file is not
exist downloading file with bacis download method.
_fileStream = new
FileStream();
_urlRequest = new
URLRequest( $fileURL );
_fileStream.open( fl,
FileMode.WRITE );
_urlStream.load(
_urlRequest );
}
}
private function socketConnect ( event:Event ) : void
{
sendRequest();
}
private function socketClose ( event:Event ) : void
{
_fileStream.close();
}
private function uStreamIOErrorHandler (
event:IOErrorEvent ) : void
{
_fileStream.close();
}
private function uStreamSecurityErrorHandler (
event:SecurityErrorEvent ) : void
{
_fileStream.close();
}
private function sendRequest () : void
{
var request : String = "";
// _pathToTarget is path to file on
server
// i.e. /getFile?myfile.jpg
// NOTE it cant be an url or anything,
depends on serve config
request += "GET " + _pathToTarget + "
HTTP/1.1" + "\n"
// host where file is hosted
// i.e. http://www.mydomain.com
request += "Host: " + _host + "\n";
// bytes from download will be started
request += "Range: bytes=" +
_downloadFromBytes + "- ";
request += "\n\n";
// sending this request
sendMultiByte( request );
}
private function socketData ( event:ProgressEvent ) : void
{
// creating holder for loaded bytes
var _loadedBytes
: ByteArray = new ByteArray();
// length of content to download from
server
var _contentLength
: Number = 0;
// creating holder for bytes to APPEND
to existed file on you HDD
var _bytesToWrite
: ByteArray = new ByteArray();
// if we have some data from socket
if ( _socket.bytesAvailable )
{
// reading bytes
_socket.readBytes(
_loadedBytes, _prevBytesPosition );
// checking if
headers was removed
// if not we must
remove HTTP headers from socket data,
// to avoid writing
this HTTP headers in to file body on HDD
if ( !_headerRemoved
)
{
var loadedChars : String = "";
// making loop to remove all HTTP headers
for ( var i : int = 0; i < _loadedBytes.length; i++ )
{
if ( loadedChars.indexOf( "13101310" ) > -1
|| loadedChars.indexOf( "1313" ) > -1 )
{
_bytesToWrite.writeByte(
_loadedBytes[ i ] );
}
else
{
loadedChars += String(
_loadedBytes[i] );
}
}
var str
: String = _loadedBytes.toString();
var httpStatus : String;
var headerEndIndex : int = str.indexOf(
"Content-Transfer-Encoding: binary\r\n\r\n" );
//
getting content length, it may be useful for progress calculation
var _range
: String = StringUtil.trim( str.substr(
str.indexOf( "Content-Range: bytes " ) + 21, str.indexOf(
"Connection:" ) - ( str.indexOf( "Content-Range: bytes " ) + 21 )
) )
_contentLength = parseInt( _range.substr( _range.lastIndexOf( "/"
) + 1 ) );
//
setting headerRemoved flag to true, to avoid next time checking
for "clear" content
_headerRemoved = true;
}
else
{
_bytesToWrite = _loadedBytes;
}
// writing file data
in to file on HDD
_fileStream.writeBytes( _bytesToWrite );
}
_prevBytesPosition =
_socket.bytesAvailable;
event.bytesTotal = _contentLength;
dispatchEvent( event );
}