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)); }
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); } }