public void NoOverlappingRangesThrowException( string ranges, int innerStreamLength, string contentRange ) { // Arrange string data = new String('a', innerStreamLength); byte[] bytes = Encoding.UTF8.GetBytes(data); MemoryStream memStream = new MemoryStream(bytes); RangeHeaderValue range = RangeHeaderValue.Parse(ranges); // Act try { new ByteRangeStreamContent(memStream, range, _expectedMediatype); } catch (InvalidByteRangeException invalidByteRangeException) { ContentRangeHeaderValue expectedContentRange = ContentRangeHeaderValue.Parse( contentRange ); Assert.Equal(expectedContentRange, invalidByteRangeException.ContentRange); } }
public void SingleRangeGeneratesNonMultipartContent( string ranges, int innerStreamLength, string contentRange ) { // Arrange string data = new String('a', innerStreamLength); byte[] bytes = Encoding.UTF8.GetBytes(data); MemoryStream memStream = new MemoryStream(bytes); RangeHeaderValue range = RangeHeaderValue.Parse(ranges); // Act ByteRangeStreamContent rangeContent = new ByteRangeStreamContent( memStream, range, _expectedMediatype ); // Assert Assert.Equal(_expectedMediatype, rangeContent.Headers.ContentType); ContentRangeHeaderValue expectedContentRange = ContentRangeHeaderValue.Parse( contentRange ); Assert.Equal(expectedContentRange, rangeContent.Headers.ContentRange); }
public async Task FileDownloadAsync(DownloadRequest request, HttpRequest httpRequest, HttpResponse httpResponse, CancellationToken cancellationToken = default(CancellationToken)) { var fileModel = await Connection.File.GetAsync(request.FileIdentifier); var organization = await Connection.Organization.GetAsync(request.FileIdentifier as OrganizationIdentifier); var managerModel = ModelConvert(organization, fileModel, connection.UserTimeZone); long?from = 0; long?to = null; httpResponse.Headers[HeaderNames.AcceptRanges] = "bytes"; if (httpRequest.Headers["Range"].Any()) { var range = RangeHeaderValue.Parse(httpRequest.Headers["Range"].ToString()).Ranges.FirstOrDefault(); if (range.From.HasValue) { from = range.From.Value; } if (range.To.HasValue) { to = Math.Max(range.To.Value, 0); } if (to == null) { to = fileModel.Length - 1; } } await ExecuteDownload(request, httpResponse, fileModel, from, to, cancellationToken); }
public void TryParse_Invalid() { RangeHeaderValue res; Assert.IsFalse(RangeHeaderValue.TryParse("bytes=4,33", out res), "#1"); Assert.IsNull(res, "#2"); }
private void CheckInvalidParse(string input) { Assert.Throws <FormatException>(() => { RangeHeaderValue.Parse(input); }); Assert.False(RangeHeaderValue.TryParse(input, out RangeHeaderValue result)); Assert.Null(result); }
/// <summary> /// Create an instance of RangeHeader using RangeHeaderValues /// </summary> /// <param name="values">A collection of RangeHeaderValues that represent upper and lower byte ranges</param> /// <returns></returns> public static RangeHeader Create(RangeHeaderValue value) { var toReturn = new RangeHeader(); toReturn.RawRange = value; return(toReturn); }
public void Parse_Invalid() { try { RangeHeaderValue.Parse(null); Assert.Fail("#1"); } catch (FormatException) { } try { RangeHeaderValue.Parse(" "); Assert.Fail("#2"); } catch (FormatException) { } try { RangeHeaderValue.Parse("5-6"); Assert.Fail("#3"); } catch (FormatException) { } try { RangeHeaderValue.Parse("bytes="); Assert.Fail("#4"); } catch (FormatException) { } }
public void MultipleRangesGeneratesMultipartByteRangesContent(string ranges, int innerStreamLength, int expectedBodyparts, string[] contentRanges) { // Arrange string data = new String('a', innerStreamLength); byte[] bytes = Encoding.UTF8.GetBytes(data); MemoryStream memStream = new MemoryStream(bytes); RangeHeaderValue range = RangeHeaderValue.Parse(ranges); // Act ByteRangeStreamContent content = new ByteRangeStreamContent(memStream, range, _expectedMediatype); MemoryStream result = new MemoryStream(); content.CopyToAsync(result).Wait(); MultipartMemoryStreamProvider multipart = content.ReadAsMultipartAsync().Result; // Assert Assert.Equal(expectedBodyparts, multipart.Contents.Count); for (int count = 0; count < multipart.Contents.Count; count++) { MediaTypeHeaderValue contentType = multipart.Contents[count].Headers.ContentType; Assert.Equal(_expectedMediatype, contentType); ContentRangeHeaderValue expectedContentRange = ContentRangeHeaderValue.Parse(contentRanges[count]); ContentRangeHeaderValue contentRange = multipart.Contents[count].Headers.ContentRange; Assert.Equal(expectedContentRange, contentRange); } }
private void CheckInvalidTryParse(string input) { RangeHeaderValue result = null; Assert.False(RangeHeaderValue.TryParse(input, out result)); Assert.Null(result); }
private void CheckValidTryParse(string input, RangeHeaderValue expectedResult) { RangeHeaderValue result = null; Assert.True(RangeHeaderValue.TryParse(input, out result)); Assert.Equal(expectedResult, result); }
public async Task ReadFileAsync( BackendConfiguration context, string id, Stream stream, long from, long to, long totalLength, CancellationToken cancellationToken = default(CancellationToken) ) { using (var request = Request(context, HttpMethod.Get, $"api/backend", new { id, totalLength })) { var rangeHeader = new RangeHeaderValue(from, to).ToString(); request.Headers.Add("Range", rangeHeader); Logger.LogDebug($"Range Header: {rangeHeader}"); using (var response = await Client.SendAsync( request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { Logger.LogDebug($"Response started: Content-Length: {response.Content.Headers.ContentLength}"); response.EnsureSuccessStatusCode(); using (var responseStream = await response.Content.ReadAsStreamAsync()) await responseStream.CopyToAsync(stream, BUFFER_SIZE, cancellationToken); Logger.LogDebug($"Complete"); } } }
private static void CheckInvalidGetRangeLength(string input, int startIndex) { object result = null; Assert.Equal(0, RangeHeaderValue.GetRangeLength(input, startIndex, out result)); Assert.Null(result); }
public async Task GetWithUnsatisfiableRangeTest() { var ct = CancellationToken.None; var root = await FileSystem.Root; var testFile = await root.CreateDocumentAsync("test1.txt", ct); await FillAsync(testFile, int.MaxValue, ct); using (var client = Server.CreateClient()) { var range = new RangeHeader("bytes", new RangeHeaderItem(_testBlock.Value.Length - 1, _testBlock.Value.Length)); var request = new HttpRequestMessage(HttpMethod.Get, "test1.txt") { Headers = { Range = RangeHeaderValue.Parse(range.ToString()), }, }; using (var response = await client.SendAsync(request, ct)) { Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); } } }
public void Parse() { var res = RangeHeaderValue.Parse("bytes=2-40"); Assert.AreEqual("bytes", res.Unit, "#1"); Assert.AreEqual(2, res.Ranges.First().From, "#2"); Assert.AreEqual(40, res.Ranges.First().To, "#3"); Assert.AreEqual("bytes=2-40", res.ToString(), "#4"); res = RangeHeaderValue.Parse("d-dd = 2 - "); Assert.AreEqual("d-dd", res.Unit, "#10"); Assert.AreEqual(2, res.Ranges.First().From, "#11"); Assert.IsNull(res.Ranges.First().To, "#12"); Assert.AreEqual("d-dd=2-", res.ToString(), "#13"); res = RangeHeaderValue.Parse("zz = - 6 , 5 - 9, -8"); Assert.AreEqual("zz", res.Unit, "#20"); Assert.IsNull(res.Ranges.First().From, "#21"); Assert.AreEqual(6, res.Ranges.First().To, "#22"); Assert.AreEqual(5, res.Ranges.Skip(1).First().From, "#21b"); Assert.AreEqual(9, res.Ranges.Skip(1).First().To, "#22b"); Assert.AreEqual("zz=-6, 5-9, -8", res.ToString(), "#23"); res = RangeHeaderValue.Parse("ddd = 2 -, 1-4"); Assert.AreEqual("ddd", res.Unit, "#30"); Assert.AreEqual(2, res.Ranges.First().From, "#31"); Assert.IsNull(res.Ranges.First().To, "#32"); Assert.AreEqual("ddd=2-, 1-4", res.ToString(), "#33"); }
public void Equals_UseSameAndDifferentRanges_EqualOrNotEqualNoExceptions() { var range1 = new RangeHeaderValue(1, 2); var range2 = new RangeHeaderValue(1, 2); range2.Unit = "BYTES"; var range3 = new RangeHeaderValue(1, null); var range4 = new RangeHeaderValue(null, 2); var range5 = new RangeHeaderValue(); range5.Ranges.Add(new RangeItemHeaderValue(1, 2)); range5.Ranges.Add(new RangeItemHeaderValue(3, 4)); var range6 = new RangeHeaderValue(); range6.Ranges.Add(new RangeItemHeaderValue(3, 4)); // reverse order of range5 range6.Ranges.Add(new RangeItemHeaderValue(1, 2)); var 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"); }
/// <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> /// Sets range header. /// </summary> /// <param name="headers">The http request header.</param> /// <param name="value">The header value.</param> public static void SetRange(this HttpRequestHeaders headers, RangeHeaderValue value) { if (value != null) { headers.Range = value; } }
public async Task Get(string id, long totalLength, CancellationToken cancellationToken = default(CancellationToken)) { Response.Headers.Add("Accept-Ranges", "bytes"); var range = RangeHeaderValue.Parse(Request.Headers["Range"]).Ranges.FirstOrDefault(); if (range == null || range.From == null || range.To == null) { throw new Exception("Missing Range Header"); } long from = range.From.Value; long to = range.To.Value; long contentLength = to - from + 1; Response.ContentLength = contentLength; Logger.LogInformation($"Get: id: {id} from: {from} to: {to} Content-Length {Response.ContentLength}"); Response.StatusCode = 206; await backend.ReadFileAsync(context, id, Response.Body, from, to, totalLength, cancellationToken).ConfigureAwait(false); Logger.LogInformation($"Get: id: {id} complete"); }
/// <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) { }
public override Task <DownloadResult> DownloadAsync(Upload upload, RangeHeaderValue range, CancellationToken cancellationToken) { return(Task.FromResult( new DownloadResult { Stream = File.OpenRead(Path.Combine(_storagePath, upload.Id + upload.Extension)) })); }
public void Parse() { var res = RangeHeaderValue.Parse("bytes=2-40"); Assert.AreEqual("bytes", res.Unit, "#1"); Assert.AreEqual(2, res.Ranges.First().From, "#2"); Assert.AreEqual(40, res.Ranges.First().To, "#3"); }
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 void TryParse() { RangeHeaderValue res; Assert.IsTrue(RangeHeaderValue.TryParse("bytes=4-33", out res), "#1"); Assert.AreEqual("bytes", res.Unit, "#2"); Assert.AreEqual(4, res.Ranges.First().From, "#3"); Assert.AreEqual(33, res.Ranges.First().To, "#4"); }
/// <summary> /// Reads the JSON representation of the object. /// </summary> /// <param name="reader">The <see cref="JsonReader"/> to read from.</param> /// <param name="objectType">Type of the object.</param> /// <param name="existingValue">The existing property value of the JSON that is being converted.</param> /// <param name="serializer">The calling serializer.</param> public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { return(RangeHeaderValue.Parse((string)reader.Value)); } throw new JsonSerializationException(); }
private static bool TryHandleSpecialHeader(HttpWebRequest webRequest, Header header) { if (header.Name.Equals(HeaderNames.Accept)) { webRequest.Accept = header.Value; return(true); } if (header.Name.Equals(HeaderNames.ContentLength)) { return(true); } if (header.Name.Equals(HeaderNames.ContentType)) { webRequest.ContentType = header.Value; return(true); } if (header.Name.Equals(HeaderNames.Host)) { webRequest.Host = header.Value; return(true); } if (header.Name.Equals(HeaderNames.IfModifiedSince)) { webRequest.IfModifiedSince = DateTime.Parse(header.Value); return(true); } if (header.Name.Equals(HeaderNames.Range)) { var ranges = RangeHeaderValue.Parse(header.Value); foreach (var range in ranges.Ranges) { webRequest.AddRange(ranges.Unit, range.From ?? 0, range.To ?? 0); } return(true); } if (header.Name.Equals(HeaderNames.Referer)) { webRequest.Referer = header.Value; return(true); } if (header.Name.Equals(HeaderNames.UserAgent)) { webRequest.UserAgent = header.Value; return(true); } return(false); }
public async Task Should_return_requested_range_not_satisfiable(string range) { //Given & When this.httpClient.DefaultRequestHeaders.Range = RangeHeaderValue.Parse($"bytes={range}"); var response = await this.httpClient.GetAsync("/downloadrange"); //Then Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); }
public static bool IsRangeHeaderCorrect(this HttpRequestHeaders headerCollection, long fileLen) { RangeHeaderValue rangeHeader = headerCollection.Range; bool unitIsNotbytes = rangeHeader.Unit != "bytes"; bool multipleRanges = rangeHeader.Ranges.Count > 1; RangeItemHeaderValue range = rangeHeader.Ranges.First(); bool start_end_fileLen_error = !(range.RangeHeaderStart(fileLen) < fileLen && range.RangeHeaderEnd(fileLen) < fileLen); return(!(unitIsNotbytes || multipleRanges || start_end_fileLen_error)); }
public void Properties_Invalid() { var value = new RangeHeaderValue(); try { value.Unit = ""; Assert.Fail("#1"); } catch (ArgumentException) { } }
/// <summary> /// Write video stream to response body /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <returns></returns> protected async Task WriteVideoStreamToBody(HttpRequest request, HttpResponse response) { var bufferingFeature = response.HttpContext.Features.Get <IHttpBufferingFeature>(); bufferingFeature?.DisableResponseBuffering(); RangeHeaderValue rangeHeader = request.GetTypedHeaders().Range; if (IsRangeRequest(rangeHeader)) { long totalLength = this.FileStream.Length; var range = rangeHeader.Ranges.First(); var start = range.From ?? 0; var end = range.To ?? totalLength - 1; response.Headers.Add("Accept-Ranges", "bytes"); // response.GetTypedHeaders().ContentRange = new ContentRangeHeaderValue(start, end, totalLength); response.Headers.Add("Content-Range", $"bytes {start}-{end}/{totalLength}"); response.ContentLength = end - start + 1; response.StatusCode = StatusCodes.Status206PartialContent; // Read video by range header try { var buffer = new byte[BUFFER_SIZE]; var position = start; var bytesLeft = end - start + 1; this.FileStream.Seek(position, SeekOrigin.Begin); while (position <= end) { var bytesRead = this.FileStream.Read(buffer, 0, (int)Math.Min(bytesLeft, buffer.Length)); await response.Body.WriteAsync(buffer, 0, bytesRead); position += bytesRead; bytesLeft = end - position + 1; } } catch (IndexOutOfRangeException ex) { await response.Body.FlushAsync(); return; } finally { await response.Body.FlushAsync(); } } else { await this.FileStream.CopyToAsync(response.Body); } }
public void TryParse_SetOfValidValueStrings_ParsedCorrectly() { CheckValidTryParse(" bytes=1-2 ", new RangeHeaderValue(1, 2)); var expected = new RangeHeaderValue(); expected.Unit = "custom"; expected.Ranges.Add(new RangeItemHeaderValue(null, 5)); expected.Ranges.Add(new RangeItemHeaderValue(1, 4)); CheckValidTryParse("custom = - 5 , 1 - 4 ,,", expected); }
/// <summary> /// Byte Range Response /// </summary> /// <param name="content">source content stream</param> /// <param name="range">range header</param> /// <param name="mediaType">MIME</param> /// <exception cref="NotSupportedException"></exception> public ByteRangeResponse(Stream content, RangeHeaderValue range, string mediaType) { if (!range.Unit.Equals("BYTES",StringComparison.InvariantCultureIgnoreCase)) { throw new NotSupportedException(); } if (!range.Any()) { throw new ArgumentException("range"); } if (string.IsNullOrEmpty(mediaType)) { mediaType = MimeTypes.GetMimeType("application/octet-stream"); } var contentLength = content.Length - content.Position; var itemCount = range.RangeItemHeaderValues.Count(); if (itemCount == 1) { var rangeItem = range.First(); base.Contents = x => { var temStream = new ByteRangeStream(content, rangeItem); temStream.CopyTo(x); }; base.ContentType = mediaType; base.Headers.Add("Content-Range", $"{range.Unit} {rangeItem.From}-{rangeItem.To}/{contentLength}"); base.StatusCode = HttpStatusCode.PartialContent; } else { throw new NotSupportedException(); } }