/// <summary> /// HTTP文件请求处理 /// </summary> /// <param name="path">请求路径</param> /// <param name="ifModifiedSince">文件修改时间</param> /// <param name="response">HTTP响应输出</param> /// <param name="isCopyPath">是否复制请求路径</param> /// <returns>文件缓存</returns> protected unsafe FileCache file(byte[] path, SubArray <byte> ifModifiedSince, ref Http.Response response, bool isCopyPath) { string cacheFileName = null; try { if (path.Length != 0 && WorkPath.Length + path.Length <= AutoCSer.IO.File.MaxFullNameLength) { byte[] contentType = null; bool isCompress = true; fixed(byte *pathFixed = path) { byte *pathStart = pathFixed, pathEnd = pathStart + path.Length; if (isFile(pathEnd, ref contentType, ref isCompress) == 0) { if (*pathStart == '/') { ++pathStart; } for (byte *formatStart = pathStart; formatStart != pathEnd; ++formatStart) { if (*formatStart == ':') { response = Http.Response.Blank; return(null); } } int cachePathLength = (int)(pathEnd - pathStart); FileCacheKey cacheKey = new FileCacheKey(pathIdentity, path, (int)(pathStart - pathFixed), cachePathLength); FileCache fileCache = FileCacheQueue.Get(ref cacheKey); if (fileCache == null) { cacheFileName = StringExtension.FastAllocateString(WorkPath.Length + cachePathLength); fixed(char *nameFixed = cacheFileName) { char *write = nameFixed + WorkPath.Length; char directorySeparatorChar = Path.DirectorySeparatorChar; StringExtension.CopyNotNull(WorkPath, nameFixed); for (byte *start = pathStart; start != pathEnd; ++start) { *write++ = *start == '/' ? directorySeparatorChar : (char)*start; } } FileInfo file = new FileInfo(cacheFileName); if (file.Exists) { string fileName = file.FullName; if (fileName.Length > WorkPath.Length && WorkPath.equalCaseNotNull(fileName, WorkPath.Length)) { if (fileName.Length <= AutoCSer.IO.File.MaxFullNameLength && file.Length <= FileCacheQueue.MaxFileSize) { if (FileCacheQueue.Get(ref cacheKey, out fileCache, isCopyPath) != 0) { try { fileCache.LastModified = file.LastWriteTimeUtc.UniversalNewBytes(); int extensionNameLength = (int)(pathEnd - getExtensionNameStart(pathEnd)); SubArray <byte> fileData = readCacheFile(new SubString { String = fileName, Start = fileName.Length - extensionNameLength, Length = extensionNameLength }); FileCacheQueue.Set(ref cacheKey, fileCache, fileCache.Set(ref fileData, contentType, cacheControl, isCompress)); if (ifModifiedSince.Length == fileCache.LastModified.Length) { fixed(byte *ifModifiedSinceFixed = ifModifiedSince.Array) { if (Memory.EqualNotNull(fileCache.LastModified, ifModifiedSinceFixed + ifModifiedSince.Start, ifModifiedSince.Length)) { response = Http.Response.NotChanged304; return(null); } } } } finally { if (fileCache.IsData == 0) { fileCache.PulseAll(); fileCache = null; FileCacheQueue.RemoveOnly(ref cacheKey); } } } } else { if (ifModifiedSince.Length == Date.ToByteLength && Date.UniversalByteEquals(file.LastWriteTimeUtc, ifModifiedSince) == 0) { response = Http.Response.NotChanged304; return(null); } response = Http.Response.Get(); //response.State = Http.ResponseState.Ok200; response.SetBodyFile(file); response.CacheControl = cacheControl; response.ContentType = contentType; response.SetLastModified(file.LastWriteTimeUtc.UniversalNewBytes()); return(null); } } } } return(fileCache); } } } } catch (Exception error) { RegisterServer.TcpServer.Log.Add(AutoCSer.Log.LogType.Error, error, cacheFileName); } return(null); }
/// <summary> /// HTTP文件请求处理 /// </summary> /// <param name="header">请求头部</param> /// <param name="response">HTTP响应输出</param> /// <returns>文件缓存</returns> protected unsafe FileCache file(Http.Header header, ref Http.Response response) { SubArray <byte> path = header.Path; string cacheFileName = null; try { if (path.Length != 0 && WorkPath.Length + path.Length <= AutoCSer.IO.File.MaxFullNameLength) { byte[] contentType = null; bool isCompress = true; fixed(byte *pathFixed = path.GetFixedBuffer()) { byte *pathStart = pathFixed + path.Start, pathEnd = pathStart + path.Length; if (isFile(pathEnd, ref contentType, ref isCompress) == 0) { if (*pathStart == '/') { ++pathStart; } for (byte *formatStart = pathStart; formatStart != pathEnd; ++formatStart) { if (*formatStart == ':') { response = Http.Response.Blank; return(null); } #if !MONO if ((uint)(*formatStart - 'A') < 26) { *formatStart |= 0x20; } #endif } int cachePathLength = (int)(pathEnd - pathStart); FileCacheKey cacheKey = new FileCacheKey(pathIdentity, path.Array, (int)(pathStart - pathFixed), cachePathLength); FileCache fileCache = FileCacheQueue.Get(ref cacheKey); if (fileCache == null) { cacheFileName = StringExtension.FastAllocateString(WorkPath.Length + cachePathLength); fixed(char *nameFixed = cacheFileName) { char *write = nameFixed + WorkPath.Length; char directorySeparatorChar = Path.DirectorySeparatorChar; StringExtension.CopyNotNull(WorkPath, nameFixed); for (byte *start = pathStart; start != pathEnd; ++start) { *write++ = *start == '/' ? directorySeparatorChar : (char)*start; } } FileInfo file = new FileInfo(cacheFileName); bool isFileExists = file.Exists, isCopyPath = true; if (!isFileExists && cacheFileName.IndexOf('%') >= WorkPath.Length) { cacheKey.CopyPath(); isCopyPath = false; string newPath = AutoCSer.Net.Http.Header.UnescapeUtf8(pathStart, cachePathLength, path.Array, (int)(pathStart - pathFixed)); if (Path.DirectorySeparatorChar != '/') { newPath.replaceNotNull('/', Path.DirectorySeparatorChar); } FileInfo newFile = new FileInfo(WorkPath + newPath); if (newFile.Exists) { file = newFile; isFileExists = true; } } if (isFileExists) { string fileName = file.FullName; if (fileName.Length > WorkPath.Length && WorkPath.equalCaseNotNull(fileName, WorkPath.Length)) { if (fileName.Length <= AutoCSer.IO.File.MaxFullNameLength && file.Length <= FileCacheQueue.MaxFileSize) { if (FileCacheQueue.Get(ref cacheKey, out fileCache, isCopyPath) != 0) { try { fileCache.LastModified = file.LastWriteTimeUtc.UniversalNewBytes(); int extensionNameLength = (int)(pathEnd - getExtensionNameStart(pathEnd)); SubArray <byte> fileData = readCacheFile(new SubString { String = fileName, Start = fileName.Length - extensionNameLength, Length = extensionNameLength }); FileCacheQueue.Set(ref cacheKey, fileCache, fileCache.Set(ref fileData, contentType, cacheControl, isCompress)); if ((header.Flag & Http.HeaderFlag.IsSetIfModifiedSince) != 0 && header.IfModifiedSinceIndex.Length == fileCache.LastModified.Length) { if (AutoCSer.Memory.Common.EqualNotNull(fileCache.LastModified, pathFixed + header.Buffer.StartIndex + header.IfModifiedSinceIndex.StartIndex, header.IfModifiedSinceIndex.Length)) { response = Http.Response.NotChanged304; return(null); } } } finally { if (fileCache.IsData == 0) { fileCache.PulseAll(); fileCache = null; FileCacheQueue.RemoveOnly(ref cacheKey); } } } } else { if ((header.Flag & Http.HeaderFlag.IsSetIfModifiedSince) != 0 && header.IfModifiedSinceIndex.Length == Date.ToByteLength && Date.UniversalByteEquals(file.LastWriteTimeUtc, header.IfModifiedSince) == 0) { response = Http.Response.NotChanged304; return(null); } response = Http.Response.Get(); //response.State = Http.ResponseState.Ok200; response.SetBodyFile(file); response.CacheControl = cacheControl; response.ContentType = contentType; response.SetLastModified(file.LastWriteTimeUtc.UniversalNewBytes()); return(null); } } } } return(fileCache); } } } } catch (Exception error) { RegisterServer.TcpServer.Log.Exception(error, cacheFileName, LogLevel.Exception | LogLevel.AutoCSer); } return(null); }