using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Threading;
using System.IO;
namespace Updater
{
/// <summary>
/// This class enable you to perform request that can be
/// interrupted after a specified number of milliseconds,
/// even in case of packet loss (which usually prevents
/// the request to terminate).
/// It's especially useful for unstable connections, like
/// GPRS connections.
/// If a request cannot be completed, the Request or
/// RequestBinary method returns null.
/// </summary>
public class TimedWebRequest
{
#region Constants
public const int DefaultBufferSize = 1024;
public const int DefaultMaxSize = 1048576;
#endregion
#region Private members
private int m_BufferSize = DefaultBufferSize;
private int m_MaxSize = DefaultMaxSize;
private object locker = new object();
#region Private properties. Used to perform locking
private byte[] bRetval = null;
private byte[] ByteRetval
{
get
{
lock (locker)
return bRetval;
}
set
{
lock (locker)
bRetval = value;
}
}
private string sAddress = null;
private string Address
{
get
{
lock (locker)
return sAddress;
}
set
{
lock (locker)
sAddress = value;
}
}
private int iCur = 0;
private int Current
{
get
{
lock (locker)
return iCur;
}
set
{
lock (locker)
iCur = value;
}
}
private int iTot = 0;
private int Total
{
get
{
lock (locker)
return iTot;
}
set
{
lock (locker)
iTot = value;
}
}
private bool bComplete = true;
private bool IsComplete()
{
lock (locker)
return bComplete;
}
#endregion
private void SetComplete(bool bValue)
{
lock (locker)
bComplete = bValue;
}
private void threadFuncB()
{
// Signal that the request is not complete.
SetComplete(false);
// Performs the request.
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(Address);
myRequest.KeepAlive = false;
try
{
// Read the response.
byte[] buffer = new byte[BufferSize];
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
Stream stream = myResponse.GetResponseStream();
long len = myResponse.ContentLength;
if (len <= 0)
len = MaxSize;
long total = 0;
List<byte> data = new List<byte>(65536);
Current = 0;
Total = (int)len;
while (total < len)
{
System.Threading.Thread.Sleep(20);
int rbytes = stream.Read(buffer, 0, BufferSize);
for (int i = 0; i < rbytes; i++)
data.Add(buffer[i]);
total += rbytes;
Current = (int)total;
Total = (int)len;
if (total > MaxSize && rbytes == 0)
break;
}
ByteRetval = data.ToArray();
}
catch
{
try
{
myRequest.Abort();
}
catch
{
}
ByteRetval = null;
}
finally
{
SetComplete(true);
}
}
#endregion
#region public members
public delegate void DgtDownloadProgress(int iCurrent, int iTotal);
/// <summary>
/// You can use this event to keep track of the download progress.
/// </summary>
public event DgtDownloadProgress DownloadProgress;
/// <summary>
/// Specify the buffer size for downloading.
/// Smaller buffer means more frequent progress updates.
/// Greater buffer means better download speed on fast connections.
/// </summary>
public int BufferSize
{
get { lock (locker) return m_BufferSize; }
set { lock (locker) m_BufferSize = value; }
}
/// <summary>
/// Specify the Maximum download size if the HTML header itself does not specify the content-length.
/// </summary>
public int MaxSize
{
get { lock (locker) return m_MaxSize; }
set { lock (locker) m_MaxSize = value; }
}
/// <summary>
/// Request a text file from the specified url.
/// </summary>
/// <param name="sURL">The url from which download data.</param>
/// <param name="timeout">The number of milliseconds before the request must be terminated.</param>
/// <returns>A string containing the page data.</returns>
public string Request(string sURL, int timeout)
{
byte[] result = RequestBinary(sURL, timeout);
if (result != null)
{
MemoryStream ms = new MemoryStream(result);
StreamReader rdr = new StreamReader(ms);
return rdr.ReadToEnd();
}
else
{
return null;
}
}
/// <summary>
/// Request binary data from the specified url.
/// </summary>
/// <param name="sURL">The url from which download data.</param>
/// <param name="timeout">The number of milliseconds before the request must be terminated.</param>
/// <returns>A byte array containing the requested data.</returns>
public byte[] RequestBinary(string sURL, int timeout)
{
int sleeptime = 150;
ByteRetval = null;
Address = sURL;
Thread th = new Thread(new ThreadStart(threadFuncB));
// Wait until previous request completes
while (IsComplete() == false)
System.Threading.Thread.Sleep(150);
SetComplete(false);
// Start reading thread
th.Start();
int time = 0;
// Read until completion or until timeout is reached.
while (IsComplete() == false)
{
th.Join(sleeptime);
lock (locker)
{
if (Current > Total)
Current = Total;
if (DownloadProgress != null)
DownloadProgress(Current, Total);
}
time += sleeptime;
if (time > timeout)
th.Abort();
}
th = null;
return ByteRetval;
}
/// <summary>
/// Request a text file from the specified url, using a timeout of 90 seconds.
/// </summary>
/// <param name="sURL">The url from which download data.</param>
/// <returns>A string containing the page data.</returns>
public string Request(string sURL)
{
return Request(sURL, 90000);
}
/// <summary>
/// Request binary data from the specified url using a timeout of 90 seconds.
/// </summary>
/// <param name="sURL">The url from which download data.</param>
/// <returns>A byte array containing the requested data.</returns>
public byte[] RequestBinary(string sURL)
{
return RequestBinary(sURL, 90000);
}
#endregion
}
}