| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -14,11 +14,28 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public StaticController() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            AllowFunction = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            AfterInitialized = Execute; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            AfterInitialized = () => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (Request == null || Request.Url == null) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var path = MapPath(Request.Url.AbsolutePath); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (StorageUtility.DirectoryExists(path)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    ExecuteDirectory(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (StorageUtility.FileExists(path)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    ExecuteFile(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                Respond404(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region property
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取此静态站点的目录。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual string GetSiteDirectory() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual string GetSiteDirectory() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var app = WebUtility.AppDirectory; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var www = StorageUtility.CombinePath(app, "www"); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -26,6 +43,34 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return www; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>响应 403 状态。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual void Respond403(string path) => Response.Error("403"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>响应 404 状态。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual void Respond404(string path) => Response.Error("404"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>从扩展名获取内容类型。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <remarks>例:<br/>GetContentType("txt") = "text/plain"</remarks>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual string GetContentType(string extension) => Mime(extension); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>按扩展名获取过期时间,单位为秒。默认值为 0(不缓存)。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <remarks>例:<br/>GetExpires("txt") = 0</remarks>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual int GetExpires(string extension) => 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>访问目录时,允许列出子项。默认值:false,不允许。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected virtual bool AllowListChildren() => false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        string PrivateGetContentType(string extension) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var result = GetContentType(extension); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (string.IsNullOrEmpty(result)) result = Mime(extension); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return result; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region common
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>解析 URL 的路径,获取本地路径。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        protected string MapPath(string urlPath) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -43,24 +88,6 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return path; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>处理请求。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual void Execute() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (Request == null || Request.Url == null) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var path = MapPath(Request.Url.AbsolutePath); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (StorageUtility.DirectoryExists(path)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                ExecuteDirectory(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (StorageUtility.FileExists(path)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                ExecuteFile(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Respond404(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void ExecuteFile(string path) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!File.Exists(path)) | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -78,8 +105,7 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (expires > 0) Response.Expires = expires; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 按扩展名获取 Content-Type。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var type = GetContentType(ext); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // var name = Path.GetFileName(path);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var type = PrivateGetContentType(ext); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // Server Side Includes
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (ext == "html" || ext == "htm" || ext == "shtml") | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -101,13 +127,89 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                Respond404(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var @default = GetDefaultFile(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (string.IsNullOrEmpty(@default)) Respond403(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else ExecuteFile(@default); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!string.IsNullOrEmpty(@default)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                ExecuteFile(@default); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (AllowListChildren()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                Response.Data = ListChildren(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Respond403(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // Server Side Includes
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        string ReadWithSSI(string path, int recursive = 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (recursive > 10) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var input = StorageUtility.ReadFile(path, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (input == null || input.LongLength < 1) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 尝试以 UTF-8 解码。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var html = TextUtility.FromBinary(input); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (string.IsNullOrEmpty(html)) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 按首尾截取。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string left = "<!--"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string right = "-->"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string head = "#include virtual="; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var sb = new StringBuilder(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var text = html; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            while (true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var offset = text.IndexOf(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (offset < 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (offset > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text.Substring(0, offset)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    text = text.Substring(offset + left.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else text = text.Substring(left.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var length = text.IndexOf(right); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (length < 1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var inner = text.Substring(0, length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var temp = inner.SafeTrim(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (temp.StartsWith(head)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    temp = temp.Substring(head.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    temp = temp.Replace("\"", ""); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var subPath = MapPath(temp); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var subText = ReadWithSSI(subPath, recursive + 1); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (subText != null && subText.Length > 0) sb.Append(subText); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(inner); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(right); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                text = text.Substring(length + right.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var output = sb.ToString(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return output; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region static
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 获取目录中的默认文件,返回文件的完整路径。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        string GetDefaultFile(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static string GetDefaultFile(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var subs = StorageUtility.GetSubFiles(directory); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (subs.Count < 0) return null; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -130,18 +232,16 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>列出子项。可指定筛选器,传入完整路径。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void ListChildren(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static Json ListChildren(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!Directory.Exists(directory)) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!Directory.Exists(directory)) return null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var json = Json.NewObject(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            json.SetProperty("directories", ListDirectories(directory)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            json.SetProperty("files", ListFiles(directory)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Response.Data = json; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return json; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Json ListDirectories(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static Json ListDirectories(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var array = Json.NewArray(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var subs = StorageUtility.GetSubDirectories(directory); | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -171,7 +271,7 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return array; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Json ListFiles(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static Json ListFiles(string directory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var array = Json.NewArray(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var subs = StorageUtility.GetSubFiles(directory); | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -199,20 +299,7 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return array; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>响应 403 状态。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual void Respond403(string path) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Response.Error("403"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>响应 404 状态。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual void Respond404(string path) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Response.Error("404"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>按扩展名获取 Content-Type。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual string GetContentType(string extension) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static string Mime(string extension) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!string.IsNullOrEmpty(extension)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -335,70 +422,7 @@ namespace Apewer.Web | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return "application/octet-stream"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>按扩展名获取过期时间,单位为秒,默认值为 0(不缓存)。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public virtual int GetExpires(string extension) => 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // Server Side Includes
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        string ReadWithSSI(string path, int recursive = 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (recursive > 10) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var input = StorageUtility.ReadFile(path, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (input == null || input.LongLength < 1) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 尝试以 UTF-8 解码。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var html = TextUtility.FromBinary(input); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (string.IsNullOrEmpty(html)) return ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 按首尾截取。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string left = "<!--"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string right = "-->"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            const string head = "#include virtual="; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var sb = new StringBuilder(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var text = html; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            while (true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var offset = text.IndexOf(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (offset < 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (offset > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text.Substring(0, offset)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    text = text.Substring(offset + left.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else text = text.Substring(left.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var length = text.IndexOf(right); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (length < 1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(text); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var inner = text.Substring(0, length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var temp = inner.SafeTrim(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (temp.StartsWith(head)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    temp = temp.Substring(head.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    temp = temp.Replace("\"", ""); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var subPath = MapPath(temp); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var subText = ReadWithSSI(subPath, recursive + 1); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (subText != null && subText.Length > 0) sb.Append(subText); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(left); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(inner); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    sb.Append(right); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                text = text.Substring(length + right.Length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var output = sb.ToString(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return output; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |