예제 #1
0
        public ByteRangeStream(Stream innerStream, RangeItemHeaderValue range)
            : base(innerStream)
        {
            if (range == null)
            {
                throw new ArgumentNullException("range");
            }
            if (!innerStream.CanSeek)
            {
                throw new ArgumentException(RS.Format(Resources.ByteRangeStreamNotSeekable, typeof(ByteRangeStream).Name), "innerStream");
            }
            if (innerStream.Length < 1)
            {
                throw new ArgumentOutOfRangeException("innerStream", innerStream.Length,
                    RS.Format(Resources.ByteRangeStreamEmpty, typeof(ByteRangeStream).Name));
            }
            if (range.From.HasValue && range.From.Value > innerStream.Length)
            {
                throw new ArgumentOutOfRangeException("range", range.From,
                    RS.Format(Resources.ByteRangeStreamInvalidFrom, innerStream.Length));
            }

            // Ranges are inclusive so 0-9 means the first 10 bytes
            long maxLength = innerStream.Length - 1;
            long upperbounds;
            if (range.To.HasValue)
            {
                if (range.From.HasValue)
                {
                    // e.g bytes=0-499 (the first 500 bytes offsets 0-499)
                    upperbounds = Math.Min(range.To.Value, maxLength);
                    _lowerbounds = range.From.Value;
                }
                else
                {
                    // e.g bytes=-500 (the final 500 bytes)
                    upperbounds = maxLength;
                    _lowerbounds = Math.Max(innerStream.Length - range.To.Value, 0);
                }
            }
            else
            {
                if (range.From.HasValue)
                {
                    // e.g bytes=500- (from byte offset 500 and up)
                    upperbounds = maxLength;
                    _lowerbounds = range.From.Value;
                }
                else
                {
                    // e.g. bytes=- (invalid so will never get here)
                    upperbounds = maxLength;
                    _lowerbounds = 0;
                }
            }

            _totalCount = upperbounds - _lowerbounds + 1;
            ContentRange = new ContentRangeHeaderValue(_lowerbounds, upperbounds, innerStream.Length);
        }
 private void Initialize(ContentRangeHeaderValue contentRange)
 {
     if (contentRange == null)
     {
         throw Error.ArgumentNull("contentRange");
     }
     this.ContentRange = contentRange;
 }
예제 #3
0
 private void Initialize(ContentRangeHeaderValue contentRange)
 {
     if (contentRange == null)
     {
         throw new ArgumentNullException("contentRange");
     }
     ContentRange = contentRange;
 }
예제 #4
0
        private ContentRangeHeaderValue(ContentRangeHeaderValue source)
        {
            Contract.Requires(source != null);

            this.from = source.from;
            this.to = source.to;
            this.length = source.length;
            this.unit = source.unit;
        }
 private void CheckValidParsedValue(string input, int startIndex, ContentRangeHeaderValue expectedResult,
     int expectedIndex)
 {
     HttpHeaderParser parser = GenericHeaderParser.ContentRangeParser;
     object result = null;
     Assert.True(parser.TryParseValue(input, null, ref startIndex, out result),
         string.Format("TryParse returned false. Input: '{0}'", input));
     Assert.Equal(expectedIndex, startIndex);
     Assert.Equal(expectedResult, result);
 }
        public void Ctor_FromToAndLengthOverloadValidValues_ValuesCorrectlySet()
        {
            ContentRangeHeaderValue range = new ContentRangeHeaderValue(0, 1, 2);

            Assert.True(range.HasRange);
            Assert.True(range.HasLength);
            Assert.Equal("bytes", range.Unit);
            Assert.Equal(0, range.From);
            Assert.Equal(1, range.To);
            Assert.Equal(2, range.Length);
        }
        public void Ctor_LengthOnlyOverloadValidValues_ValuesCorrectlySet()
        {
            ContentRangeHeaderValue range = new ContentRangeHeaderValue(5);

            Assert.False(range.HasRange);
            Assert.True(range.HasLength);
            Assert.Equal("bytes", range.Unit);
            Assert.Null(range.From);
            Assert.Null(range.To);
            Assert.Equal(5, range.Length);
        }
        public void Unit_GetAndSetValidAndInvalidValues_MatchExpectation()
        {
            ContentRangeHeaderValue range = new ContentRangeHeaderValue(0);
            range.Unit = "myunit";
            Assert.Equal("myunit", range.Unit); // "Unit (custom value)"

            Assert.Throws<ArgumentException>(() => { range.Unit = null; }); // "<null>"
            Assert.Throws<ArgumentException>(() => { range.Unit = ""; }); // "empty string"
            Assert.Throws<FormatException>(() => { range.Unit = " x"; }); // "leading space"
            Assert.Throws<FormatException>(() => { range.Unit = "x "; }); // "trailing space"
            Assert.Throws<FormatException>(() => { range.Unit = "x y"; }); // "invalid token"
        }
        public void Equals()
        {
            var value = new ContentRangeHeaderValue (8);
            Assert.AreEqual (value, new ContentRangeHeaderValue (8), "#1");
            Assert.AreNotEqual (value, new ContentRangeHeaderValue (8, 30), "#2");

            value = new ContentRangeHeaderValue (5, 30, 100);
            Assert.AreEqual (value, new ContentRangeHeaderValue (5, 30, 100), "#3");
            Assert.AreNotEqual (value, new ContentRangeHeaderValue (5, 30, 101), "#4");
            Assert.AreNotEqual (value, new ContentRangeHeaderValue (5, 30), "#5");
            Assert.AreNotEqual (value, new ContentRangeHeaderValue (5, 30, 100) {
                Unit = "g"
            }, "#6");
        }
예제 #10
0
        public void Ctor_SetsContentRange()
        {
            // Arrange
            ContentRangeHeaderValue expectedContentRange = new ContentRangeHeaderValue(5, 9, 20);
            Mock<Stream> mockInnerStream = new Mock<Stream>();
            mockInnerStream.Setup(s => s.CanSeek).Returns(true);
            mockInnerStream.Setup(s => s.Length).Returns(20);
            RangeItemHeaderValue range = new RangeItemHeaderValue(5, 9);

            // Act
            ByteRangeStream rangeStream = new ByteRangeStream(mockInnerStream.Object, range);

            // Assert
            Assert.Equal(expectedContentRange, rangeStream.ContentRange);
        }
예제 #11
0
        private ContentRangeHeaderValue(ContentRangeHeaderValue source)
        {
            Contract.Requires(source != null);

            _from = source._from;
            _to = source._to;
            _length = source._length;
            _unit = source._unit;
        }
예제 #12
0
        private ContentRangeHeaderValue(ContentRangeHeaderValue source)
        {
            Debug.Assert(source != null);

            _from = source._from;
            _to = source._to;
            _length = source._length;
            _unit = source._unit;
        }
