Пример #1
0
        public void MaxAgeShouldSetWhenNoRockCacheablityOptionSet()
        {
            var cache = new RockCacheability
            {
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                },
            };

            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.Private;

            Assert.That.IsNotNull(cache.MaxAge);

            cache = new RockCacheability
            {
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                },
            };

            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.Public;

            Assert.That.IsNotNull(cache.MaxAge);
        }
Пример #2
0
        public void SetupHttpCachePolicySetPrivateOptionWithMaxAgesCorrectly()
        {
            var cachePolicy = ReflectionHelper.CreateInstance <HttpCachePolicy>();

            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Private,
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Seconds, Value = 120
                },
                SharedMaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Seconds, Value = 240
                }
            };

            cache.SetupHttpCachePolicy(cachePolicy);

            var noStore = ReflectionHelper.GetFieldValue <bool>(cachePolicy, "_noStore");

            Assert.That.IsFalse(noStore);

            var cacheability = ReflectionHelper.GetFieldValue <HttpCacheability>(cachePolicy, "_cacheability");

            Assert.That.AreEqual(HttpCacheability.Private, cacheability);

            var maxAge = ReflectionHelper.GetFieldValue <TimeSpan>(cachePolicy, "_maxAge");

            Assert.That.AreEqual(new TimeSpan(0, 0, 120), maxAge);

            var sharedMaxAge = ReflectionHelper.GetFieldValue <TimeSpan>(cachePolicy, "_proxyMaxAge");

            Assert.That.AreEqual(new TimeSpan(0, 0, 240), sharedMaxAge);
        }
Пример #3
0
        public void RockCacheablityTypeSettingToAgeTypeShouldLeaveAgeProperties()
        {
            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Private,
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                },
                SharedMaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                }
            };

            Assert.That.IsNotNull(cache.SharedMaxAge);
            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.Public;

            Assert.That.IsNotNull(cache.SharedMaxAge);
            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.Private;

            Assert.That.IsNotNull(cache.SharedMaxAge);
            Assert.That.IsNotNull(cache.MaxAge);
        }
Пример #4
0
        public void SharedMaxAgeShouldNotSetWhenNonAgeSupportedRockCacheablityOptionSet()
        {
            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.NoCache
            };

            Assert.That.IsNull(cache.SharedMaxAge);

            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Days, Value = 5
            };

            Assert.That.IsNull(cache.SharedMaxAge);

            cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.NoStore
            };

            Assert.That.IsNull(cache.SharedMaxAge);

            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Days, Value = 5
            };

            Assert.That.IsNull(cache.SharedMaxAge);
        }
Пример #5
0
        public void MaxAgeShouldSetWhenAgeSupportedRockCacheablityOptionSet()
        {
            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Private
            };

            Assert.That.IsNull(cache.MaxAge);

            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Days, Value = 5
            };

            Assert.That.IsNotNull(cache.MaxAge);

            cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Public
            };

            Assert.That.IsNull(cache.MaxAge);

            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Days, Value = 5
            };

            Assert.That.IsNotNull(cache.MaxAge);
        }
Пример #6
0
        public void OptionSupportsAgeShouldReturnCorrectly()
        {
            var cache = new RockCacheability();

            Assert.That.IsFalse(cache.OptionSupportsAge(RockCacheablityType.NoCache));
            Assert.That.IsFalse(cache.OptionSupportsAge(RockCacheablityType.NoStore));
            Assert.That.IsTrue(cache.OptionSupportsAge(RockCacheablityType.Private));
            Assert.That.IsTrue(cache.OptionSupportsAge(RockCacheablityType.Public));
        }
Пример #7
0
        public void SetupHttpCachePolicySetNoStoreOptionCorrectly()
        {
            var cachePolicy = ReflectionHelper.CreateInstance <HttpCachePolicy>();

            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.NoStore
            };

            cache.SetupHttpCachePolicy(cachePolicy);

            var noStore = ReflectionHelper.GetFieldValue <bool>(cachePolicy, "_noStore");

            Assert.That.IsTrue(noStore);
        }
