예제 #1
0
        public Task GetAsync()
        {
            var webRequest = (HttpWebRequest)WebRequest.Create(RemoteLocation);

            webRequest.AllowAutoRedirect      = true;
            webRequest.Method                 = WebRequestMethods.Http.Get;
            webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

            return(Task.Factory.FromAsync(webRequest.BeginGetResponse, (Func <IAsyncResult, WebResponse>)webRequest.BetterEndGetResponse, this).ContinueWith(asyncResult => {
                // Logging.Logger.Message("In FromAsync Task::::::{0}", RemoteLocation);
                try {
                    if (_isCanceled)
                    {
                        _failed(RemoteLocation);
                        return;
                    }

                    var httpWebResponse = asyncResult.Result as HttpWebResponse;
                    _lastStatus = httpWebResponse.StatusCode;

                    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                    {
                        _lastModified = httpWebResponse.LastModified;
                        _contentLength = httpWebResponse.ContentLength;
                        ActualRemoteLocation = httpWebResponse.ResponseUri;

                        if (_isCanceled)
                        {
                            _failed(RemoteLocation);
                            return;
                        }

                        if (string.IsNullOrEmpty(_filename))
                        {
                            _filename = httpWebResponse.ContentDispositionFilename();

                            if (string.IsNullOrEmpty(_filename))
                            {
                                _filename = ActualRemoteLocation.LocalPath.Substring(ActualRemoteLocation.LocalPath.LastIndexOf('/') + 1);
                                if (string.IsNullOrEmpty(_filename) || ServerSideExtensions.Contains(Path.GetExtension(_filename)))
                                {
                                    ActualRemoteLocation.GetLeftPart(UriPartial.Path).MakeSafeFileName();
                                }
                            }
                        }

                        try {
                            if (Filename.FileIsLocalAndExists())
                            {
                                var md5 = string.Empty;
                                try {
                                    if (httpWebResponse.Headers.AllKeys.ContainsIgnoreCase("x-ms-meta-MD5"))
                                    {
                                        // it's coming from azure, check the value of the md5 and compare against the file on disk ... better than date/size matching.
                                        md5 = httpWebResponse.Headers["x-ms-meta-MD5"].Trim();
                                    }
                                    else if (httpWebResponse.Headers.AllKeys.ContainsIgnoreCase("Content-MD5"))
                                    {
                                        md5 = httpWebResponse.Headers["Content-MD5"].Trim();
                                        if (md5.EndsWith("="))
                                        {
                                            md5 = Convert.FromBase64CharArray(md5.ToCharArray(), 0, md5.Length).ToUtf8String();
                                        }
                                    }
                                } catch {
                                    // something gone screwy?
                                }

                                if (!string.IsNullOrEmpty(md5))
                                {
                                    var localMD5 = string.Empty;
                                    using (var stream = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                                        localMD5 = MD5.Create().ComputeHash(stream).ToHexString();
                                    }

                                    if (string.Equals(md5, localMD5, StringComparison.CurrentCultureIgnoreCase))
                                    {
                                        // it's the same file. We're not doin nothing.
                                        _completed(RemoteLocation);
                                        return;
                                    }

                                    // only do the size/date comparison if the server doesn't provide an MD5
                                }
                                else if (_contentLength > 0 && _lastModified.CompareTo(File.GetCreationTime(Filename)) <= 0 && _contentLength == new FileInfo(Filename).Length)
                                {
                                    // file is identical to the one on disk.
                                    // we're not going to reget it. :p
                                    _completed(RemoteLocation);
                                    return;
                                }
                            }

                            // we should open the file here, so that it's ready when we start the async read cycle.
                            if (_filestream != null)
                            {
                                _failed(RemoteLocation);
                                throw new CoAppException("THIS VERY BAD AND UNEXPECTED. (Failed to close?)");
                            }

                            _filestream = File.Open(Filename, FileMode.Create);

                            if (_isCanceled)
                            {
                                _failed(RemoteLocation);
                                return;
                            }

                            var tcs = new TaskCompletionSource <HttpWebResponse>(TaskCreationOptions.AttachedToParent);
                            tcs.Iterate(AsyncReadImpl(tcs, httpWebResponse));
                            return;
                        } catch {
                            // failed to actually create the file, or some other catastrophic failure.
                            _failed(RemoteLocation);
                            return;
                        }
                    }
                    // this is not good.
                    _failed(RemoteLocation);
                } catch (AggregateException e) {
                    _failed(RemoteLocation);
                    // at this point, we've failed somehow
                    if (_lastStatus == HttpStatusCode.NotImplemented)
                    {
                        // we never got started. Probably not found.
                    }
                    var ee = e.Flatten();
                    foreach (var ex in ee.InnerExceptions)
                    {
                        var wex = ex as WebException;
                        if (wex != null)
                        {
                            // Console.WriteLine("Status:" + wex.Status);
                            // Console.WriteLine("Response:" + wex.Response);
                            // Console.WriteLine("Response:" + ((HttpWebResponse)wex.Response).StatusCode);
                        }

                        // Console.WriteLine(ex.GetType());
                        // Console.WriteLine(ex.Message);
                        // Console.WriteLine(ex.StackTrace);
                    }
                } catch {
                    // Console.WriteLine(e.GetType());
                    // Console.WriteLine(e.Message);
                    // Console.WriteLine(e.StackTrace);
                }
            }, TaskContinuationOptions.AttachedToParent));
        }