예제 #13
0
        public static bool TryParse(string input, out ContentRangeHeaderValue parsedValue)
        {
            parsedValue = null;

            var lexer = new Lexer(input);
            var t     = lexer.Scan();

            if (t != Token.Type.Token)
            {
                return(false);
            }

            var value = new ContentRangeHeaderValue();

            value.unit = lexer.GetStringValue(t);

            t = lexer.Scan();
            if (t != Token.Type.Token)
            {
                return(false);
            }

            int nvalue;

            if (!lexer.IsStarStringValue(t))
            {
                if (!lexer.TryGetNumericValue(t, out nvalue))
                {
                    var s = lexer.GetStringValue(t);
                    if (s.Length < 3)
                    {
                        return(false);
                    }

                    var sep = s.Split('-');
                    if (sep.Length != 2)
                    {
                        return(false);
                    }

                    if (!int.TryParse(sep[0], NumberStyles.None, CultureInfo.InvariantCulture, out nvalue))
                    {
                        return(false);
                    }

                    value.From = nvalue;

                    if (!int.TryParse(sep[1], NumberStyles.None, CultureInfo.InvariantCulture, out nvalue))
                    {
                        return(false);
                    }

                    value.To = nvalue;
                }
                else
                {
                    value.From = nvalue;

                    t = lexer.Scan();
                    if (t != Token.Type.SeparatorDash)
                    {
                        return(false);
                    }

                    t = lexer.Scan();

                    if (!lexer.TryGetNumericValue(t, out nvalue))
                    {
                        return(false);
                    }

                    value.To = nvalue;
                }
            }

            t = lexer.Scan();

            if (t != Token.Type.SeparatorSlash)
            {
                return(false);
            }

            t = lexer.Scan();

            if (!lexer.IsStarStringValue(t))
            {
                if (!lexer.TryGetNumericValue(t, out nvalue))
                {
                    return(false);
                }

                value.Length = nvalue;
            }

            t = lexer.Scan();

            if (t != Token.Type.End)
            {
                return(false);
            }

            parsedValue = value;

            return(true);
        }
        HttpResponseMessage StreamFile(BlobId formatBlobId, FileNameWithExtension fileName = null)
        {
            var descriptor = _blobStore.GetDescriptor(formatBlobId);

            if (descriptor == null)
            {
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("File {0} not found", formatBlobId)
                );
            }

            RangeHeaderValue rangeHeader = Request.Headers.Range;

            var response = Request.CreateResponse(HttpStatusCode.OK);
            response.Headers.AcceptRanges.Add("bytes");

            // HEAD?
            bool isHead = false;
            if (Request.Method == HttpMethod.Head)
            {
                isHead = true;
                rangeHeader = null;
            }

            // full stream
            if (rangeHeader == null || !rangeHeader.Ranges.Any())
            {
                if (isHead)
                {
                    response.Content = new ByteArrayContent(new byte[0]);
                    response.Content.Headers.ContentLength = descriptor.Length;
                }
                else
                {
                    response.Content = new StreamContent(descriptor.OpenRead());
                }

                response.Content.Headers.ContentType = new MediaTypeHeaderValue(descriptor.ContentType);

                if (fileName != null)
                {
                    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                    {
                        FileName = fileName
                    };
                }

                return response;
            }

            // range stream
            long start = 0, end = 0;
            long totalLength = descriptor.Length;

            // 1. If the unit is not 'bytes'.
            // 2. If there are multiple ranges in header value.
            // 3. If start or end position is greater than file length.
            if (rangeHeader.Unit != "bytes" || rangeHeader.Ranges.Count > 1 ||
                !TryReadRangeItem(rangeHeader.Ranges.First(), totalLength, out start, out end))
            {
                response.StatusCode = HttpStatusCode.RequestedRangeNotSatisfiable;
                response.Content = new StreamContent(Stream.Null);  // No content for this status.
                response.Content.Headers.ContentRange = new ContentRangeHeaderValue(totalLength);
                response.Content.Headers.ContentType = new MediaTypeHeaderValue(descriptor.ContentType);

                return response;
            }

            var contentRange = new ContentRangeHeaderValue(start, end, totalLength);

            // We are now ready to produce partial content.
            response.StatusCode = HttpStatusCode.PartialContent;
            response.Content = new PushStreamContent((outputStream, httpContent, transpContext)
            =>
            {
                using (outputStream) // Copy the file to output stream in indicated range.
                using (Stream inputStream = descriptor.OpenRead())
                    CreatePartialContent(inputStream, outputStream, start, end);

            }, descriptor.ContentType);

            response.Content.Headers.ContentType = new MediaTypeHeaderValue(descriptor.ContentType);
            response.Content.Headers.ContentLength = end - start + 1;
            response.Content.Headers.ContentRange = contentRange;

            return response;
        }
        public void CreateErrorResponseRangeNotSatisfiable_SetsCorrectStatusCodeAndContentRangeHeader()
        {
            // Arrange
            HttpRequestMessage request = new HttpRequestMessage();
            ContentRangeHeaderValue expectedContentRange = new ContentRangeHeaderValue(length: 128);
            InvalidByteRangeException invalidByteRangeException = new InvalidByteRangeException(expectedContentRange);

            // Act
            HttpResponseMessage response = request.CreateErrorResponse(invalidByteRangeException);

            // Assert
            Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
            Assert.Same(expectedContentRange, response.Content.Headers.ContentRange);
        }
 public InvalidByteRangeException(ContentRangeHeaderValue contentRange, SerializationInfo info, StreamingContext context)
     : base(info, context)
 {
     this.Initialize(contentRange);
 }
