OSDN Git Service

na-get-lib, a4ab378a911e444c1d35e49e4de87bc1ea86755b でのミスを修正。
[applistation/AppliStation.git] / na-get-lib / NaGet.SubCommands.SubTask / DownloadSubTask.cs
index 2746786..c1ff3e4 100644 (file)
@@ -49,11 +49,21 @@ namespace NaGet.SubCommands.SubTask
                public System.Net.Cache.RequestCacheLevel CacheLevel = System.Net.Cache.RequestCacheLevel.NoCacheNoStore;
                
                /// <summary>
+               /// ダウンロード時に downloadedFileName に改名するか否か。
+               /// </summary>
+               protected bool enableChangeFileName = false;
+               
+               /// <summary>
                /// キャンセルが呼ばれたか否か。
                /// </summary>
                private bool cancelCalled = false;
                
                /// <summary>
+               /// ダウンロード中のファイル名につける接尾辞
+               /// </summary>
+               private static readonly string PartialFilePostfix = ".part";
+               
+               /// <summary>
                /// コンストラクタ
                /// </summary>
                /// <param name="url">ダウンロード先URL</param>
@@ -98,6 +108,21 @@ namespace NaGet.SubCommands.SubTask
                }
                
                /// <summary>
+               /// 保存先ファイル名を本来のファイル名に変えるか。
+               /// </summary>
+               public bool EnableChangeFileName {
+                       get { return enableChangeFileName; }
+                       set { enableChangeFileName = value; }
+               }
+               
+               /// <summary>
+               /// 保存ファイル。
+               /// </summary>
+               public string Filepath {
+                       get { return filepath; }
+               }
+               
+               /// <summary>
                /// キャンセル可能
                /// </summary>
                public override bool Cancelable {
@@ -184,9 +209,8 @@ namespace NaGet.SubCommands.SubTask
                        
                        HttpWebRequest httpRequest = request as HttpWebRequest;
                        if (httpRequest != null) {
-                               httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;  
-                               // TODO User-Agent
-                               httpRequest.UserAgent = "AppliStation/1.3";
+                               httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
+                               httpRequest.UserAgent = NaGet.Env.UserAgentString;
                        }
                }
                
@@ -216,21 +240,33 @@ namespace NaGet.SubCommands.SubTask
                        } catch (Exception) {
                        }
                        
-                       if (File.Exists(filepath)) { // ファイルが存在するとき削除
+                       // パス名を変えるときは、HTTPヘッダから取得したファイル名に変更する。
+                       if (enableChangeFileName && (!string.IsNullOrEmpty(downloadedFileName))) {
+                               filepath = Path.Combine(Path.GetDirectoryName(filepath), downloadedFileName);
+                       }
+                       
+                       // ファイルが存在するとき削除
+                       if (File.Exists(filepath)) {
                                File.Delete(filepath);
                        }
+                       // 部分ファイルが存在するときも削除 TODO レジューム処理
+                       if (File.Exists(filepath + PartialFilePostfix)) {
+                               File.Delete(filepath + PartialFilePostfix);
+                       }
                }
                
                private void runDownloadToFile()
                {
                        Stopwatch stopwatch = new Stopwatch();
+                       string partialFilepath = filepath + PartialFilePostfix;
                        
                        using (Stream stream = response.GetResponseStream() )
-                       using (FileStream fs = new FileStream(filepath,
+                       using (FileStream fs = new FileStream(partialFilepath,
                                                    FileMode.Create,
                                                    FileAccess.Write) ) {
+                               
                                try {
-                                       File.SetAttributes(filepath, FileAttributes.Hidden);
+                                       File.SetAttributes(partialFilepath, FileAttributes.Hidden);
                                        long contentLength = response.ContentLength;
        
                                        stopwatch.Start();
@@ -257,8 +293,6 @@ namespace NaGet.SubCommands.SubTask
                                        } finally {
                                                timer.Dispose();
                                        }
-                                       
-                                       File.SetAttributes(filepath, FileAttributes.Normal);
                                } catch (IOException ex) {
                                        if (cancelCalled) {
                                                throw new TaskCanceledException(string.Empty);
@@ -272,10 +306,15 @@ namespace NaGet.SubCommands.SubTask
                                        }
                                }
                        }
+                       
+                       if (File.Exists(partialFilepath)) {
+                               File.Move(partialFilepath, filepath);
+                               File.SetAttributes(filepath, FileAttributes.Normal);
+                       }
                }
                
                private void runPostprocess()
-               {                       
+               {
                        // 更新日を補完
                        if (File.Exists(filepath)) {
                                HttpWebResponse httpResponse = response as HttpWebResponse;
@@ -310,8 +349,17 @@ namespace NaGet.SubCommands.SubTask
                        HttpWebResponse httpresp = response as HttpWebResponse;
                        if (httpresp != null) {
                                string contentDisposition = httpresp.Headers["Content-Disposition"];
-                               
                                if (! string.IsNullOrEmpty(contentDisposition)) {
+                                       // おかしな Content-Disposition ヘッダ向け
+                                       // attachment と書いていないでいきなりfilenameからはじまるとき、attachment; を補って RFC1806 に準拠させる
+                                       if (System.Text.RegularExpressions.Regex.IsMatch(contentDisposition, @"^ *filename=", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) {
+                                               contentDisposition = "attachment; " + contentDisposition;
+                                       }
+                                       // "atachment;filename=\""のようにセミコロンの後ろにスペースがない場合、それを補充する
+                                       if (System.Text.RegularExpressions.Regex.IsMatch(contentDisposition, @";[^ ]", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) {
+                                               contentDisposition = string.Join("; ", System.Text.RegularExpressions.Regex.Split(contentDisposition, @"; *"));
+                                       }
+                                       
                                        try {
                                                ContentDisposition parser = new ContentDisposition(contentDisposition);
                                                if (! string.IsNullOrEmpty(parser.FileName)) {
@@ -345,7 +393,7 @@ namespace NaGet.SubCommands.SubTask
                        // スループット・残り時間の算出
                        if (elapsedms > 0) {
                                byteps = 1000 * downloadsize / elapsedms;
-                               if (filesize > 0) {
+                               if (filesize > 0 && byteps > 0) {
                                        eta = TimeSpan.FromSeconds((filesize - downloadsize) / byteps);
                                }
                        }
@@ -353,7 +401,7 @@ namespace NaGet.SubCommands.SubTask
                        System.Text.StringBuilder msgbuilder = new System.Text.StringBuilder();
                        msgbuilder.AppendFormat("{0} bytes", downloadsize);
                        if (percent > 0) {
-                               msgbuilder.AppendFormat(" ({0}%)", percent);
+                               msgbuilder.AppendFormat(" ({0:F2}%)", percent);
                        }
                        if (eta.Ticks > 0) {
                                msgbuilder.AppendFormat(" ETA {0}", eta);