예제 #1
0
        public static Action DownloadAsync(string url, string auth, string referer, string connectionGroupName, DateTime?cacheLastModifiedTime, Action <HttpWebResponse> onResponse, Action <byte[], int> onDownloadChunk, Action onComplete, Action <Exception> onException)
        {
            const int       readBufferSize   = 8192;
            const int       requestTimeoutMS = 60000;
            const int       readTimeoutMS    = 60000;
            object          sync             = new object();
            bool            aborting         = false;
            HttpWebRequest  request          = null;
            HttpWebResponse response         = null;
            Stream          responseStream   = null;
            Action          cleanup          = () => {
                if (request != null)
                {
                    request.Abort();
                    request = null;
                }
                if (responseStream != null)
                {
                    try { responseStream.Close(); }
                    catch { }
                    responseStream = null;
                }
                if (response != null)
                {
                    try { response.Close(); }
                    catch { }
                    response = null;
                }
            };
            Action <Exception> abortDownloadInternal = (ex) => {
                lock (sync) {
                    if (aborting)
                    {
                        return;
                    }
                    aborting = true;
                    cleanup();
                    onException(ex);
                }
            };
            Action abortDownload = () => {
                ThreadPool.QueueUserWorkItem((s) => {
                    abortDownloadInternal(new Exception("Download has been aborted."));
                });
            };

            lock (sync) {
                try {
                    request = BuildWebRequest(url: url, auth: auth, connectionGroupName: connectionGroupName, cacheLastModifiedTime: cacheLastModifiedTime, referer: referer);
                    // Unfortunately BeginGetResponse blocks until the DNS lookup has finished
                    IAsyncResult requestResult = request.BeginGetResponse((requestResultParam) => {
                        lock (sync) {
                            try {
                                if (aborting)
                                {
                                    return;
                                }
                                response = (HttpWebResponse)request.EndGetResponse(requestResultParam);
                                if (GetMIMETypeFromContentType(response.ContentType) == "text/html")
                                {
                                    var memoryStream = new MemoryStream();
                                    CopyStream(new ThrottledStream(response.GetResponseStream(), Settings.MaximumBytesPerSecond ?? ThrottledStream.Infinite), memoryStream);
                                    memoryStream.Position    = 0;
                                    byte[] redirectPageBytes = memoryStream.ToArray();
                                    Encoding pageEncoding    = DetectHTMLEncoding(redirectPageBytes, response.ContentType);
                                    string metaRedirectHtml  = pageEncoding.GetString(redirectPageBytes);
                                    memoryStream.Position    = 0;
                                    responseStream           = memoryStream;
                                    string redirectUrl       = GetRedirectUrl(metaRedirectHtml, response.ResponseUri.AbsoluteUri);
                                    if (!string.IsNullOrEmpty(redirectUrl))
                                    {
                                        HttpWebRequest redirectionRequest = BuildWebRequest(url: redirectUrl, auth: auth, connectionGroupName: connectionGroupName, cacheLastModifiedTime: cacheLastModifiedTime);
                                        response       = (HttpWebResponse)redirectionRequest.GetResponse();
                                        responseStream = new ThrottledStream(response.GetResponseStream(), Settings.MaximumBytesPerSecond ?? ThrottledStream.Infinite);
                                    }
                                }
                                else
                                {
                                    responseStream = new ThrottledStream(response.GetResponseStream(), Settings.MaximumBytesPerSecond ?? ThrottledStream.Infinite);
                                }
                                onResponse(response);
                                byte[] buff = new byte[readBufferSize];
                                AsyncCallback readCallback = null;
                                readCallback = (readResultParam) => {
                                    lock (sync) {
                                        try {
                                            if (aborting)
                                            {
                                                return;
                                            }
                                            if (readResultParam != null)
                                            {
                                                int bytesRead = responseStream.EndRead(readResultParam);
                                                if (bytesRead == 0)
                                                {
                                                    request = null;
                                                    onComplete();
                                                    aborting = true;
                                                    cleanup();
                                                    return;
                                                }
                                                onDownloadChunk(buff, bytesRead);
                                            }
                                            IAsyncResult readResult = responseStream.BeginRead(buff, 0, buff.Length, readCallback, null);
                                            ThreadPool.RegisterWaitForSingleObject(readResult.AsyncWaitHandle,
                                                                                   (state, timedOut) => {
                                                if (!timedOut)
                                                {
                                                    return;
                                                }
                                                abortDownloadInternal(new Exception("Timed out while reading response."));
                                            }, null, readTimeoutMS, true);
                                        }
                                        catch (Exception ex) {
                                            abortDownloadInternal(ex);
                                        }
                                    }
                                };
                                readCallback(null);
                            }
                            catch (Exception ex) {
                                if (ex is WebException)
                                {
                                    WebException webEx = (WebException)ex;
                                    if (webEx.Status == WebExceptionStatus.ProtocolError)
                                    {
                                        HttpStatusCode code = ((HttpWebResponse)webEx.Response).StatusCode;
                                        if (code == HttpStatusCode.NotFound)
                                        {
                                            ex = new HTTP404Exception();
                                        }
                                        else if (code == HttpStatusCode.NotModified)
                                        {
                                            ex = new HTTP304Exception();
                                        }
                                    }
                                }
                                abortDownloadInternal(ex);
                            }
                        }
                    }, null);
                    ThreadPool.RegisterWaitForSingleObject(requestResult.AsyncWaitHandle,
                                                           (state, timedOut) => {
                        if (!timedOut)
                        {
                            return;
                        }
                        abortDownloadInternal(new Exception("Timed out while waiting for response."));
                    }, null, requestTimeoutMS, true);
                }
                catch (Exception ex) {
                    abortDownloadInternal(ex);
                }
            }
            return(abortDownload);
        }