예제 #17
0
 public static bool TryParse(string input, out ContentRangeHeaderValue parsedValue)
 {
 }
        public void CreateErrorResponseRangeNotSatisfiable_SetsCorrectStatusCodeAndContentRangeHeader()
        {
            // Arrange
            var context = new DefaultHttpContext();
            context.RequestServices = CreateServices(new DefaultContentNegotiator());

            var request = CreateRequest(context);

            var expectedContentRange = new ContentRangeHeaderValue(length: 128);
            var invalidByteRangeException = new InvalidByteRangeException(expectedContentRange);

            // Act
            var response = request.CreateErrorResponse(invalidByteRangeException);

            // Assert
            Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
            Assert.Same(expectedContentRange, response.Content.Headers.ContentRange);
        }
        public void ToString_UseDifferentRanges_AllSerializedCorrectly()
        {
            ContentRangeHeaderValue range = new ContentRangeHeaderValue(1, 2, 3);
            range.Unit = "myunit";
            Assert.Equal("myunit 1-2/3", range.ToString()); // "Range with all fields set"

            range = new ContentRangeHeaderValue(123456789012345678, 123456789012345679);
            Assert.Equal("bytes 123456789012345678-123456789012345679/*", range.ToString()); // "Only range, no length"

            range = new ContentRangeHeaderValue(150);
            Assert.Equal("bytes */150", range.ToString()); // "Only length, no range"
        }
예제 #20
0
        public void ContentRange_ReadAndWriteProperty_ValueMatchesPriorSetValue()
        {
            Assert.Null(_headers.ContentRange);
            ContentRangeHeaderValue value = new ContentRangeHeaderValue(1, 2, 3);

            _headers.ContentRange = value;
            Assert.Equal(value, _headers.ContentRange);

            _headers.ContentRange = null;
            Assert.Null(_headers.ContentRange);
        }
예제 #21
0
		public ByteRangeStream(Stream innerStream, RangeItemHeaderValue range)
			: base(innerStream)
		{
			// Ranges are inclusive so 0-9 means the first 10 bytes
			long maxLength = innerStream.Length - 1;
			long upperbounds;
			if (range.To.HasValue)
			{
				if (range.From.HasValue)
				{
					// e.g bytes=0-499 (the first 500 bytes offsets 0-499)
					upperbounds = Math.Min(range.To.Value, maxLength);
					_lowerbounds = range.From.Value;
				}
				else
				{
					// e.g bytes=-500 (the final 500 bytes)
					upperbounds = maxLength;
					_lowerbounds = Math.Max(innerStream.Length - range.To.Value, 0);
				}
			}
			else
			{
				if (range.From.HasValue)
				{
					// e.g bytes=500- (from byte offset 500 and up)
					upperbounds = maxLength;
					_lowerbounds = range.From.Value;
				}
				else
				{
					// e.g. bytes=- (invalid so will never get here)
					upperbounds = maxLength;
					_lowerbounds = 0;
				}
			}

			_totalCount = upperbounds - _lowerbounds + 1;
			ContentRange = new ContentRangeHeaderValue(_lowerbounds, upperbounds, innerStream.Length);
		}