Пример #8
0
        public void SetupHttpCachePolicySetPrivateOptionCorrectly()
        {
            var cachePolicy = ReflectionHelper.CreateInstance <HttpCachePolicy>();

            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Private
            };

            cache.SetupHttpCachePolicy(cachePolicy);

            var noStore = ReflectionHelper.GetFieldValue <bool>(cachePolicy, "_noStore");

            Assert.That.IsFalse(noStore);

            var cacheability = ReflectionHelper.GetFieldValue <HttpCacheability>(cachePolicy, "_cacheability");

            Assert.That.AreEqual(HttpCacheability.Private, cacheability);
        }
Пример #9
0
        public void RockCacheablityTypeSettingToNonAgeTypeShouldClearAgeProperties()
        {
            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Public,
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                },
                SharedMaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                }
            };

            Assert.That.IsNotNull(cache.SharedMaxAge);
            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.NoCache;

            Assert.That.IsNull(cache.SharedMaxAge);
            Assert.That.IsNull(cache.MaxAge);

            cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.Public,
                MaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                },
                SharedMaxAge = new TimeInterval {
                    Unit = TimeIntervalUnit.Days, Value = 10
                }
            };

            Assert.That.IsNotNull(cache.SharedMaxAge);
            Assert.That.IsNotNull(cache.MaxAge);

            cache.RockCacheablityType = RockCacheablityType.NoStore;

            Assert.That.IsNull(cache.SharedMaxAge);
            Assert.That.IsNull(cache.MaxAge);
        }
Пример #10
0
        /// <summary>
        /// Copies from model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public override void SetFromEntity(IEntity entity)
        {
            base.SetFromEntity(entity);

            var blockType = entity as BinaryFileType;

            if (blockType == null)
            {
                return;
            }

            IsSystem           = blockType.IsSystem;
            CacheControlHeader = blockType.CacheControlHeader;
            Name        = blockType.Name;
            Description = blockType.Description;
            CacheControlHeaderSettings = blockType.CacheControlHeaderSettings;
            CacheToServerFileSystem    = blockType.CacheToServerFileSystem;
            Guid                = blockType.Guid;
            IconCssClass        = blockType.IconCssClass;
            Id                  = blockType.Id;
            StorageEntityTypeId = blockType.StorageEntityTypeId;
        }
