コード例 #1
0
ファイル: StaticFilesModule.cs プロジェクト: ngdadu/embedio
        private bool HandleGet(HttpListenerContext context, WebServer server, bool sendBuffer = true)
        {
            var urlPath = context.Request.Url.LocalPath.Replace('/', Path.DirectorySeparatorChar);

            // adjust the path to see if we've got a default document
            if (urlPath.Last() == Path.DirectorySeparatorChar)
                urlPath = urlPath + DefaultDocument;

            urlPath = urlPath.TrimStart(new char[] {Path.DirectorySeparatorChar});

            var localPath = Path.Combine(FileSystemPath, urlPath);
            var eTagValid = false;
            byte[] buffer = null;
            var fileDate = DateTime.Today;
            var partialHeader = context.RequestHeader(Constants.HeaderRange);
            var usingPartial = String.IsNullOrWhiteSpace(partialHeader) == false && partialHeader.StartsWith("bytes=");

            if (string.IsNullOrWhiteSpace(DefaultExtension) == false && DefaultExtension.StartsWith(".") &&
                File.Exists(localPath) == false)
            {
                var newPath = localPath + DefaultExtension;
                if (File.Exists(newPath))
                    localPath = newPath;
            }

            if (File.Exists(localPath) == false) return false;

            if (usingPartial == false)
            {
                fileDate = File.GetLastWriteTime(localPath);
                var requestHash = context.RequestHeader(Constants.HeaderIfNotMatch);

                if (RamCache.ContainsKey(localPath) && RamCache[localPath].LastModified == fileDate)
                {
                    server.Log.DebugFormat("RAM Cache: {0}", localPath);
                    var currentHash = Extensions.ComputeMd5Hash(RamCache[localPath].Buffer) + '-' + fileDate.Ticks;

                    if (String.IsNullOrWhiteSpace(requestHash) || requestHash != currentHash)
                    {
                        buffer = RamCache[localPath].Buffer;
                        context.Response.AddHeader(Constants.HeaderETag, currentHash);
                    }
                    else
                    {
                        eTagValid = true;
                    }
                }
                else
                {
                    server.Log.DebugFormat("File System: {0}", localPath);
                    if (sendBuffer)
                    {
                        buffer = File.ReadAllBytes(localPath);

                        var currentHash = Extensions.ComputeMd5Hash(buffer) + '-' + fileDate.Ticks;

                        if (String.IsNullOrWhiteSpace(requestHash) || requestHash != currentHash)
                        {
                            if (UseRamCache && buffer.Length <= MaxRamCacheFileSize)
                            {
                                RamCache[localPath] = new RamCacheEntry() {LastModified = fileDate, Buffer = buffer};
                            }

                            context.Response.AddHeader(Constants.HeaderETag, currentHash);
                        }
                        else
                        {
                            eTagValid = true;
                        }
                    }
                }
            }

            // check to see if the file was modified or etag is the same
            var utcFileDateString = fileDate.ToUniversalTime()
                .ToString(Constants.BrowserTimeFormat, CultureInfo.InvariantCulture);
            if (usingPartial == false &&
                (eTagValid || context.RequestHeader(Constants.HeaderIfModifiedSince).Equals(utcFileDateString)))
            {
                context.Response.AddHeader(Constants.HeaderCacheControl, "private");
                context.Response.AddHeader(Constants.HeaderPragma, string.Empty);
                context.Response.AddHeader(Constants.HeaderExpires, string.Empty);
                context.Response.ContentType = string.Empty;

                context.Response.StatusCode = 304;
            }
            else
            {
                var extension = Path.GetExtension(localPath).ToLowerInvariant();
                if (MimeTypes.ContainsKey(extension))
                    context.Response.ContentType = MimeTypes[extension];

                context.Response.AddHeader(Constants.HeaderCacheControl, "private");
                context.Response.AddHeader(Constants.HeaderPragma, string.Empty);
                context.Response.AddHeader(Constants.HeaderExpires, string.Empty);
                context.Response.AddHeader(Constants.HeaderLastModified, utcFileDateString);
                context.Response.AddHeader(Constants.HeaderAcceptRanges, "bytes");

                if (sendBuffer)
                {
                    var lrange = 0;
                    var urange = 0;
                    var size = (long) 0;
                    var isPartial = false;
                    var fileSize = new FileInfo(localPath).Length;

                    if (usingPartial)
                    {
                        var range = partialHeader.Replace("bytes=", "").Split('-');
                        if (range.Length == 2 && int.TryParse(range[0], out lrange) &&
                            int.TryParse(range[1], out urange))
                        {
                            isPartial = true;
                        }

                        if ((range.Length == 2 && int.TryParse(range[0], out lrange) &&
                             string.IsNullOrWhiteSpace(range[1])) ||
                            (range.Length == 1 && int.TryParse(range[0], out lrange)))
                        {
                            urange = (int) fileSize - 1;
                            isPartial = true;
                        }

                        if (range.Length == 2 && string.IsNullOrWhiteSpace(range[0]) &&
                            int.TryParse(range[1], out urange))
                        {
                            lrange = (int) fileSize - urange;
                            urange = (int)fileSize - 1;
                            isPartial = true;
                        }
                    }

                    if (isPartial)
                    {
                        if (urange > fileSize)
                        {
                            context.Response.StatusCode = 416;
                            context.Response.AddHeader(Constants.HeaderContentRanges,
                                string.Format("bytes */{0}", fileSize));
                            return true;
                        }

                        size = (urange - lrange) + 1;

                        context.Response.AddHeader(Constants.HeaderContentRanges,
                            string.Format("bytes {0}-{1}/{2}", lrange, urange, fileSize));

                        context.Response.StatusCode = 206;

                        server.Log.DebugFormat("Opening stream {0} bytes {1}-{2} size {3}", localPath, lrange, urange,
                            size);

                        buffer = new byte[size];

                        // Open FileStream with FileShare
                        using (var fs = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                        {
                            if (lrange + size > fs.Length) size = fs.Length - lrange;
                            fs.Seek(lrange, SeekOrigin.Begin);
                            fs.Read(buffer, 0, (int) size);
                            fs.Close();
                        }

                        // Reset lower range
                        lrange = 0;
                    }
                    else
                    {
                        size = buffer.LongLength;

                        // Perform compression if available
                        if (context.RequestHeader(Constants.HeaderAcceptEncoding).Contains("gzip"))
                        {
                            buffer = buffer.Compress();
                            context.Response.AddHeader(Constants.HeaderContentEncoding, "gzip");
                            size = buffer.LongLength;
                            lrange = 0;
                        }
                    }

                    context.Response.ContentLength64 = size;

                    try
                    {
                        context.Response.OutputStream.Write(buffer, lrange, (int) size);
                    }
                    catch (HttpListenerException)
                    {
                        // Connection error, nothing else to do
                    }
                }
                else
                {
                    context.Response.ContentLength64 = buffer == null
                        ? new FileInfo(localPath).Length
                        : buffer.LongLength;
                }
            }

            return true;
        }
コード例 #2
0
        private bool HandleGet(HttpListenerContext context, WebServer server, bool sendBuffer = true)
        {
            var rootFs = FileSystemPath;
            var urlPath = GetUrlPath(context, ref rootFs);
            var localPath = Path.Combine(rootFs, urlPath);
            var eTagValid = false;
            Stream buffer = null;
            var partialHeader = context.RequestHeader(Constants.HeaderRange);
            var usingPartial = string.IsNullOrWhiteSpace(partialHeader) == false && partialHeader.StartsWith("bytes=");

            if (ExistsLocalPath(urlPath, ref localPath) == false) return false;

            var fileDate = File.GetLastWriteTime(localPath);

            var requestHash = context.RequestHeader(Constants.HeaderIfNotMatch);

            if (RamCache.ContainsKey(localPath) && RamCache[localPath].LastModified == fileDate)
            {
            #if COMPAT
                server.Log.DebugFormat("RAM Cache: {0}", localPath);
            #else
                $"RAM Cache: {localPath}".Debug();
            #endif

                var currentHash = RamCache[localPath].Buffer.ComputeMD5().ToUpperHex() + '-' + fileDate.Ticks;

                if (string.IsNullOrWhiteSpace(requestHash) || requestHash != currentHash)
                {
                    buffer = new MemoryStream(RamCache[localPath].Buffer);
                    context.Response.AddHeader(Constants.HeaderETag, currentHash);
                }
                else
                {
                    eTagValid = true;
                }
            }
            else
            {
            #if COMPAT
                server.Log.DebugFormat("File System: {0}", localPath);
            #else
                $"File System: {localPath}".Debug();
            #endif

                if (sendBuffer)
                {
                    buffer = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                    if (usingPartial == false)
                    {
                        eTagValid = UpdateFileCache(context, buffer, fileDate, requestHash, localPath);
                    }
                }
            }

            // check to see if the file was modified or e-tag is the same
            var utcFileDateString = fileDate.ToUniversalTime()
                .ToString(Constants.BrowserTimeFormat, Constants.StandardCultureInfo);

            if (usingPartial == false &&
                (eTagValid || context.RequestHeader(Constants.HeaderIfModifiedSince).Equals(utcFileDateString)))
            {
                SetStatusCode304(context);
                return true;
            }

            SetHeaders(context, localPath, utcFileDateString);

            var fileSize = new FileInfo(localPath).Length;

            if (sendBuffer == false)
            {
                context.Response.ContentLength64 = buffer?.Length ?? fileSize;
                return true;
            }

            // If buffer is null something is really wrong
            if (buffer == null) return false;

            var lowerByteIndex = 0;
            var upperByteIndex = 0;
            long byteLength;
            var isPartial = usingPartial &&
                            CalculateRange(partialHeader, fileSize, out lowerByteIndex, out upperByteIndex);

            if (isPartial)
            {
                if (upperByteIndex > fileSize)
                {
                    context.Response.StatusCode = 416;
                    context.Response.AddHeader(Constants.HeaderContentRanges,
                        $"bytes */{fileSize}");

                    return true;
                }

                if (upperByteIndex == fileSize)
                {
                    byteLength = buffer.Length;
                }
                else
                {
                    byteLength = upperByteIndex - lowerByteIndex + 1;

                    context.Response.AddHeader(Constants.HeaderContentRanges,
                        $"bytes {lowerByteIndex}-{upperByteIndex}/{fileSize}");

                    context.Response.StatusCode = 206;

            #if COMPAT
                server.Log.DebugFormat("Opening stream {0} bytes {1}-{2} size {3}", localPath, lowerByteIndex,
                        upperByteIndex,
                        byteLength);
            #else
                $"Opening stream {localPath} bytes {lowerByteIndex}-{upperByteIndex} size {byteLength}".Debug();
            #endif
                }
            }
            else
            {
                if (UseGzip &&
                    context.RequestHeader(Constants.HeaderAcceptEncoding).Contains(Constants.HeaderCompressionGzip) &&
                    buffer.Length < MaxGzipInputLength &&
                    // Ignore audio/video from compression
                    context.Response.ContentType?.StartsWith("audio") == false &&
                    context.Response.ContentType?.StartsWith("video") == false)
                {
                    // Perform compression if available
                    buffer = buffer.Compress();
                    context.Response.AddHeader(Constants.HeaderContentEncoding, Constants.HeaderCompressionGzip);
                    lowerByteIndex = 0;
                }

                byteLength = buffer.Length;
            }

            context.Response.ContentLength64 = byteLength;

            try
            {
                WriteToOutputStream(context, byteLength, buffer, lowerByteIndex);
            }
            catch (HttpListenerException)
            {
                // Connection error, nothing else to do
            }
            finally
            {
            #if !NETCOREAPP1_1 && !NETSTANDARD1_6
                buffer.Close();
            #endif
                buffer.Dispose();
            }

            return true;
        }