예제 #22
0
        public static bool TryParse(string input, out ContentRangeHeaderValue parsedValue)
        {
            int index = 0;
            object output;
            parsedValue = null;

            if (GenericHeaderParser.ContentRangeParser.TryParseValue(input, null, ref index, out output))
            {
                parsedValue = (ContentRangeHeaderValue)output;
                return true;
            }
            return false;
        }
        public void Properties()
        {
            var value = new ContentRangeHeaderValue (4);
            Assert.IsNull (value.From, "#1");
            Assert.IsTrue (value.HasLength, "#2");
            Assert.IsFalse (value.HasRange, "#3");
            Assert.AreEqual (4, value.Length, "#4");
            Assert.IsNull (value.To, "#5");
            Assert.AreEqual ("bytes", value.Unit, "#6");

            value = new ContentRangeHeaderValue (1, 10, 20);
            value.Unit = "mu";
            Assert.AreEqual (1, value.From, "#11");
            Assert.IsTrue (value.HasLength, "#12");
            Assert.IsTrue (value.HasRange, "#13");
            Assert.AreEqual (20, value.Length, "#14");
            Assert.AreEqual (10, value.To, "#15");
            Assert.AreEqual ("mu", value.Unit, "#16");
        }
        /// <summary>
        /// 依傳入的標頭回傳一個ResponseMessage
        /// 正常來說直接回應給瀏覽器就可以了
        /// this will return a ResponseMessage object
        /// and response to web browser general.
        /// </summary>
        /// <param name="rangeHeader">ApiController's property: Request.Headers.Range</param>
        /// <param name="fileName">video file name, it was getting from request's query string general</param>
        /// <returns>HttpResponseMessage</returns>
        public HttpResponseMessage CreateHttpResponseMessage(RangeHeaderValue rangeHeader, string fileName)
        {
            HttpResponseMessage response = new HttpResponseMessage();

            // This can prevent some unnecessary accesses.
            // These kind of file names won't be existing at all.
            if (string.IsNullOrWhiteSpace(fileName) || AnyInvalidFileNameChars(fileName))
                throw new HttpResponseException(HttpStatusCode.NotFound);

            FileInfo fileInfo = new FileInfo(Path.Combine(InitialDirectory, fileName));

            if (!fileInfo.Exists)
                throw new HttpResponseException(HttpStatusCode.NotFound);

            long totalLength = fileInfo.Length;

            response.Headers.AcceptRanges.Add("bytes");

            // The request will be treated as normal request if there is no Range header.
            if (rangeHeader == null || !rangeHeader.Ranges.Any())
            {
                response.StatusCode = HttpStatusCode.OK;
                response.Content = new PushStreamContent((outputStream, httpContent, transpContext)
                =>
                {
                    using (outputStream) // Copy the file to output stream straightforward.
                    using (Stream inputStream = fileInfo.OpenRead())
                    {
                        try
                        {
                            inputStream.CopyTo(outputStream, ReadStreamBufferSize);
                        }
                        catch (Exception error)
                        {
                            Console.WriteLine(error);
                        }
                    }
                }, GetMimeNameFromExt(fileInfo.Extension));

                response.Content.Headers.ContentLength = totalLength;
                return response;
            }

            long start = 0, end = 0;

            // 1. If the unit is not 'bytes'.
            // 2. If there are multiple ranges in header value.
            // 3. If start or end position is greater than file length.
            if (rangeHeader.Unit != "bytes" || rangeHeader.Ranges.Count > 1 ||
                !TryReadRangeItem(rangeHeader.Ranges.First(), totalLength, out start, out end))
            {
                response.StatusCode = HttpStatusCode.RequestedRangeNotSatisfiable;
                response.Content = new StreamContent(Stream.Null);  // No content for this status.
                response.Content.Headers.ContentRange = new ContentRangeHeaderValue(totalLength);
                response.Content.Headers.ContentType = GetMimeNameFromExt(fileInfo.Extension);

                return response;
            }

            var contentRange = new ContentRangeHeaderValue(start, end, totalLength);

            // We are now ready to produce partial content.
            response.StatusCode = HttpStatusCode.PartialContent;
            response.Content = new PushStreamContent((outputStream, httpContent, transpContext)
            =>
            {
                using (outputStream) // Copy the file to output stream in indicated range.
                using (Stream inputStream = fileInfo.OpenRead())
                    CreatePartialContent(inputStream, outputStream, start, end);

            }, GetMimeNameFromExt(fileInfo.Extension));

            response.Content.Headers.ContentLength = end - start + 1;
            response.Content.Headers.ContentRange = contentRange;

            return response;
        }