예제 #2
0
        public static Action DownloadAsync(string url, string auth, string referer, string connectionGroupName, DateTime?cacheLastModifiedTime, Action <HttpWebResponse> onResponse, Action <byte[], int> onDownloadChunk, Action onComplete, Action <Exception> onException)
        {
            const int       readBufferSize   = 8192;
            const int       requestTimeoutMS = 60000;
            const int       readTimeoutMS    = 60000;
            object          sync             = new object();
            bool            aborting         = false;
            HttpWebRequest  request          = null;
            HttpWebResponse response         = null;
            Stream          responseStream   = null;
            Action          cleanup          = () => {
                if (request != null)
                {
                    request.Abort();
                    request = null;
                }
                if (responseStream != null)
                {
                    try { responseStream.Close(); }
                    catch { }
                    responseStream = null;
                }
                if (response != null)
                {
                    try { response.Close(); }
                    catch { }
                    response = null;
                }
            };
            Action <Exception> abortDownloadInternal = (ex) => {
                lock (sync) {
                    if (aborting)
                    {
                        return;
                    }
                    aborting = true;
                    cleanup();
                    onException(ex);
                }
            };
            Action abortDownload = () => {
                ThreadPool.QueueUserWorkItem((s) => {
                    abortDownloadInternal(new Exception("Download has been aborted."));
                });
            };

            lock (sync) {
                try {
                    request = (HttpWebRequest)WebRequest.Create(url);
                    if (connectionGroupName != null)
                    {
                        request.ConnectionGroupName = connectionGroupName;
                    }
                    request.UserAgent = (Settings.UseCustomUserAgent == true) ? Settings.CustomUserAgent : ("Chan Thread Watch " + Version);
                    request.Referer   = referer;
                    if (cacheLastModifiedTime != null)
                    {
                        request.IfModifiedSince = cacheLastModifiedTime.Value;
                    }
                    if (!String.IsNullOrEmpty(auth))
                    {
                        Encoding encoding = Encoding.GetEncoding("iso-8859-1");
                        request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(encoding.GetBytes(auth)));
                    }
                    // Unfortunately BeginGetResponse blocks until the DNS lookup has finished
                    IAsyncResult requestResult = request.BeginGetResponse((requestResultParam) => {
                        lock (sync) {
                            try {
                                if (aborting)
                                {
                                    return;
                                }
                                response       = (HttpWebResponse)request.EndGetResponse(requestResultParam);
                                responseStream = new ThrottledStream(response.GetResponseStream(), Settings.MaximumBytesPerSecond ?? ThrottledStream.Infinite);
                                onResponse(response);
                                byte[] buff = new byte[readBufferSize];
                                AsyncCallback readCallback = null;
                                readCallback = (readResultParam) => {
                                    lock (sync) {
                                        try {
                                            if (aborting)
                                            {
                                                return;
                                            }
                                            if (readResultParam != null)
                                            {
                                                int bytesRead = responseStream.EndRead(readResultParam);
                                                if (bytesRead == 0)
                                                {
                                                    request = null;
                                                    onComplete();
                                                    aborting = true;
                                                    cleanup();
                                                    return;
                                                }
                                                onDownloadChunk(buff, bytesRead);
                                            }
                                            IAsyncResult readResult = responseStream.BeginRead(buff, 0, buff.Length, readCallback, null);
                                            ThreadPool.RegisterWaitForSingleObject(readResult.AsyncWaitHandle,
                                                                                   (state, timedOut) => {
                                                if (!timedOut)
                                                {
                                                    return;
                                                }
                                                abortDownloadInternal(new Exception("Timed out while reading response."));
                                            }, null, readTimeoutMS, true);
                                        }
                                        catch (Exception ex) {
                                            abortDownloadInternal(ex);
                                        }
                                    }
                                };
                                readCallback(null);
                            }
                            catch (Exception ex) {
                                if (ex is WebException)
                                {
                                    WebException webEx = (WebException)ex;
                                    if (webEx.Status == WebExceptionStatus.ProtocolError)
                                    {
                                        HttpStatusCode code = ((HttpWebResponse)webEx.Response).StatusCode;
                                        if (code == HttpStatusCode.NotFound)
                                        {
                                            ex = new HTTP404Exception();
                                        }
                                        else if (code == HttpStatusCode.NotModified)
                                        {
                                            ex = new HTTP304Exception();
                                        }
                                    }
                                }
                                abortDownloadInternal(ex);
                            }
                        }
                    }, null);
                    ThreadPool.RegisterWaitForSingleObject(requestResult.AsyncWaitHandle,
                                                           (state, timedOut) => {
                        if (!timedOut)
                        {
                            return;
                        }
                        abortDownloadInternal(new Exception("Timed out while waiting for response."));
                    }, null, requestTimeoutMS, true);
                }
                catch (Exception ex) {
                    abortDownloadInternal(ex);
                }
            }
            return(abortDownload);
        }