private RangeHeaderValue (RangeHeaderValue source) : this () { if (source.ranges != null) { foreach (var item in source.ranges) Ranges.Add (item); } }
public void TryParse_SetOfValidValueStrings_ParsedCorrectly() { CheckValidParsedValue("X bytes=1-2 ", 1, new RangeHeaderValue(1, 2), 12); RangeHeaderValue expected = new RangeHeaderValue(); expected.Unit = "custom"; expected.Ranges.Add(new RangeItemHeaderValue(null, 5)); expected.Ranges.Add(new RangeItemHeaderValue(1, 4)); CheckValidParsedValue("custom = - 5 , 1 - 4 ,,", 0, expected, 24); }
private void CheckValidParsedValue(string input, int startIndex, RangeHeaderValue expectedResult, int expectedIndex) { HttpHeaderParser parser = GenericHeaderParser.RangeParser; 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_ThrowsOnNullContent() { RangeHeaderValue range = new RangeHeaderValue(); Assert.ThrowsArgumentNull(() => new ByteRangeStreamContent( content: null, range: range, mediaType: _expectedMediatype, bufferSize: 128), "content"); }
private RangeHeaderValue(RangeHeaderValue source) : this() { if (source.ranges != null) { foreach (var item in source.ranges) { Ranges.Add(item); } } }
public void ToString_UseDifferentRanges_AllSerializedCorrectly() { RangeHeaderValue range = new RangeHeaderValue(); range.Unit = "myunit"; range.Ranges.Add(new RangeItemHeaderValue(1, 3)); Assert.Equal("myunit=1-3", range.ToString()); range.Ranges.Add(new RangeItemHeaderValue(5, null)); range.Ranges.Add(new RangeItemHeaderValue(null, 17)); Assert.Equal("myunit=1-3, 5-, -17", range.ToString()); }
public void Unit_GetAndSetValidAndInvalidValues_MatchExpectation() { RangeHeaderValue range = new RangeHeaderValue(); range.Unit = "myunit"; Assert.Equal("myunit", range.Unit); Assert.Throws<ArgumentException>(() => { range.Unit = null; }); Assert.Throws<ArgumentException>(() => { range.Unit = ""; }); Assert.Throws<FormatException>(() => { range.Unit = " x"; }); Assert.Throws<FormatException>(() => { range.Unit = "x "; }); Assert.Throws<FormatException>(() => { range.Unit = "x y"; }); }
public void Equals () { var value = new RangeHeaderValue (4, null); Assert.AreEqual (value, new RangeHeaderValue (4, null), "#1"); Assert.AreNotEqual (value, new RangeHeaderValue (4, 5), "#2"); Assert.AreNotEqual (value, new RangeHeaderValue (), "#3"); value = new RangeHeaderValue (2, 4); Assert.AreEqual (value, new RangeHeaderValue (2, 4), "#4"); Assert.AreNotEqual (value, new RangeHeaderValue (2, null), "#5"); Assert.AreNotEqual (value, new RangeHeaderValue (2, 3), "#6"); }
public override bool Equals(object obj) { RangeHeaderValue other = obj as RangeHeaderValue; if (other == null) { return(false); } return(string.Equals(_unit, other._unit, StringComparison.OrdinalIgnoreCase) && HeaderUtilities.AreEqualCollections(_ranges, other._ranges)); }
private RangeHeaderValue(RangeHeaderValue source) { Debug.Assert(source != null); _unit = source._unit; if (source._ranges != null) { foreach (RangeItemHeaderValue range in source._ranges) { this.Ranges.Add(new RangeItemHeaderValue(range)); } } }
private RangeHeaderValue(RangeHeaderValue source) { Debug.Assert(source != null); _unit = source._unit; if (source._ranges != null) { foreach (RangeItemHeaderValue range in source._ranges) { this.Ranges.Add((RangeItemHeaderValue)((ICloneable)range).Clone()); } } }
private RangeHeaderValue(RangeHeaderValue source) { Debug.Assert(source != null); _unit = source._unit; if (source._ranges != null) { foreach (RangeItemHeaderValue range in source._ranges) { this.Ranges.Add((RangeItemHeaderValue)((ICloneable)range).Clone()); } } }
private RangeHeaderValue(RangeHeaderValue source) { Contract.Requires(source != null); _unit = source._unit; if (source._ranges != null) { foreach (RangeItemHeaderValue range in source._ranges) { this.Ranges.Add((RangeItemHeaderValue)((ICloneable)range).Clone()); } } }
private RangeHeaderValue(RangeHeaderValue source) { Contract.Requires(source != null); _unit = source._unit; if (source._ranges != null) { foreach (RangeItemHeaderValue range in source._ranges) { this.Ranges.Add((RangeItemHeaderValue)((ICloneable)range).Clone()); } } }
public static bool TryParse(string input, out RangeHeaderValue parsedValue) { int index = 0; object output; parsedValue = null; if (GenericHeaderParser.RangeParser.TryParseValue(input, null, ref index, out output)) { parsedValue = (RangeHeaderValue)output; return(true); } return(false); }
public void Ctor_ThrowsIfCantSeekContent() { // Arrange Mock<Stream> mockInnerStream = new Mock<Stream>(); mockInnerStream.Setup(s => s.CanSeek).Returns(false); RangeHeaderValue range = new RangeHeaderValue(); // Act/Assert Assert.ThrowsArgument(() => new ByteRangeStreamContent( content: mockInnerStream.Object, range: range, mediaType: _expectedMediatype, bufferSize: 128), "content"); }
internal static int GetRangeLength(string input, int startIndex, out object parsedValue) { Contract.Requires(startIndex >= 0); parsedValue = null; if (string.IsNullOrEmpty(input) || (startIndex >= input.Length)) { return(0); } // Parse the unit string: <unit> in '<unit>=<from1>-<to1>, <from2>-<to2>' int unitLength = HttpRuleParser.GetTokenLength(input, startIndex); if (unitLength == 0) { return(0); } RangeHeaderValue result = new RangeHeaderValue(); result._unit = input.Substring(startIndex, unitLength); int current = startIndex + unitLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); if ((current == input.Length) || (input[current] != '=')) { return(0); } current++; // skip '=' separator current = current + HttpRuleParser.GetWhitespaceLength(input, current); int rangesLength = RangeItemHeaderValue.GetRangeItemListLength(input, current, result.Ranges); if (rangesLength == 0) { return(0); } current = current + rangesLength; Debug.Assert(current == input.Length, "GetRangeItemListLength() should consume the whole string or fail."); parsedValue = result; return(current - startIndex); }
public override void OnActionExecuting(HttpActionContext actionContext) { if(!actionContext.ActionDescriptor.ReturnType.IsGenericType || actionContext.ActionDescriptor.ReturnType.GetGenericTypeDefinition()!=typeof(IEnumerable<>)) { throw new InvalidOperationException("Return type must be IEnumerable<T>."); } else { _elementType = actionContext.ActionDescriptor.ReturnType.GetGenericArguments()[0]; } _requestRangeHeader = actionContext.Request.Headers.Range; if (_requestRangeHeader!=null && _requestRangeHeader.Unit != EnityRangeUnit) throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable)); base.OnActionExecuting(actionContext); }
public void GetHashCode_UseSameAndDifferentRanges_SameOrDifferentHashCodes() { RangeHeaderValue range1 = new RangeHeaderValue(1, 2); RangeHeaderValue range2 = new RangeHeaderValue(1, 2); range2.Unit = "BYTES"; RangeHeaderValue range3 = new RangeHeaderValue(1, null); RangeHeaderValue range4 = new RangeHeaderValue(null, 2); RangeHeaderValue range5 = new RangeHeaderValue(); range5.Ranges.Add(new RangeItemHeaderValue(1, 2)); range5.Ranges.Add(new RangeItemHeaderValue(3, 4)); RangeHeaderValue range6 = new RangeHeaderValue(); range6.Ranges.Add(new RangeItemHeaderValue(3, 4)); // reverse order of range5 range6.Ranges.Add(new RangeItemHeaderValue(1, 2)); Assert.Equal(range1.GetHashCode(), range2.GetHashCode()); Assert.NotEqual(range1.GetHashCode(), range3.GetHashCode()); Assert.NotEqual(range1.GetHashCode(), range4.GetHashCode()); Assert.NotEqual(range1.GetHashCode(), range5.GetHashCode()); Assert.Equal(range5.GetHashCode(), range6.GetHashCode()); }
public void Equals_UseSameAndDifferentRanges_EqualOrNotEqualNoExceptions() { RangeHeaderValue range1 = new RangeHeaderValue(1, 2); RangeHeaderValue range2 = new RangeHeaderValue(1, 2); range2.Unit = "BYTES"; RangeHeaderValue range3 = new RangeHeaderValue(1, null); RangeHeaderValue range4 = new RangeHeaderValue(null, 2); RangeHeaderValue range5 = new RangeHeaderValue(); range5.Ranges.Add(new RangeItemHeaderValue(1, 2)); range5.Ranges.Add(new RangeItemHeaderValue(3, 4)); RangeHeaderValue range6 = new RangeHeaderValue(); range6.Ranges.Add(new RangeItemHeaderValue(3, 4)); // reverse order of range5 range6.Ranges.Add(new RangeItemHeaderValue(1, 2)); RangeHeaderValue range7 = new RangeHeaderValue(1, 2); range7.Unit = "other"; Assert.False(range1.Equals(null), "bytes=1-2 vs. <null>"); Assert.True(range1.Equals(range2), "bytes=1-2 vs. BYTES=1-2"); Assert.False(range1.Equals(range3), "bytes=1-2 vs. bytes=1-"); Assert.False(range1.Equals(range4), "bytes=1-2 vs. bytes=-2"); Assert.False(range1.Equals(range5), "bytes=1-2 vs. bytes=1-2,3-4"); Assert.True(range5.Equals(range6), "bytes=1-2,3-4 vs. bytes=3-4,1-2"); Assert.False(range1.Equals(range7), "bytes=1-2 vs. other=1-2"); }
public void Clone_Call_CloneFieldsMatchSourceFields() { RangeHeaderValue source = new RangeHeaderValue(1, 2); RangeHeaderValue clone = (RangeHeaderValue)((ICloneable)source).Clone(); Assert.Equal(1, source.Ranges.Count); Assert.Equal(source.Unit, clone.Unit); Assert.Equal(source.Ranges.Count, clone.Ranges.Count); Assert.Equal(source.Ranges.ElementAt(0), clone.Ranges.ElementAt(0)); source.Unit = "custom"; source.Ranges.Add(new RangeItemHeaderValue(3, null)); source.Ranges.Add(new RangeItemHeaderValue(null, 4)); clone = (RangeHeaderValue)((ICloneable)source).Clone(); Assert.Equal(3, source.Ranges.Count); Assert.Equal(source.Unit, clone.Unit); Assert.Equal(source.Ranges.Count, clone.Ranges.Count); Assert.Equal(source.Ranges.ElementAt(0), clone.Ranges.ElementAt(0)); Assert.Equal(source.Ranges.ElementAt(1), clone.Ranges.ElementAt(1)); Assert.Equal(source.Ranges.ElementAt(2), clone.Ranges.ElementAt(2)); }
public void Properties () { var value = new RangeHeaderValue (3, 9); Assert.AreEqual ("bytes", value.Unit, "#1"); Assert.AreEqual (3, value.Ranges.First ().From, "#2"); Assert.AreEqual (9, value.Ranges.First ().To, "#3"); value = new RangeHeaderValue (); Assert.AreEqual ("bytes", value.Unit, "#4"); Assert.AreEqual (0, value.Ranges.Count, "#5"); }
public void Properties_Invalid () { var value = new RangeHeaderValue (); try { value.Unit = ""; Assert.Fail ("#1"); } catch (ArgumentException) { } }
public static bool TryParse(string input, out RangeHeaderValue parsedValue) { parsedValue = null; var lexer = new Lexer(input); var t = lexer.Scan(); if (t != Token.Type.Token) { return(false); } var value = new RangeHeaderValue(); value.unit = lexer.GetStringValue(t); t = lexer.Scan(); if (t != Token.Type.SeparatorEqual) { return(false); } bool token_read; do { int?from = null, to = null; int number; token_read = false; t = lexer.Scan(); switch (t.Kind) { case Token.Type.SeparatorDash: t = lexer.Scan(); if (!lexer.TryGetNumericValue(t, out number)) { return(false); } to = number; break; case Token.Type.Token: string s = lexer.GetStringValue(t); var values = s.Split(new [] { '-' }, StringSplitOptions.RemoveEmptyEntries); if (!int.TryParse(values[0], out number)) { return(false); } switch (values.Length) { case 1: t = lexer.Scan(); from = number; switch (t.Kind) { case Token.Type.SeparatorDash: t = lexer.Scan(); if (t != Token.Type.Token) { token_read = true; break; } if (!lexer.TryGetNumericValue(t, out number)) { return(false); } to = number; if (to < from) { return(false); } break; case Token.Type.End: if (s.Length > 0 && s [s.Length - 1] != '-') { return(false); } token_read = true; break; case Token.Type.SeparatorComma: token_read = true; break; default: return(false); } break; case 2: from = number; if (!int.TryParse(values[1], out number)) { return(false); } to = number; if (to < from) { return(false); } break; default: return(false); } break; default: return(false); } value.Ranges.Add(new RangeItemHeaderValue(from, to)); if (!token_read) { t = lexer.Scan(); } } while (t == Token.Type.SeparatorComma); if (t != Token.Type.End) { return(false); } parsedValue = value; return(true); }
private static void CallGetRangeLength(string input, int startIndex, int expectedLength, out RangeHeaderValue result) { object temp = null; Assert.Equal(expectedLength, RangeHeaderValue.GetRangeLength(input, startIndex, out temp)); result = temp as RangeHeaderValue; }
public static bool TryParse (string input, out RangeHeaderValue parsedValue) { parsedValue = null; var lexer = new Lexer (input); var t = lexer.Scan (); if (t != Token.Type.Token) return false; var value = new RangeHeaderValue (); value.unit = lexer.GetStringValue (t); t = lexer.Scan (); if (t != Token.Type.SeparatorEqual) return false; bool token_read; do { int? from = null, to = null; int number; token_read = false; t = lexer.Scan (); switch (t.Kind) { case Token.Type.SeparatorDash: t = lexer.Scan (); if (!lexer.TryGetNumericValue (t, out number)) return false; to = number; break; case Token.Type.Token: string s = lexer.GetStringValue (t); var values = s.Split (new [] { '-' }, StringSplitOptions.RemoveEmptyEntries); if (!int.TryParse (values[0], out number)) return false; switch (values.Length) { case 1: t = lexer.Scan (); switch (t.Kind) { case Token.Type.SeparatorDash: from = number; t = lexer.Scan (); if (t != Token.Type.Token) { token_read = true; break; } if (!lexer.TryGetNumericValue (t, out number)) return false; to = number; if (to < from) return false; break; default: return false; } break; case 2: from = number; if (!int.TryParse (values[1], out number)) return false; to = number; if (to < from) return false; break; default: return false; } break; default: return false; } value.Ranges.Add (new RangeItemHeaderValue (from, to)); if (!token_read) t = lexer.Scan (); } while (t == Token.Type.SeparatorComma); if (t != Token.Type.End) return false; parsedValue = value; return true; }
public void Range_ReadAndWriteProperty_ValueMatchesPriorSetValue() { Assert.Null(headers.Range); RangeHeaderValue value = new RangeHeaderValue(1, 2); headers.Range = value; Assert.Equal(value, headers.Range); headers.Range = null; Assert.Null(headers.Range); }
public static bool TryParse(string input, out RangeHeaderValue parsedValue) { int index = 0; object output; parsedValue = null; if (GenericHeaderParser.RangeParser.TryParseValue(input, null, ref index, out output)) { parsedValue = (RangeHeaderValue)output; return true; } return false; }
/// <summary> /// Runs an HttpClient issuing sample requests against controller using Range requests. /// </summary> static void RunClient() { HttpClient client = new HttpClient(); client.BaseAddress = new Uri(_baseAddress, "/api/range"); // Get the full content without any ranges using (HttpResponseMessage response = client.GetAsync("").Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Full Content without ranges: '{0}'\n", content); } // Get the first byte HttpRequestMessage firstByteRequest = new HttpRequestMessage(); firstByteRequest.Headers.Range = new RangeHeaderValue(0, 0); using (HttpResponseMessage response = client.SendAsync(firstByteRequest).Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Range '{0}' requesting the first byte: '{1}'\n", firstByteRequest.Headers.Range, content); } // Get the last byte HttpRequestMessage lastByteRequest = new HttpRequestMessage(); lastByteRequest.Headers.Range = new RangeHeaderValue(null, 1); using (HttpResponseMessage response = client.SendAsync(lastByteRequest).Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Range '{0}' requesting the last byte: '{1}'\n", lastByteRequest.Headers.Range, content); } // Get from byte 4 and up HttpRequestMessage fourAndUpByteRequest = new HttpRequestMessage(); fourAndUpByteRequest.Headers.Range = new RangeHeaderValue(4, null); using (HttpResponseMessage response = client.SendAsync(fourAndUpByteRequest).Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Range '{0}' requesting byte 4 and up: '{1}'\n", fourAndUpByteRequest.Headers.Range, content); } // Get the first and the last byte HttpRequestMessage firstAndLastByteRequest = new HttpRequestMessage(); RangeHeaderValue firstAndLastByteRange = new RangeHeaderValue(); firstAndLastByteRange.Ranges.Add(new RangeItemHeaderValue(0, 0)); firstAndLastByteRange.Ranges.Add(new RangeItemHeaderValue(null, 1)); firstAndLastByteRequest.Headers.Range = firstAndLastByteRange; using (HttpResponseMessage response = client.SendAsync(firstAndLastByteRequest).Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Range '{0}' requesting first and last byte:\n{1}\n", firstAndLastByteRange, content); } // Get the first, mid four, and the last byte HttpRequestMessage firstMidAndLastByteRequest = new HttpRequestMessage(); RangeHeaderValue firstMidAndLastByteRange = new RangeHeaderValue(); firstMidAndLastByteRange.Ranges.Add(new RangeItemHeaderValue(0, 0)); firstMidAndLastByteRange.Ranges.Add(new RangeItemHeaderValue(12, 15)); firstMidAndLastByteRange.Ranges.Add(new RangeItemHeaderValue(null, 1)); firstMidAndLastByteRequest.Headers.Range = firstMidAndLastByteRange; using (HttpResponseMessage response = client.SendAsync(firstMidAndLastByteRequest).Result) { response.EnsureSuccessStatusCode(); string content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("Range '{0}' requesting first, mid four, and last byte:\n{1}\n", firstMidAndLastByteRange, content); } // Ask for a non-matching range (byte 100 and up) HttpRequestMessage nonMatchingByteRequest = new HttpRequestMessage(); nonMatchingByteRequest.Headers.Range = new RangeHeaderValue(100, null); using (HttpResponseMessage response = client.SendAsync(nonMatchingByteRequest).Result) { Console.WriteLine("Range '{0}' resulted in status code '{1}' with Content-Range header '{2}'", nonMatchingByteRequest.Headers.Range, response.StatusCode, response.Content.Headers.ContentRange); } }
/// <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; } }
/// <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> public ByteRangeStreamContent(Stream content, RangeHeaderValue range, MediaTypeHeaderValue mediaType) : this(content, range, mediaType, DefaultBufferSize) { }
/// <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, string mediaType, int bufferSize) : this(content, range, new MediaTypeHeaderValue(mediaType), bufferSize) { }
private void CheckValidTryParse(string input, RangeHeaderValue expectedResult) { RangeHeaderValue result = null; Assert.True(RangeHeaderValue.TryParse(input, out result)); Assert.Equal(expectedResult, result); }
public static bool TryParse(string input, out RangeHeaderValue parsedValue) { throw new NotImplementedException(); }
private RangeItemHeaderValue GetRange(string rangeHeader) { return(RangeHeaderValue.Parse(rangeHeader).Ranges.FirstOrDefault()); }
public static bool TryParse(string input, out RangeHeaderValue parsedValue) { }
private void CheckValidParse(string input, RangeHeaderValue expectedResult) { RangeHeaderValue result = RangeHeaderValue.Parse(input); Assert.Equal(expectedResult, result); }
public void Range_UseAddMethod_AddedValueCanBeRetrievedUsingProperty() { headers.TryAddWithoutValidation("Range", "custom= , ,1-2, -4 , "); RangeHeaderValue value = new RangeHeaderValue(); value.Unit = "custom"; value.Ranges.Add(new RangeItemHeaderValue(1, 2)); value.Ranges.Add(new RangeItemHeaderValue(null, 4)); Assert.Equal(value, headers.Range); }
/// <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; }
internal static int GetRangeLength(string input, int startIndex, out object parsedValue) { Debug.Assert(startIndex >= 0); parsedValue = null; if (string.IsNullOrEmpty(input) || (startIndex >= input.Length)) { return 0; } // Parse the unit string: <unit> in '<unit>=<from1>-<to1>, <from2>-<to2>' int unitLength = HttpRuleParser.GetTokenLength(input, startIndex); if (unitLength == 0) { return 0; } RangeHeaderValue result = new RangeHeaderValue(); result._unit = input.Substring(startIndex, unitLength); int current = startIndex + unitLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); if ((current == input.Length) || (input[current] != '=')) { return 0; } current++; // skip '=' separator current = current + HttpRuleParser.GetWhitespaceLength(input, current); int rangesLength = RangeItemHeaderValue.GetRangeItemListLength(input, current, result.Ranges); if (rangesLength == 0) { return 0; } current = current + rangesLength; Debug.Assert(current == input.Length, "GetRangeItemListLength() should consume the whole string or fail."); parsedValue = result; return current - startIndex; }
/// <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; } }