예제 #25
0
        private static bool TryCreateContentRange(string input, string unit, int fromStartIndex, int fromLength,
            int toStartIndex, int toLength, int lengthStartIndex, int lengthLength, out object parsedValue)
        {
            parsedValue = null;

            long from = 0;
            if ((fromLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(fromStartIndex, fromLength), out from))
            {
                return false;
            }

            long to = 0;
            if ((toLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(toStartIndex, toLength), out to))
            {
                return false;
            }

            // 'from' must not be greater than 'to'
            if ((fromLength > 0) && (toLength > 0) && (from > to))
            {
                return false;
            }

            long length = 0;
            if ((lengthLength > 0) && !HeaderUtilities.TryParseInt64(input.Substring(lengthStartIndex, lengthLength),
                out length))
            {
                return false;
            }

            // 'from' and 'to' must be less than 'length'
            if ((toLength > 0) && (lengthLength > 0) && (to >= length))
            {
                return false;
            }

            ContentRangeHeaderValue result = new ContentRangeHeaderValue();
            result._unit = unit;

            if (fromLength > 0)
            {
                result._from = from;
                result._to = to;
            }

            if (lengthLength > 0)
            {
                result._length = length;
            }

            parsedValue = result;
            return true;
        }
예제 #26
0
        /// <summary>
        /// <see cref="HttpContent"/> implementation which provides a byte range view over a stream used to generate HTTP
        /// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend 
        /// of the selected resource represented by the <paramref name="content"/> parameter then an 
        /// <see cref="InvalidByteRangeException"/> is thrown indicating the valid Content-Range of the content. 
        /// </summary>
        /// <param name="content">The stream over which to generate a byte range view.</param>
        /// <param name="range">The range or ranges, typically obtained from the Range HTTP request header field.</param>
        /// <param name="mediaType">The media type of the content stream.</param>
        /// <param name="bufferSize">The buffer size used when copying the content stream.</param>
        public ByteRangeStreamContent(Stream content, RangeHeaderValue range, MediaTypeHeaderValue mediaType, int bufferSize)
        {
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            if (!content.CanSeek)
            {
                throw new ArgumentException("content", RS.Format(Resources.ByteRangeStreamNotSeekable, typeof(ByteRangeStreamContent).Name));
            }
            if (range == null)
            {
                throw new ArgumentNullException("range");
            }
            if (mediaType == null)
            {
                throw new ArgumentNullException("mediaType");
            }
            if (bufferSize < MinBufferSize)
            {
                throw new ArgumentOutOfRangeException("bufferSize", bufferSize, RS.Format(Resources.ArgumentMustBeGreaterThanOrEqualTo, MinBufferSize));
            }
            if (!range.Unit.Equals(SupportedRangeUnit, StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException(RS.Format(Resources.ByteRangeStreamContentNotBytesRange, range.Unit, SupportedRangeUnit), "range");
            }

            try
            {
                // If we have more than one range then we use a multipart/byteranges content type as wrapper.
                // Otherwise we use a non-multipart response.
                if (range.Ranges.Count > 1)
                {
                    // Create Multipart content and copy headers to this content
                    MultipartContent rangeContent = new MultipartContent(ByteRangesContentSubtype);
                    _byteRangeContent = rangeContent;

                    foreach (RangeItemHeaderValue rangeValue in range.Ranges)
                    {
                        try
                        {
                            ByteRangeStream rangeStream = new ByteRangeStream(content, rangeValue);
                            HttpContent rangeBodyPart = new StreamContent(rangeStream, bufferSize);
                            rangeBodyPart.Headers.ContentType = mediaType;
                            rangeBodyPart.Headers.ContentRange = rangeStream.ContentRange;
                            rangeContent.Add(rangeBodyPart);
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            // We ignore range errors until we check that we have at least one valid range
                        }
                    }

                    // If no overlapping ranges were found then stop
                    if (!rangeContent.Any())
                    {
                        ContentRangeHeaderValue actualContentRange = new ContentRangeHeaderValue(content.Length);
                        string msg = RS.Format(Resources.ByteRangeStreamNoneOverlap, range.ToString());
                        throw new InvalidByteRangeException(actualContentRange, msg);
                    }
                }
                else if (range.Ranges.Count == 1)
                {
                    try
                    {
                        ByteRangeStream rangeStream = new ByteRangeStream(content, range.Ranges.First());
                        _byteRangeContent = new StreamContent(rangeStream, bufferSize);
                        _byteRangeContent.Headers.ContentType = mediaType;
                        _byteRangeContent.Headers.ContentRange = rangeStream.ContentRange;
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        ContentRangeHeaderValue actualContentRange = new ContentRangeHeaderValue(content.Length);
                        string msg = RS.Format(Resources.ByteRangeStreamNoOverlap, range.ToString());
                        throw new InvalidByteRangeException(actualContentRange, msg);
                    }
                }
                else
                {
                    throw new ArgumentException(Resources.ByteRangeStreamContentNoRanges, "range");
                }

                // Copy headers from byte range content so that we get the right content type etc.
                foreach (KeyValuePair<string, IEnumerable<string>> header in _byteRangeContent.Headers)
                {
                    Headers.TryAddWithoutValidation(header.Key, header.Value);
                }

                _content = content;
                _start = content.Position;
            }
            catch
            {
                if (_byteRangeContent != null)
                {
                    _byteRangeContent.Dispose();
                }
                throw;
            }
        }
예제 #27
0
			/// <summary>
			/// <see cref="HttpContent"/> implementation which provides a byte range view over a stream used to generate HTTP
			/// 206 (Partial Content) byte range responses. If none of the requested ranges overlap with the current extend 
			/// of the selected resource represented by the <paramref name="content"/> parameter then an 
			/// <see cref="InvalidByteRangeException"/> is thrown indicating the valid Content-Range of the content. 
			/// </summary>
			/// <param name="content">The stream over which to generate a byte range view.</param>
			/// <param name="range">The range or ranges, typically obtained from the Range HTTP request header field.</param>
			/// <param name="mediaType">The media type of the content stream.</param>
			/// <param name="bufferSize">The buffer size used when copying the content stream.</param>
			public ByteRangeStreamContent(Stream content, RangeHeaderValue range, MediaTypeHeaderValue mediaType, int bufferSize)
			{

				try
				{
					// If we have more than one range then we use a multipart/byteranges content type as wrapper.
					// Otherwise we use a non-multipart response.
					if (range.Ranges.Count > 1)
					{
						// Create Multipart content and copy headers to this content
						MultipartContent rangeContent = new MultipartContent(ByteRangesContentSubtype);
						_byteRangeContent = rangeContent;

						foreach (RangeItemHeaderValue rangeValue in range.Ranges)
						{
							try
							{
								ByteRangeStream rangeStream = new ByteRangeStream(content, rangeValue);
								HttpContent rangeBodyPart = new StreamContent(rangeStream, bufferSize);
								rangeBodyPart.Headers.ContentType = mediaType;
								rangeBodyPart.Headers.ContentRange = rangeStream.ContentRange;
								rangeContent.Add(rangeBodyPart);
							}
							catch (ArgumentOutOfRangeException)
							{
								// We ignore range errors until we check that we have at least one valid range
							}
						}

						// If no overlapping ranges were found then stop
						if (!rangeContent.Any())
						{
							ContentRangeHeaderValue actualContentRange = new ContentRangeHeaderValue(content.Length);
							string msg = "ByteRangeStreamNoneOverlap";
							throw new InvalidByteRangeException(actualContentRange, msg);
						}
					}
					else if (range.Ranges.Count == 1)
					{
						try
						{
							ByteRangeStream rangeStream = new ByteRangeStream(content, range.Ranges.First());
							_byteRangeContent = new StreamContent(rangeStream, bufferSize);
							_byteRangeContent.Headers.ContentType = mediaType;
							_byteRangeContent.Headers.ContentRange = rangeStream.ContentRange;
						}
						catch (ArgumentOutOfRangeException)
						{
							ContentRangeHeaderValue actualContentRange = new ContentRangeHeaderValue(content.Length);
							string msg = "ByteRangeStreamNoOverlap";
							throw new InvalidByteRangeException(actualContentRange, msg);
						}
					}
					else
					{
						throw new ArgumentException("range");
					}

					// Copy headers from byte range content so that we get the right content type etc.
					_byteRangeContent.Headers.CopyTo(Headers);

					_content = content;
					_start = content.Position;
				}
				catch
				{
					if (_byteRangeContent != null)
					{
						_byteRangeContent.Dispose();
					}
					throw;
				}
			}
 public void Ctor_SetsContentRange()
 {
     ContentRangeHeaderValue contentRange = new ContentRangeHeaderValue(0, 20, 100);
     InvalidByteRangeException invalidByteRangeException = new InvalidByteRangeException(contentRange);
     Assert.Same(contentRange, invalidByteRangeException.ContentRange);
 }
예제 #29
0
        public void ContentRange_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
        {
            _headers.TryAddWithoutValidation("Content-Range", "custom 1-2/*");

            ContentRangeHeaderValue value = new ContentRangeHeaderValue(1, 2);
            value.Unit = "custom";

            Assert.Equal(value, _headers.ContentRange);
        }
 public InvalidByteRangeException(ContentRangeHeaderValue contentRange)
 {
     this.Initialize(contentRange);
 }
예제 #31
0
		public static bool TryParse (string input, out ContentRangeHeaderValue parsedValue)
		{
			parsedValue = null;

			var lexer = new Lexer (input);
			var t = lexer.Scan ();
			if (t != Token.Type.Token)
				return false;

			var value = new ContentRangeHeaderValue ();
			value.unit = lexer.GetStringValue (t);

			t = lexer.Scan ();
			if (t != Token.Type.Token)
				return false;

			int nvalue;
			if (!lexer.IsStarStringValue (t)) {
				if (!lexer.TryGetNumericValue (t, out nvalue)) {
					var s = lexer.GetStringValue (t);
					if (s.Length < 3)
						return false;

					var sep = s.Split ('-');
					if (sep.Length != 2)
						return false;

					if (!int.TryParse (sep[0], NumberStyles.None, CultureInfo.InvariantCulture, out nvalue))
						return false;

					value.From = nvalue;

					if (!int.TryParse (sep[1], NumberStyles.None, CultureInfo.InvariantCulture, out nvalue))
						return false;

					value.To = nvalue;
				} else {
					value.From = nvalue;

					t = lexer.Scan (recognizeDash: true);
					if (t != Token.Type.SeparatorDash)
						return false;

					t = lexer.Scan ();

					if (!lexer.TryGetNumericValue (t, out nvalue))
						return false;

					value.To = nvalue;
				}
			}

			t = lexer.Scan ();

			if (t != Token.Type.SeparatorSlash)
				return false;

			t = lexer.Scan ();

			if (!lexer.IsStarStringValue (t)) {
				long lvalue;
				if (!lexer.TryGetNumericValue (t, out lvalue))
					return false;

				value.Length = lvalue;
			}

			t = lexer.Scan ();

			if (t != Token.Type.End)
				return false;

			parsedValue = value;
 
			return true;
		}
 public InvalidByteRangeException(ContentRangeHeaderValue contentRange, string message, Exception innerException)
     : base(message, innerException)
 {
     this.Initialize(contentRange);
 }