예제 #2
0
        public void Get()
        {
            var webRequest = (HttpWebRequest)WebRequest.Create(RemoteLocation);

            webRequest.AllowAutoRedirect      = true;
            webRequest.Method                 = WebRequestMethods.Http.Get;
            webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
            webRequest.Timeout                = 15000;

            try {
                var response = webRequest.GetResponse() as HttpWebResponse;
                if (_isCanceled || response == null)
                {
                    _failed(RemoteLocation);
                    return;
                }

                var status = response.StatusCode;

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    _failed(RemoteLocation);
                    return;
                }

                var lastModified  = response.LastModified;
                var contentLength = response.ContentLength;
                ActualRemoteLocation = response.ResponseUri;

                // if we don't have a destination filename yet.
                if (string.IsNullOrEmpty(_filename))
                {
                    _filename = response.ContentDispositionFilename();

                    if (string.IsNullOrEmpty(_filename))
                    {
                        _filename = ActualRemoteLocation.LocalPath.Substring(ActualRemoteLocation.LocalPath.LastIndexOf('/') + 1);
                        if (string.IsNullOrEmpty(_filename) || ServerSideExtensions.Contains(Path.GetExtension(_filename)))
                        {
                            ActualRemoteLocation.GetLeftPart(UriPartial.Path).MakeSafeFileName();
                        }
                    }
                }

                // if we've already got a file here, let's compare what we have and see if we should proceed.
                if (Filename.FileIsLocalAndExists())
                {
                    var md5 = string.Empty;
                    try {
                        if (response.Headers.AllKeys.ContainsIgnoreCase("x-ms-meta-MD5"))
                        {
                            // it's coming from azure, check the value of the md5 and compare against the file on disk ... better than date/size matching.
                            md5 = response.Headers["x-ms-meta-MD5"].Trim();
                        }
                        else if (response.Headers.AllKeys.ContainsIgnoreCase("Content-MD5"))
                        {
                            md5 = response.Headers["Content-MD5"].Trim();
                            if (md5.EndsWith("="))
                            {
                                md5 = Convert.FromBase64CharArray(md5.ToCharArray(), 0, md5.Length).ToUtf8String();
                            }
                        }
                    } catch {
                        // something gone screwy?
                    }

                    if (!string.IsNullOrEmpty(md5))
                    {
                        var localMD5 = string.Empty;
                        using (var stream = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                            localMD5 = MD5.Create().ComputeHash(stream).ToHexString();
                        }
                        if (string.Equals(md5, localMD5, StringComparison.CurrentCultureIgnoreCase))
                        {
                            // it's the same file. We're not doin nothing.
                            _completed(RemoteLocation);
                            return;
                        }
                        // only do the size/date comparison if the server doesn't provide an MD5
                    }
                    else if (contentLength > 0 && lastModified.CompareTo(File.GetCreationTime(Filename)) <= 0 && contentLength == new FileInfo(Filename).Length)
                    {
                        // file is identical to the one on disk.
                        // we're not going to reget it. :p
                        _completed(RemoteLocation);
                        return;
                    }

                    // there was a file here, but it doesn't look like what we want.
                    Filename.TryHardToDelete();
                }

                try {
                    using (var filestream = File.Open(Filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) {
                        FileSecurity fSec = File.GetAccessControl(Filename);
                        fSec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, AccessControlType.Allow));
                        File.SetAccessControl(Filename, fSec);

                        if (_isCanceled)
                        {
                            _failed(RemoteLocation);
                            return;
                        }
                        var buffer    = new byte[BufferSize];
                        var totalRead = 0;
                        var bytesRead = 0;

                        using (Stream stream = response.GetResponseStream()) {
                            try {
                                do
                                {
                                    bytesRead = stream.Read(buffer, 0, BufferSize);
                                    filestream.Write(buffer, 0, bytesRead);
                                    totalRead += bytesRead;
                                    if (contentLength > 0)
                                    {
                                        _progress(RemoteLocation, (int)((totalRead * 100) / contentLength));
                                    }
                                } while (bytesRead != 0);
                            } catch (Exception e) {
                                Logger.Error(e);
                                _failed(RemoteLocation);
                            }
                        }
                    }
                } catch (Exception) {
                    // if it fails during download, then we cleanup the file too.
                    if (File.Exists(Filename))
                    {
                        Filename.TryHardToDelete();
                        // we should return a failure to the calling task I think.
                    }
                }
                try {
                    var fi = new FileInfo(Filename);
                    File.SetCreationTime(Filename, lastModified);
                    File.SetLastWriteTime(Filename, lastModified);

                    if (contentLength == 0)
                    {
                        contentLength = fi.Length;
                    }
                } catch {
                    // don't care if setting the timestamps fails.
                }
                _completed(RemoteLocation);
            } catch (WebException ex) {
                if ((int)ex.Status != 404)
                {
                    Logger.Error(ex);
                }
                _failed(RemoteLocation);
            } catch (Exception ex) {
                // on other errors, remove the file.
                Logger.Error(ex);
                _failed(RemoteLocation);
            }
        }