示例#1
0
        private void copyFile(string from, Stream toStr, string to, bool withProgress)
        {
            // Copy manually, as normal File.Move is likely to copy ACL from text directory as well
            VerboseMessage("Copying file '{0}' to '{1}'", from, to);
            long?len = null;

            try
            {
                len = new FileInfo(from).Length;
            }
            catch { }
            byte[] buf    = new byte[65536];
            long   copied = 0;
            string pref   = Context.TransformStr(Name, Transform);

            try
            {
                using (var fromStr = Context.OpenStream(from))
                {
                    if (withProgress)
                    {
                        var ps = new DownloadProgress(0, len);
                        Context.OnProgress(0, from);
                        if (base.Items.Count != 0)
                        {
                            Vars sv = new Vars();
                            sv.Set("", ps);
                            Context.ExecuteWithVars(baseExecute, sv, pref);
                        }
                    }

                    int n;
                    while ((n = fromStr.Read(buf, 0, buf.Length)) != 0)
                    {
                        Context.CheckAbort();
                        toStr.Write(buf, 0, n);
                        copied += n;
                        if (withProgress)
                        {
                            var ps = new DownloadProgress(copied, len);
                            Context.OnProgress(ps.ProgressPercentage, from);

                            if (base.Items.Count != 0)
                            {
                                Vars sv = new Vars();
                                sv.Set("", ps);
                                Context.ExecuteWithVars(baseExecute, sv, pref);
                            }
                        }
                    }
                    if (withProgress)
                    {
                        var ps = new DownloadProgress(copied, copied);
                        Context.OnProgress(100, from);
                        if (base.Items.Count != 0)
                        {
                            Vars sv = new Vars();
                            sv.Set("", ps);
                            Context.ExecuteWithVars(baseExecute, sv, pref);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                VerboseMessage("Copying failed: {0}. Deleting '{1}'", e.Message, to);
                try
                {
                    File.Delete(to);
                }
                catch
                {
                }
                throw;
            }
        }
示例#2
0
        /// Execute action
        public override object Execute()
        {
            string fromExpanded  = Context.TransformStr(From, Transform);
            string toExpanded    = Context.TransformStr(To, Transform);
            string outToExpanded = Context.TransformStr(OutTo, Transform);

            if (string.IsNullOrEmpty(outToExpanded))
            {
                if (!string.IsNullOrEmpty(toExpanded))
                {
                    toExpanded = UrlToLocalFileName(fromExpanded, toExpanded);
                }
            }
            var enc = Utils.GetEncoding(Context.TransformStr(Encoding, Transform));
            Uri uri = new Uri(fromExpanded);

            VerboseMessage("Downloading {0} => {1}...", Utils.SecureUri(fromExpanded), toExpanded);

            bool passive = PassiveFtp;
            bool ftpssl  = false;
            bool ftp     = false;
            var  scheme  = uri.Scheme;

            if (scheme == "ftpa" || scheme == "ftps" || scheme == "ftpas" || scheme == "ftpsa")
            {
                ftp = true;
                UriBuilder ub = new UriBuilder(uri);
                ub.Scheme = "ftp";
                uri       = ub.Uri;
                passive   = !(scheme == "ftpa" || scheme == "ftpas" || scheme == "ftpsa");
                ftpssl    = (scheme == "ftps" || scheme == "ftpas" || scheme == "ftpsa");
            }
            var timeout = Utils.ToTimeSpan(Context.TransformStr(Timeout, Transform));



            if (uri.IsFile || uri.Scheme == "embed")
            {
                var fname = (uri.Scheme == "embed") ? uri.ToString() : uri.LocalPath;
                VerboseMessage("Local filename '{0}' detected. Copying instead", fname);
                try
                {
                    if (Binary && toExpanded != null)
                    {
                        if (File.Exists(toExpanded))
                        {
                            File.Delete(toExpanded);
                        }
                        using (var toStr = Context.CreateStream(toExpanded))
                            copyFile(fname, toStr, toExpanded, true);
                    }
                    else
                    {
                        using (var ms = new MemoryStream())
                        {
                            copyFile(fname, ms, "memory:///", true);
                            if (Binary)
                            {
                                Context.OutTo(outToExpanded, ms.ToArray());
                            }
                            else
                            {
                                Context.OutTo(outToExpanded, (enc == null ? new StreamReader(ms) : new StreamReader(ms, enc)).ReadToEnd());
                            }
                        }
                    }
                }
                catch
                {
                    File.Delete(toExpanded);
                    throw;
                }
                return(null);
            }
            using (DownloadState state = new DownloadState(Context))
            {
                using (WebClientEx webClient = new WebClientEx(passive, Binary))
                {
                    webClient.KeepAlive   = (ftp && !passive);
                    webClient.FtpSsl      = ftpssl;
                    webClient.CachePolicy = new RequestCachePolicy(CacheLevel);

                    string user     = Context.TransformStr(User, Transform);
                    string password = Context.TransformStr(Password, Transform);
                    uri = webClient.SetCredentials(uri, user, password);

                    if (!string.IsNullOrEmpty(Post))
                    {
                        webClient.HttpPost = Context.Transform(Post, Transform);
                        if (!string.IsNullOrEmpty(PostContentType))
                        {
                            webClient.HttpPostContentType = Context.TransformStr(PostContentType, Transform);
                        }
                    }
                    webClient.HttpUserAgent = Context.TransformStr(UserAgent, Transform);
                    webClient.Timeout       = timeout;


                    int  oldPercentage = -1;
                    long bytesReceived = -1;


                    // We must ensure that all script components are executed in a single thread
                    webClient.DownloadProgressChanged += state.ProgressChanged;
                    webClient.DownloadFileCompleted   += state.FileCompleted;
                    webClient.DownloadStringCompleted += state.StringCompleted;
                    webClient.DownloadDataCompleted   += state.DataCompleted;

                    if (enc != null)
                    {
                        webClient.Encoding = enc;
                    }

                    string tmp = null;
                    if (string.IsNullOrEmpty(outToExpanded))
                    {
                        tmp = Direct ? toExpanded : Path.GetTempFileName();
                    }


                    var          lastUpdate = System.Diagnostics.Stopwatch.StartNew();
                    WaitHandle[] wh         = new WaitHandle[] { state.Completed, state.ProgressAvailable };
                    try
                    {
                        if (tmp == null)
                        {
                            if (Binary)
                            {
                                webClient.DownloadDataAsync(uri);
                            }
                            else
                            {
                                webClient.DownloadStringAsync(uri);
                            }
                        }
                        else
                        {
                            webClient.DownloadFileAsync(uri, tmp);
                        }

                        string pref = Context.TransformStr(Name, Transform);
                        while (true)
                        {
                            int n = WaitHandle.WaitAny(wh, 300, true);

                            if (n == 0 || n == 1)
                            {
                                lastUpdate = System.Diagnostics.Stopwatch.StartNew();
                                DownloadProgress ps = state.Progress;
                                if (n == 0)
                                {
                                    ps = state.Progress;
                                    if (Binary && state.Result != null)
                                    {
                                        ps.BytesReceived = ((byte[])state.Result).LongLength;
                                    }
                                    else if (tmp != null)
                                    {
                                        ps.BytesReceived = new FileInfo(tmp).Length;
                                    }
                                }

                                if (ps.BytesReceived > 0 && ps.BytesReceived > bytesReceived)
                                {
                                    VerboseMessage("Received: {0}", ps);
                                    Context.OnProgress(ps.ProgressPercentage, uri.ToString());
                                    oldPercentage = ps.ProgressPercentage;

                                    if (base.Items.Count != 0)
                                    {
                                        Vars sv = new Vars();
                                        sv.Set("", ps);
                                        Context.ExecuteWithVars(baseExecute, sv, pref);
                                    }
                                    bytesReceived = ps.BytesReceived;
                                }
                            }
                            else
                            {
                                // Sometimes FTP hangs, seen with FileZilla 0.9.31 + VMWare a few times
                                if (timeout.HasValue && lastUpdate.Elapsed > timeout.Value)
                                {
                                    throw new TimeoutException();
                                }
                            }
                            if (n == 0)
                            {
                                break;
                            }


                            Context.OnProgress(Math.Max(oldPercentage, 0), uri.ToString());
                        }
                        if (state.Error != null)
                        {
                            if (state.Error is TargetInvocationException)
                            {
                                Utils.Rethrow(state.Error.InnerException);
                            }
                            else
                            {
                                Utils.Rethrow(state.Error);
                            }
                        }

                        if (tmp != null && toExpanded != tmp)
                        {
                            if (File.Exists(toExpanded))
                            {
                                File.Delete(toExpanded);
                            }
                            using (var toStr = Context.CreateStream(toExpanded))
                                copyFile(tmp, toStr, toExpanded, false);
                            VerboseMessage("Copying completed. Deleting '{0}'", tmp);
                            File.Delete(tmp);
                        }
                    }
                    catch (Exception e)
                    {
                        VerboseMessage("Caught exception: {0}", e.Message);
                        webClient.CancelAsync();
                        state.SetCompleted();
                        throw;
                    }
                    finally
                    {
                        VerboseMessage("Waiting for download completion");

                        state.Completed.WaitOne(timeout ?? TimeSpan.FromSeconds(30), false);

                        VerboseMessage("Waiting completed");

                        webClient.DownloadProgressChanged -= state.ProgressChanged;
                        webClient.DownloadFileCompleted   -= state.FileCompleted;
                        webClient.DownloadStringCompleted -= state.StringCompleted;
                        webClient.DownloadDataCompleted   -= state.DataCompleted;


                        try
                        {
                            if (webClient.IsBusy)
                            {
                                webClient.CancelAsync();
                            }
                        }
                        catch
                        {
                        }

                        if (tmp == null)
                        {
                            Context.OutTo(outToExpanded, Binary ? state.Result : state.ResultStr);
                        }
                        else if (tmp != toExpanded)
                        {
                            try
                            {
                                File.Delete(tmp);
                            }
                            catch (IOException)
                            {
                                Thread.Sleep(500);
                                File.Delete(tmp);
                            }
                        }
                    }
                    VerboseMessage("Download completed.");
                }
            }

            return(null);
        }