Пример #11
0
        /// <summary>
        /// Sends the file.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="fileContents">The file contents.</param>
        /// <param name="mimeType">Type of the MIME.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="eTag">The e tag.</param>
        private void SendFile(HttpContext context, Stream fileContents, string mimeType, string fileName, string eTag, RockCacheability rockCacheability)
        {
            /*
             *  9/23/2021 - JME - Range Support
             *  The original implementation of range support did not take into account the size of the file compared to the requested range in bytes. For
             *  example if the Azure CDN requested 8MB of bytes starting at the 8MB byte (the second chunk 8MB chunk) and the file is only 12MB is size the
             *  "Content-Range" response header was being sent as: "bytes 8388608-16777215/12582912". Basically saying "I'm going to send you 8MB but only
             *  sending ~4MB.
             *
             *  Also, if the file was quite large (say 50MB) and the Azure CDN made the same request it would send back the correct "Content-Range" header
             *  ("bytes 8388608-16777215/52428800") but would send the contents of the file starting at 8MB all the way to the end of the file (instead of
             *  stopping at the 16MB point).
             *
             *  The logic had to be updated to send the correct header if the file does not have the full range available and to send only the requested range
             *  of content.
             *
             *  More Details: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
             *
             *  Worries:
             *  Little nervous of some of the +1 -1 logic from the SO article. Worried that when there is more content than requested in the range we could be
             *  off by one byte. Used the curl below to does the size of the output. Looks correct.
             *
             *  In the Azure CDN example above the request header from Azure for the range is:
             *  "Range: bytes=8388608-16777215"
             *
             *  curl -so curl.bin -i --location --request GET 'http://{server_name}/GetFile.ashx?Id=538' --header 'Range: bytes=8388608-16777215' -w '%{size_download}'
             *  Outputs: 8388608
             *
             *  According to the documentation here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests this is correct. In their example of
             *  "Range: bytes=0-1023" the response length should be 1024 (inclusive of start and end).
             *  so
             *  "Range: bytes=8388608-16777215" = 16777215 - 8388608 + 1 = 8388608
             */

            const int _defaultBufferSize = 4096;

            var rangeStartIndex   = 0;
            var rangeEndIndex     = 0;
            var fileLength        = ( int )fileContents.Length;
            var responseLength    = fileLength;
            var isRangeRequest    = false;
            var numberOfBytesSent = 0;

            // Rresumable logic from http://stackoverflow.com/a/6475414/1755417
            if (context.Request.Headers["Range"] != null && (context.Request.Headers["If-Range"] == null))
            {
                isRangeRequest = true;
                var match = Regex.Match(context.Request.Headers["Range"], @"bytes=(\d*)-(\d*)");
                rangeStartIndex = match.Groups[1].Value.AsInteger();
                rangeEndIndex   = match.Groups[2].Value.AsIntegerOrNull() + 1 ?? fileLength;

                var requestedRangeSize = rangeEndIndex - rangeStartIndex;
                var rangeAvailable     = fileLength - rangeStartIndex;

                // Response length will be the range requested or the remaining file content size
                responseLength = Math.Min(requestedRangeSize, rangeAvailable);

                // Send the Content-Range header
                context.Response.Headers["Content-Range"] = "bytes " + rangeStartIndex + "-" + (rangeStartIndex + responseLength - 1) + "/" + fileLength;

                // Send 209 status code 'Partial Content'
                context.Response.StatusCode = ( int )System.Net.HttpStatusCode.PartialContent;
            }

            context.Response.Clear();
            context.Response.Buffer = false;
            context.Response.Headers["Accept-Ranges"] = "bytes";

            bool sendAsAttachment = context.Request.QueryString["attachment"].AsBooleanOrNull() ?? false;

            context.Response.AddHeader("content-disposition", string.Format("{1};filename={0}", fileName.MakeValidFileName(), sendAsAttachment ? "attachment" : "inline"));
            context.Response.AddHeader("content-length", responseLength.ToString());

            rockCacheability.SetupHttpCachePolicy(context.Response.Cache);

            context.Response.Cache.SetETag(eTag);   // required for IE9 resumable downloads
            context.Response.ContentType = mimeType;
            byte[] buffer = new byte[_defaultBufferSize];

            if (context.Response.IsClientConnected)
            {
                using (var fileStream = fileContents)
                {
                    if (fileStream.CanSeek)
                    {
                        fileStream.Seek(rangeStartIndex, SeekOrigin.Begin);
                    }

                    while (true)
                    {
                        // If range request we may need to adjust the size of the buffer if we don't need to read the entire 4k default size
                        if (isRangeRequest)
                        {
                            var amountLeftToRead = responseLength - numberOfBytesSent;
                            if (amountLeftToRead < _defaultBufferSize)
                            {
                                buffer = new byte[amountLeftToRead];
                            }
                        }

                        var bytesRead = fileStream.Read(buffer, 0, buffer.Length);
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        if (!context.Response.IsClientConnected)
                        {
                            // quit sending if the client isn't connected
                            break;
                        }

                        try
                        {
                            context.Response.OutputStream.Write(buffer, 0, bytesRead);
                            numberOfBytesSent = numberOfBytesSent + bytesRead;
                        }
                        catch (HttpException ex)
                        {
                            if (!context.Response.IsClientConnected)
                            {
                                // if client disconnected during the .write, ignore
                            }
                            else
                            {
                                throw ex;
                            }
                        }
                    }
                }
            }

            context.ApplicationInstance.CompleteRequest();
        }
