/// <summary> /// 设置文件缓存 /// </summary> /// <param name="path"></param> /// <param name="fileCache"></param> /// <param name="fileSize"></param> private void set(ref FileCacheKey path, FileCache fileCache, int fileSize) { Monitor.Enter(fileLock); try { fileCache.Size = fileSize; FileCache oldFileCache = files.Set(ref path, fileCache); freeCacheSize -= fileSize; if (oldFileCache == null) { while (freeCacheSize < 0 && files.Count > 1) { freeCacheSize += files.UnsafePopValue().Size; } } else if (oldFileCache != fileCache) { freeCacheSize += oldFileCache.Size; } } finally { Monitor.Exit(fileLock); } }
internal static void Set(ref FileCacheKey path, FileCache fileCache, int fileSize) { queues[path.HashCode & 0xff].set(ref path, fileCache, fileSize); }
internal static byte Get(ref FileCacheKey path, out FileCache fileCache, bool isCopyPath) { return(queues[path.HashCode & 0xff].get(ref path, out fileCache, isCopyPath)); }
/// <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> /// 创建错误输出数据 /// </summary> protected unsafe virtual void createErrorResponse() { KeyValue <Http.Response, Http.Response>[] errorResponses = new KeyValue <Http.Response, Http.Response> [EnumAttribute <Http.ResponseState> .GetMaxValue(-1) + 1]; int isResponse = 0; try { byte[] path = new byte[9]; fixed(byte *pathFixed = path) { *pathFixed = (byte)'/'; *(int *)(pathFixed + sizeof(int)) = '.' + ('h' << 8) + ('t' << 16) + ('m' << 24); *(pathFixed + sizeof(int) * 2) = (byte)'l'; foreach (Http.ResponseState type in System.Enum.GetValues(typeof(Http.ResponseState))) { Http.ResponseStateAttribute state = EnumAttribute <Http.ResponseState, Http.ResponseStateAttribute> .Array((int)type); if (state != null && state.IsError) { int stateValue = state.Number, value = stateValue / 100; *(pathFixed + 1) = (byte)(value + '0'); stateValue -= value * 100; *(pathFixed + 2) = (byte)((value = stateValue / 10) + '0'); *(pathFixed + 3) = (byte)((stateValue - value * 10) + '0'); Http.Response response = null; FileCache fileCache = file(path, default(SubArray <byte>), ref response, true); if (fileCache == null) { if (response != null) { response.CancelPool(); errorResponses[(int)type].Set(response, response); isResponse = 1; } } else { Http.Response gzipResponse; if ((response = fileCache.Response) == null) { response = Http.Response.New(); gzipResponse = Http.Response.New(); SubArray <byte> data = fileCache.Data, gzipData = fileCache.GZipData; if (FileCacheQueue.IsFileCacheHeader && data.Start == FileCache.HttpHeaderSize) { response.SetCanHeaderSize(ref data); gzipResponse.SetCanHeaderSize(ref gzipData); } else { response.SetBody(ref data); gzipResponse.SetBody(ref gzipData); } gzipResponse.SetContentEncoding(Http.Response.GZipEncoding); } else { gzipResponse = fileCache.GZipResponse ?? response; } response.SetState(type); gzipResponse.SetState(type); errorResponses[(int)type].Set(response, gzipResponse); isResponse = 1; } } } } } catch (Exception error) { RegisterServer.TcpServer.Log.Add(AutoCSer.Log.LogType.Error, error); } if (isResponse != 0) { this.errorResponses = errorResponses; } }
/// <summary> /// HTTP文件请求处理 /// </summary> /// <param name="header">请求头部信息</param> /// <param name="fileCache">文件输出信息</param> /// <param name="response">HTTP响应</param> protected unsafe void file(Http.Header header, FileCache fileCache, ref Http.Response response) { Http.HeaderFlag headerFlag = header.Flag; if (fileCache == null) { if (response != null) { if (response.Type == Http.ResponseType.File) { if ((headerFlag & Http.HeaderFlag.IsRange) != 0 && !header.FormatRange(response.BodySize)) { response = Http.Response.RangeNotSatisfiable416; return; } if ((headerFlag & Http.HeaderFlag.IsVersion) != 0 || isStaticFileCacheControl(header.Path)) { response.CacheControl = AutoCSer.Net.Http.Response.StaticFileCacheControl; } } if ((response.Flag & Http.ResponseFlag.IsPool) != 0 && (headerFlag & Http.HeaderFlag.IsSetOrigin) != 0 && this.isOrigin(header.Origin, (headerFlag & Http.HeaderFlag.IsSsl) != 0)) { response.SetAccessControlAllowOrigin(header.OriginIndex); } } return; } if ((headerFlag & Http.HeaderFlag.IsRange) != 0 && !header.FormatRange(fileCache.Data.Length)) { response = Http.Response.RangeNotSatisfiable416; return; } byte[] cacheControl = (headerFlag & Http.HeaderFlag.IsVersion) != 0 || isStaticFileCacheControl(header.Path) ? AutoCSer.Net.Http.Response.StaticFileCacheControl : this.cacheControl; bool isOrigin = (headerFlag & Http.HeaderFlag.IsSetOrigin) != 0 && this.isOrigin(header.Origin, (headerFlag & Http.HeaderFlag.IsSsl) != 0), isHeader = !isOrigin && (headerFlag & Http.HeaderFlag.IsRange) == 0 && FileCacheQueue.IsFileCacheHeader; if (isHeader && (response = (headerFlag & Http.HeaderFlag.IsGZip) == 0 ? fileCache.Response : fileCache.GZipResponse) != null && response.IsCacheControl(cacheControl)) { return; } SubArray <byte> body = (headerFlag & Http.HeaderFlag.IsGZip) != 0 && (headerFlag & Http.HeaderFlag.IsRange) == 0 ? fileCache.GZipData : fileCache.Data; response = Http.Response.Get(); //response.State = Http.ResponseState.Ok200; if (isHeader && body.Start == FileCache.HttpHeaderSize) { response.SetCanHeaderSize(ref body); } else { response.SetBody(ref body); } response.CacheControl = cacheControl; response.ContentType = fileCache.ContentType; if (body.Array != fileCache.Data.Array) { response.SetContentEncoding(Http.Response.GZipEncoding); } response.SetLastModified(fileCache.LastModified); if (isOrigin) { response.SetAccessControlAllowOrigin(header.OriginIndex); } return; }
/// <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); }