/* .Net/C#: Implementing the Http Web Client tool class (C# DIY HttpWebClient) that supports breakpoint continuous transmission and multi-thread download
* Reflector has been rewritten or added several times:
* Download, Upload related methods!
* DownLoad has major changes!
* Added DataReceive, ExceptionOccurrs events!
* For understanding the HTTP protocol for server-side interaction with clients, see:
* Make the custom connection for file downloads support FlashGet's breakpoint continuous transmission multi-threaded link download! JSP/Servlet implementation!
* /playyuer/archive/2004/08/02/
* Make the custom connection for file downloads support FlashGet's breakpoint continuous transmission multi-threaded link download! C#/ Implementation!
* /playyuer/archive/2004/08/02/
*/
//2005-03-14 Revision:
/* .Net/C#: Implement tool classes that support breakpoint continuous transmission and multi-thread download
* Reflector has been rewritten or added several times:
* Download, Upload related methods!
* Added DataReceive, ExceptionOccurrs events
*/
namespace
{
using System;
using ;
using ;
using ;
using ;
using ;
using ;
/// <summary>
/// Record the byte position of the download
/// </summary>
public class DownLoadState
{
private string _FileName;
private string _AttachmentName;
private int _Position;
private string _RequestURL;
private string _ResponseURL;
private int _Length;
private byte[] _Data;
public string FileName
{
get
{
return _FileName;
}
}
public int Position
{
get
{
return _Position;
}
}
public int Length
{
get
{
return _Length;
}
}
public string AttachmentName
{
get
{
return _AttachmentName;
}
}
public string RequestURL
{
get
{
return _RequestURL;
}
}
public string ResponseURL
{
get
{
return _ResponseURL;
}
}
public byte[] Data
{
get
{
return _Data;
}
}
internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, byte[] Data)
{
this._FileName = FileName;
this._RequestURL = RequestURL;
this._ResponseURL = ResponseURL;
this._AttachmentName = AttachmentName;
this._Position = Position;
this._Data = Data;
this._Length = Length;
}
internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, ThreadCallbackHandler tch)
{
this._RequestURL = RequestURL;
this._ResponseURL = ResponseURL;
this._FileName = FileName;
this._AttachmentName = AttachmentName;
this._Position = Position;
this._Length = Length;
this._ThreadCallback = tch;
}
internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length)
{
this._RequestURL = RequestURL;
this._ResponseURL = ResponseURL;
this._FileName = FileName;
this._AttachmentName = AttachmentName;
this._Position = Position;
this._Length = Length;
}
private ThreadCallbackHandler _ThreadCallback;
public HttpWebClient httpWebClient
{
get
{
return this._hwc;
}
set
{
this._hwc = value;
}
}
internal Thread thread
{
get
{
return _thread;
}
set
{
_thread = value;
}
}
private HttpWebClient _hwc;
private Thread _thread;
//
internal void StartDownloadFileChunk()
{
if (this._ThreadCallback != null)
{
this._ThreadCallback(this._RequestURL, this._FileName, this._Position, this._Length);
this._hwc.OnThreadProcess(this._thread);
}
}
}
//The execution method signature of the delegate agent thread is consistent
public delegate void ThreadCallbackHandler(string S, string s, int I, int i);
//Exception handling action
public enum ExceptionActions
{
Throw,
CancelAll,
Ignore,
Retry
}
/// <summary>
/// Class containing Exception event data
/// </summary>
public class ExceptionEventArgs :
{
private _Exception;
private ExceptionActions _ExceptionAction;
private DownLoadState _DownloadState;
public DownLoadState DownloadState
{
get
{
return _DownloadState;
}
}
public Exception Exception
{
get
{
return _Exception;
}
}
public ExceptionActions ExceptionAction
{
get
{
return _ExceptionAction;
}
set
{
_ExceptionAction = value;
}
}
internal ExceptionEventArgs( e, DownLoadState DownloadState)
{
this._Exception = e;
this._DownloadState = DownloadState;
}
}
/// <summary>
/// Class containing Download event data
/// </summary>
public class DownLoadEventArgs :
{
private DownLoadState _DownloadState;
public DownLoadState DownloadState
{
get
{
return _DownloadState;
}
}
public DownLoadEventArgs(DownLoadState DownloadState)
{
this._DownloadState = DownloadState;
}
}
public class ThreadProcessEventArgs :
{
private Thread _thread;
public Thread thread
{
get
{
return this._thread;
}
}
public ThreadProcessEventArgs(Thread thread)
{
this._thread = thread;
}
}
/// <summary>
/// Classes that support breakpoint continuous transmission and multi-thread download
/// </summary>
public class HttpWebClient
{
private static object _SyncLockObject = new object();
public delegate void DataReceiveEventHandler(HttpWebClient Sender, DownLoadEventArgs e);
public event DataReceiveEventHandler DataReceive; //Receive byte data events
public delegate void ExceptionEventHandler(HttpWebClient Sender, ExceptionEventArgs e);
public event ExceptionEventHandler ExceptionOccurrs; //Exception event occurred
public delegate void ThreadProcessEventHandler(HttpWebClient Sender, ThreadProcessEventArgs e);
public event ThreadProcessEventHandler ThreadProcessEnd; //The multi-thread processing event occurs
private int _FileLength; //Total size of downloaded file
public int FileLength
{
get
{
return _FileLength;
}
}
/// <summary>
/// Download the file in chunks
/// </summary>
/// <param name="Address">URL Address</param>
/// <param name="FileName">Path file name saved to local</param>
/// <param name="ChunksCount">Number of blocks, number of threads</param>
public void DownloadFile(string Address, string FileName, int ChunksCount)
{
int p = 0; // position
int s = 0; // chunk size
string a = null;
HttpWebRequest hwrq;
HttpWebResponse hwrp = null;
try
{
hwrq = (HttpWebRequest) ((Address));
hwrp = (HttpWebResponse) ();
long L = ;
= this.m_credentials;
L = ((L == -1) || (L > 0x7ffffffff)) ? ((long) 0x7ffffffff) : L; // The value of this constant is 2,147,483,647; that is, 0x7FFFFFFFFFF
int l = (int) L;
this._FileLength = l;
// Prepare the space locally (it doesn't need to reserve the space first under multi-threading)
// FileStream sw = new FileStream(FileName, , , );
// (new byte[l], 0, l);
// ();
// sw = null;
bool b = (["Accept-Ranges"] != null & ["Accept-Ranges"] == "bytes");
a = ["Content-Disposition"]; //attachment
if (a != null)
{
a = (("filename=") + 9);
}
else
{
a = FileName;
}
int ss = s;
if (b)
{
s = l / ChunksCount;
if (s < 2 * 64 * 1024) //The block size is at least 128 K bytes
{
s = 2 * 64 * 1024;
}
ss = s;
int i = 0;
while (l > s)
{
l -= s;
if (l < s)
{
s += l;
}
if (i++ > 0)
{
DownLoadState x = new DownLoadState(Address, , FileName, a, p, s, new ThreadCallbackHandler());
// Single thread download
// ();
= this;
//Multi-threaded download
Thread t = new Thread(new ThreadStart());
//(t);
();
}
p += s;
}
s = ss;
byte[] buffer = (Address, hwrp, s, FileName);
();
// lock (_SyncLockObject)
// {
// this._Bytes += ;
// }
}
}
catch (Exception e)
{
ExceptionActions ea = ;
if ( != null)
{
DownLoadState x = new DownLoadState(Address, , FileName, a, p, s);
ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
ExceptionOccurrs(this, eea);
ea = ;
}
if (ea == )
{
if (!(e is WebException) && !(e is SecurityException))
{
throw new WebException("net_webclient", e);
}
throw;
}
}
}
internal void OnThreadProcess(Thread t)
{
if (ThreadProcessEnd != null)
{
ThreadProcessEventArgs tpea = new ThreadProcessEventArgs(t);
ThreadProcessEnd(this, tpea);
}
}
/// <summary>
/// Download a file block, and use this method to realize multi-threaded breakpoint continuous transmission by yourself
/// </summary>
/// <param name="Address">URL Address</param>
/// <param name="FileName">Path file name saved to local</param>
/// <param name="Length">Block size</param>
public void DownloadFileChunk(string Address, string FileName, int FromPosition, int Length)
{
HttpWebResponse hwrp = null;
string a = null;
try
{
//this._FileName = FileName;
HttpWebRequest hwrq = (HttpWebRequest) ((Address));
// = this.m_credentials;
(FromPosition);
hwrp = (HttpWebResponse) ();
a = ["Content-Disposition"]; //attachment
if (a != null)
{
a = (("filename=") + 9);
}
else
{
a = FileName;
}
byte[] buffer = (Address, hwrp, Length, FileName);
// lock (_SyncLockObject)
// {
// this._Bytes += ;
// }
}
catch (Exception e)
{
ExceptionActions ea = ;
if ( != null)
{
DownLoadState x = new DownLoadState(Address, , FileName, a, FromPosition, Length);
ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
ExceptionOccurrs(this, eea);
ea = ;
}
if (ea == )
{
if (!(e is WebException) && !(e is SecurityException))
{
throw new WebException("net_webclient", e);
}
throw;
}
}
}
internal byte[] ResponseAsBytes(string RequestURL, WebResponse Response, long Length, string FileName)
{
string a = null; //AttachmentName
int P = 0; //Pointer of the location of the entire file
int num2 = 0;
try
{
a = ["Content-Disposition"]; //attachment
if (a != null)
{
a = (("filename=") + 9);
}
long num1 = Length; //;
bool flag1 = false;
if (num1 == -1)
{
flag1 = true;
num1 = 0x10000; //64k
}
byte[] buffer1 = new byte[(int) num1];
int p = 0; // Position pointer of this block
string s = ["Content-Range"];
if (s != null)
{
s = ("bytes ", "");
s = (0, ("-"));
P = Convert.ToInt32(s);
}
int num3 = 0;
Stream S = ();
do
{
num2 = (buffer1, num3, ((int) num1) - num3);
num3 += num2;
if (flag1 && (num3 == num1))
{
num1 += 0x10000;
byte[] buffer2 = new byte[(int) num1];
(buffer1, 0, buffer2, 0, num3);
buffer1 = buffer2;
}
// lock (_SyncLockObject)
// {
// this._bytes += num2;
// }
if (num2 > 0)
{
if ( != null)
{
byte[] buffer = new byte[num2];
(buffer1, p, buffer, 0, );
DownLoadState dls = new DownLoadState(RequestURL, , FileName, a, P, num2, buffer);
DownLoadEventArgs dlea = new DownLoadEventArgs(dls);
//Trigger event
(dlea);
//(100);
}
p += num2; // Position pointer of this block
P += num2; //Pointer of the location of the entire file
}
else
{
break;
}
}
while (num2 != 0);
();
S = null;
if (flag1)
{
byte[] buffer3 = new byte[num3];
(buffer1, 0, buffer3, 0, num3);
buffer1 = buffer3;
}
return buffer1;
}
catch (Exception e)
{
ExceptionActions ea = ;
if ( != null)
{
DownLoadState x = new DownLoadState(RequestURL, , FileName, a, P, num2);
ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
ExceptionOccurrs(this, eea);
ea = ;
}
if (ea == )
{
if (!(e is WebException) && !(e is SecurityException))
{
throw new WebException("net_webclient", e);
}
throw;
}
return null;
}
}
private void OnDataReceive(DownLoadEventArgs e)
{
//Trigger data arrival event
DataReceive(this, e);
}
public byte[] UploadFile(string address, string fileName)
{
return (address, "POST", fileName, "file");
}
public string UploadFileEx(string address, string method, string fileName, string fieldName)
{
return (UploadFile(address, method, fileName, fieldName));
}
public byte[] UploadFile(string address, string method, string fileName, string fieldName)
{
byte[] buffer4;
FileStream stream1 = null;
try
{
fileName = (fileName);
string text1 = "---------------------" + ("x");
string text2 = "application/octet-stream";
stream1 = new FileStream(fileName, , );
WebRequest request1 = ((address));
= this.m_credentials;
= "multipart/form-data; boundary=" + text1;
= method;
string[] textArray1 = new string[7] {"--", text1, "\r\nContent-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"", (fileName), "\"\r\nContent-Type: ", text2, "\r\n\r\n"};
string text3 = (textArray1);
byte[] buffer1 = Encoding.(text3);
byte[] buffer2 = ("\r\n--" + text1 + "\r\n");
long num1 = 0x7fffffffffffffff;
try
{
num1 = ;
= (num1 + ) + ;
}
catch
{
}
byte[] buffer3 = new byte[(0x2000, (int) num1)];
using (Stream stream2 = ())
{
int num2;
(buffer1, 0, );
do
{
num2 = (buffer3, 0, );
if (num2 != 0)
{
(buffer3, 0, num2);
}
}
while (num2 != 0);
(buffer2, 0, );
}
();
stream1 = null;
WebResponse response1 = ();
buffer4 = (response1);
}
catch (Exception exception1)
{
if (stream1 != null)
{
();
stream1 = null;
}
if (!(exception1 is WebException) && !(exception1 is SecurityException))
{
//throw new WebException(("net_webclient"), exception1);
throw new WebException("net_webclient", exception1);
}
throw;
}
return buffer4;
}
private byte[] ResponseAsBytes(WebResponse response)
{
int num2;
long num1 = ;
bool flag1 = false;
if (num1 == -1)
{
flag1 = true;
num1 = 0x10000;
}
byte[] buffer1 = new byte[(int) num1];
Stream stream1 = ();
int num3 = 0;
do
{
num2 = (buffer1, num3, ((int) num1) - num3);
num3 += num2;
if (flag1 && (num3 == num1))
{
num1 += 0x10000;
byte[] buffer2 = new byte[(int) num1];
(buffer1, 0, buffer2, 0, num3);
buffer1 = buffer2;
}
}
while (num2 != 0);
();
if (flag1)
{
byte[] buffer3 = new byte[num3];
(buffer1, 0, buffer3, 0, num3);
buffer1 = buffer3;
}
return buffer1;
}
private NameValueCollection m_requestParameters;
private Uri m_baseAddress;
private ICredentials m_credentials = ;
public ICredentials Credentials
{
get
{
return this.m_credentials;
}
set
{
this.m_credentials = value;
}
}
public NameValueCollection QueryString
{
get
{
if (this.m_requestParameters == null)
{
this.m_requestParameters = new NameValueCollection();
}
return this.m_requestParameters;
}
set
{
this.m_requestParameters = value;
}
}
public string BaseAddress
{
get
{
if (this.m_baseAddress != null)
{
return this.m_baseAddress.ToString();
}
return ;
}
set
{
if ((value == null) || ( == 0))
{
this.m_baseAddress = null;
}
else
{
try
{
this.m_baseAddress = new Uri(value);
}
catch (Exception exception1)
{
throw new ArgumentException("value", exception1);
}
}
}
}
private Uri GetUri(string path)
{
Uri uri1;
try
{
if (this.m_baseAddress != null)
{
uri1 = new Uri(this.m_baseAddress, path);
}
else
{
uri1 = new Uri(path);
}
if (this.m_requestParameters == null)
{
return uri1;
}
StringBuilder builder1 = new StringBuilder();
string text1 = ;
for (int num1 = 0; num1 < this.m_requestParameters.Count; num1++)
{
(text1 + this.m_requestParameters.AllKeys[num1] + "=" + this.m_requestParameters[num1]);
text1 = "&";
}
UriBuilder builder2 = new UriBuilder(uri1);
= ();
uri1 = ;
}
catch (UriFormatException)
{
uri1 = new Uri((path));
}
return uri1;
}
}
}
/// <summary>
/// Test class
/// </summary>
class AppTest
{
int _k = 0;
int _K = 0;
static void Main()
{
AppTest a = new AppTest();
x = new ();
a._K = 10;
//Subscribe to DataReceive Event
+= new (a.x_DataReceive);
//Subscribe to ExceptionOccurrs Event
+= new (a.x_ExceptionOccurrs);
+= new (a.x_ThreadProcessEnd);
string F = "http://localhost/download/phpMyAdmin-2.6.";
F = "/";
a._F = F;
string f = (("/") + 1);
//(new (new (new ThreadProcessState(F, @"E:\temp\" + f, 10, x).StartThreadProcess))).Start();
(F, @"d:\temp\" + f, a._K);
// (F, @"E:\temp\" + f,15,34556);
();
// string uploadfile = "e:\\test_local.rar";
// string str = ("http://localhost/phpmyadmin/", "POST", uploadfile, "file1");
// (str);
// ();
}
string bs = ""; // Used to record the last digit number
bool b = false;
private int i = 0;
private static object _SyncLockObject = new object();
string _F;
string _f;
private void x_DataReceive( Sender, e)
{
if (!)
{
lock (_SyncLockObject)
{
if (!)
{
(() + " Received data: ");
//( () + " Received data: ");
= true;
}
}
}
string f = ;
if ( != null)
f = (f) + @"\" + ;
this._f = f;
using ( sw = new (f, , , ))
{
= ;
(, 0, );
();
}
string s = ();
lock (_SyncLockObject)
{
+= ;
(bs + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b"+ i + " / " + + " Byte Data " + s);
//(bs + i + " Byte data " + s);
= new string('\b', Digits(i) + 3 + Digits() + );
}
}
int Digits(int n) //The number of places occupied by numbers
{
n = (n);
n = n / 10;
int i = 1;
while (n > 0)
{
n = n / 10;
i++;
}
return i;
}
private void x_ExceptionOccurrs( Sender, e)
{
();
//The re-download occurs when an exception is equivalent to a breakpoint continuous transmission. You can choose the processing method yourself
x = new ();
(this._F, this._f, , );
= ;
}
private void x_ThreadProcessEnd( Sender, e)
{
//if ( == )
if (this._k ++ == this._K - 1)
("\nend");
}
}