Пример #12
0
        /// <summary>
        /// Sends the file.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="fileContents">The file contents.</param>
        /// <param name="mimeType">Type of the MIME.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="eTag">The e tag.</param>
        private void SendFile(HttpContext context, Stream fileContents, string mimeType, string fileName, string eTag, RockCacheability rockCacheability)
        {
            int startIndex     = 0;
            int fileLength     = ( int )fileContents.Length;
            int responseLength = fileLength;

            // resumable logic from http://stackoverflow.com/a/6475414/1755417
            if (context.Request.Headers["Range"] != null && (context.Request.Headers["If-Range"] == null))
            {
                var match = Regex.Match(context.Request.Headers["Range"], @"bytes=(\d*)-(\d*)");
                startIndex     = match.Groups[1].Value.AsInteger();
                responseLength = (match.Groups[2].Value.AsIntegerOrNull() + 1 ?? fileLength) - startIndex;
                context.Response.StatusCode = ( int )System.Net.HttpStatusCode.PartialContent;
                context.Response.Headers["Content-Range"] = "bytes " + startIndex + "-" + (startIndex + responseLength - 1) + "/" + fileLength;
            }

            context.Response.Clear();
            context.Response.Buffer = false;
            context.Response.Headers["Accept-Ranges"] = "bytes";

            bool sendAsAttachment = context.Request.QueryString["attachment"].AsBooleanOrNull() ?? false;

            context.Response.AddHeader("content-disposition", string.Format("{1};filename={0}", fileName.MakeValidFileName(), sendAsAttachment ? "attachment" : "inline"));
            context.Response.AddHeader("content-length", responseLength.ToString());

            rockCacheability.SetupHttpCachePolicy(context.Response.Cache);

            context.Response.Cache.SetETag(eTag);   // required for IE9 resumable downloads
            context.Response.ContentType = mimeType;
            byte[] buffer = new byte[4096];

            if (context.Response.IsClientConnected)
            {
                using (var fileStream = fileContents)
                {
                    if (fileStream.CanSeek)
                    {
                        fileStream.Seek(startIndex, SeekOrigin.Begin);
                    }
                    while (true)
                    {
                        var bytesRead = fileStream.Read(buffer, 0, buffer.Length);
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        if (!context.Response.IsClientConnected)
                        {
                            // quit sending if the client isn't connected
                            break;
                        }

                        try
                        {
                            context.Response.OutputStream.Write(buffer, 0, bytesRead);
                        }
                        catch (HttpException ex)
                        {
                            if (!context.Response.IsClientConnected)
                            {
                                // if client disconnected during the .write, ignore
                            }
                            else
                            {
                                throw ex;
                            }
                        }
                    }
                }
            }

            context.ApplicationInstance.CompleteRequest();
        }
Пример #13
0
        public void ToStringShouldReturnCorrectly()
        {
            var cache = new RockCacheability
            {
                RockCacheablityType = RockCacheablityType.NoStore
            };

            Assert.That.AreEqual("no-store", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.NoCache;
            Assert.That.AreEqual("no-cache", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Public;
            Assert.That.AreEqual("public", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Private;
            Assert.That.AreEqual("private", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Public;
            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("public,max-age=3600", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Private;
            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("private,max-age=3600", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Public;
            cache.MaxAge       = null;
            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("public,s-maxage=3600", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Private;
            cache.MaxAge       = null;
            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("private,s-maxage=3600", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Public;
            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("public,max-age=3600,s-maxage=3600", cache.ToString());

            cache.RockCacheablityType = RockCacheablityType.Private;
            cache.MaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            cache.SharedMaxAge = new TimeInterval {
                Unit = TimeIntervalUnit.Seconds, Value = 3600
            };
            Assert.That.AreEqual("private,max-age=3600,s-maxage=3600", cache.ToString());
        }