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 void RangesOverZeroLengthStream(string ranges) { // Arrange RangeHeaderValue range = RangeHeaderValue.Parse(ranges); // Act try { new ByteRangeStreamContent(Stream.Null, range, _expectedMediatype); } catch (InvalidByteRangeException invalidByteRangeException) { ContentRangeHeaderValue expectedContentRange = new ContentRangeHeaderValue( length: 0 ); Assert.Equal(expectedContentRange, invalidByteRangeException.ContentRange); } }
public void GetHashCode_UseSameAndDifferentRanges_SameOrDifferentHashCodes() { ContentRangeHeaderValue range1 = new ContentRangeHeaderValue(1, 2, 5); ContentRangeHeaderValue range2 = new ContentRangeHeaderValue(1, 2); ContentRangeHeaderValue range3 = new ContentRangeHeaderValue(5); ContentRangeHeaderValue range4 = new ContentRangeHeaderValue(1, 2, 5); range4.Unit = "BYTES"; ContentRangeHeaderValue range5 = new ContentRangeHeaderValue(1, 2, 5); range5.Unit = "myunit"; Assert.NotEqual(range1.GetHashCode(), range2.GetHashCode()); // "bytes 1-2/5 vs. bytes 1-2/*" Assert.NotEqual(range1.GetHashCode(), range3.GetHashCode()); // "bytes 1-2/5 vs. bytes */5" Assert.NotEqual(range2.GetHashCode(), range3.GetHashCode()); // "bytes 1-2/* vs. bytes */5" Assert.Equal(range1.GetHashCode(), range4.GetHashCode()); // "bytes 1-2/5 vs. BYTES 1-2/5" Assert.NotEqual(range1.GetHashCode(), range5.GetHashCode()); // "bytes 1-2/5 vs. myunit 1-2/5" }
public async Task TestResponseContentHeaders() { var mock = new MockHttpClient(); var currentDate = DateTime.UtcNow; var expectedExpires = new DateTimeOffset(currentDate.AddSeconds(60)); var expectedByteArray = new byte[] { 65 }; var expected = new ByteArrayContent(expectedByteArray); expected.Headers.Allow.Add("GET"); expected.Headers.Allow.Add("POST"); expected.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse("attachment"); expected.Headers.ContentLength = expectedByteArray.Length; expected.Headers.ContentLocation = new Uri("https://example.com"); expected.Headers.ContentRange = ContentRangeHeaderValue.Parse("bytes 200-1000/67589"); expected.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain"); expected.Headers.ContentMD5 = new byte[] { 1 }; expected.Headers.ContentLanguage.Add("en-US"); expected.Headers.ContentEncoding.Add("gzip"); expected.Headers.Expires = expectedExpires; expected.Headers.LastModified = currentDate; mock.SetupGet("/").ReturnsAsync(content: expected); var result = await mock.Object.GetAsync("/"); var resultByteArray = await result.Content.ReadAsByteArrayAsync(); Assert.Equal(expectedByteArray, resultByteArray); Assert.Equal("GET, POST", result.Content.Headers.Allow.ToString()); Assert.Equal("attachment", result.Content.Headers.ContentDisposition.ToString()); Assert.Equal(expectedByteArray.Length, result.Content.Headers.ContentLength); Assert.Equal("https://example.com/", result.Content.Headers.ContentLocation.AbsoluteUri); Assert.Equal("bytes 200-1000/67589", result.Content.Headers.ContentRange.ToString()); Assert.Equal("text/plain", result.Content.Headers.ContentType.ToString()); Assert.Equal(new byte[] { 1 }, result.Content.Headers.ContentMD5); Assert.Equal("en-US", result.Content.Headers.ContentLanguage.ToString()); Assert.Equal("gzip", result.Content.Headers.ContentEncoding.ToString()); Assert.NotNull(result.Content.Headers.Expires); Assert.NotNull(result.Content.Headers.LastModified); Assert.Equal(expectedExpires.ToString("s"), result.Content.Headers.Expires.Value.ToString("s")); Assert.Equal(currentDate.ToString("s"), result.Content.Headers.LastModified.Value.ToString("s")); }
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { // Arrange var contentType = "text/plain"; var lastModified = DateTimeOffset.MinValue; var entityTag = new EntityTagHeaderValue("\"Etag\""); var byteArray = Encoding.ASCII.GetBytes("Hello World"); var readStream = new MemoryStream(byteArray); readStream.SetLength(11); var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfMatch = new[] { new EntityTagHeaderValue("\"Etag\""), }; requestHeaders.Range = new RangeHeaderValue(0, 4); requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); // Act await ExecuteAsync(httpContext, readStream, contentType, lastModified, entityTag, enableRangeProcessing : true); // Assert var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(lastModified.ToString("R"), httpResponse.Headers.LastModified); Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.Equal(5, httpResponse.ContentLength); Assert.Equal("Hello", body); Assert.False(readStream.CanSeek); }
public async Task WriteFileAsync_RangeRequested_FileLengthZeroOrNull(long?fileLength) { // Arrange var contentType = "text/plain"; var lastModified = new DateTimeOffset(); var entityTag = new EntityTagHeaderValue("\"Etag\""); var byteArray = Encoding.ASCII.GetBytes(""); var readStream = new MemoryStream(byteArray); fileLength = fileLength ?? 0L; readStream.SetLength(fileLength.Value); var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(0, 5); requestHeaders.IfMatch = new[] { new EntityTagHeaderValue("\"Etag\""), }; httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); // Act await ExecuteAsync(httpContext, readStream, contentType, lastModified, entityTag, enableRangeProcessing : true); // Assert var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(lastModified.ToString("R"), httpResponse.Headers.LastModified); Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); var contentRange = new ContentRangeHeaderValue(byteArray.Length); Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.Equal(0, httpResponse.ContentLength); Assert.Empty(body); Assert.False(readStream.CanSeek); }
public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long?start, long?end, string expectedString, long contentLength) { // Arrange var contentType = "text/plain"; var lastModified = new DateTimeOffset(); var entityTag = new EntityTagHeaderValue("\"Etag\""); var byteArray = Encoding.ASCII.GetBytes("Hello World"); var readStream = new MemoryStream(byteArray); readStream.SetLength(11); var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(start, end); requestHeaders.IfMatch = new[] { new EntityTagHeaderValue("\"Etag\""), }; httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); // Act await ExecuteAsync(httpContext, readStream, contentType, lastModified, entityTag, enableRangeProcessing : true); // Assert start = start ?? 11 - end; end = start + contentLength - 1; var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers.LastModified); Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.Equal(contentLength, httpResponse.ContentLength); Assert.Equal(expectedString, body); Assert.False(readStream.CanSeek); }
public static async Task WriteFileAsync_WritesRangeRequested <TContext>( long?start, long?end, string expectedString, long contentLength, Func <PhysicalFileResult, TContext, Task> function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); result.EnableRangeProcessing = true; var sendFile = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set <IHttpResponseBodyFeature>(sendFile); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; requestHeaders.Range = new RangeHeaderValue(start, end); httpContext.Request.Method = HttpMethods.Get; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; await function(result, (TContext)context); // Assert var startResult = start ?? 34 - end; var endResult = startResult + contentLength - 1; var httpResponse = actionContext.HttpContext.Response; var contentRange = new ContentRangeHeaderValue(startResult.Value, endResult.Value, 34); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(contentLength, httpResponse.ContentLength); Assert.Equal(Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")), sendFile.Name); Assert.Equal(startResult, sendFile.Offset); Assert.Equal((long?)contentLength, sendFile.Length); }
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 async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) { // Arrange var contentType = "text/plain"; var lastModified = new DateTimeOffset(); var entityTag = new EntityTagHeaderValue("\"Etag\""); var byteArray = Encoding.ASCII.GetBytes("Hello World"); var readStream = new MemoryStream(byteArray); var result = new FileStreamResult(readStream, contentType) { LastModified = lastModified, EntityTag = entityTag, EnableRangeProcessing = true, }; var httpContext = GetHttpContext(); httpContext.Request.Headers[HeaderNames.Range] = rangeString; httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert var httpResponse = actionContext.HttpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(byteArray.Length); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(body); Assert.False(readStream.CanSeek); }
public async Task WriteFileAsync_WritesRangeRequested( long?start, long?end, long contentLength) { // Arrange var path = Path.GetFullPath("helllo.txt"); var contentType = "text/plain; charset=us-ascii; p1=p1-value"; var appEnvironment = new Mock <IWebHostEnvironment>(); appEnvironment.Setup(app => app.WebRootFileProvider) .Returns(GetFileProvider(path)); var sendFileFeature = new TestSendFileFeature(); var httpContext = GetHttpContext(GetFileProvider(path)); httpContext.Features.Set <IHttpResponseBodyFeature>(sendFileFeature); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(start, end); requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); httpContext.Request.Method = HttpMethods.Get; // Act await ExecuteAsync(httpContext, path, contentType, enableRangeProcessing : true); // Assert var startResult = start ?? 33 - end; var endResult = startResult + contentLength - 1; var httpResponse = httpContext.Response; var contentRange = new ContentRangeHeaderValue(startResult.Value, endResult.Value, 33); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(contentLength, httpResponse.ContentLength); Assert.Equal(path, sendFileFeature.Name); Assert.Equal(startResult, sendFileFeature.Offset); Assert.Equal((long?)contentLength, sendFileFeature.Length); }
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"); }
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 static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange <TContext>( Func <PhysicalFileResult, TContext, Task> function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); result.EnableRangeProcessing = true; var sendFile = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set <IHttpResponseBodyFeature>(sendFile); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; requestHeaders.Range = new RangeHeaderValue(0, 3); requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); httpContext.Request.Method = HttpMethods.Get; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); var contentRange = new ContentRangeHeaderValue(0, 3, 34); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); Assert.Equal(4, httpResponse.ContentLength); Assert.Equal(Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")), sendFile.Name); Assert.Equal(0, sendFile.Offset); Assert.Equal(4, sendFile.Length); }
public void Parse() { var res = ContentRangeHeaderValue.Parse("bytes 0 - 499/ 1234"); Assert.AreEqual(0, res.From, "#1"); Assert.AreEqual(499, res.To, "#2"); Assert.AreEqual(1234, res.Length, "#3"); Assert.AreEqual("bytes 0-499/1234", res.ToString(), "#4"); res = ContentRangeHeaderValue.Parse("bytes */ 8"); Assert.IsNull(res.From, "#11"); Assert.IsNull(res.To, "#12"); Assert.AreEqual(8, res.Length, "#13"); Assert.AreEqual("bytes */8", res.ToString(), "#14"); res = ContentRangeHeaderValue.Parse("by */*"); Assert.IsNull(res.From, "#21"); Assert.IsNull(res.To, "#22"); Assert.IsNull(res.Length, "#23"); Assert.AreEqual("by */*", res.ToString(), "#24"); }
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { // Arrange var path = Path.GetFullPath("helllo.txt"); var contentType = "text/plain; charset=us-ascii; p1=p1-value"; var appEnvironment = new Mock <IWebHostEnvironment>(); appEnvironment.Setup(app => app.WebRootFileProvider) .Returns(GetFileProvider(path)); var sendFileFeature = new TestSendFileFeature(); var httpContext = GetHttpContext(GetFileProvider(path)); httpContext.Features.Set <IHttpResponseBodyFeature>(sendFileFeature); var entityTag = new EntityTagHeaderValue("\"Etag\""); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; requestHeaders.Range = new RangeHeaderValue(0, 3); requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); httpContext.Request.Method = HttpMethods.Get; // Act await ExecuteAsync(httpContext, path, contentType, entityTag : entityTag, enableRangeProcessing : true); // Assert var httpResponse = httpContext.Response; Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); var contentRange = new ContentRangeHeaderValue(0, 3, 33); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); Assert.Equal(4, httpResponse.ContentLength); Assert.Equal(path, sendFileFeature.Name); Assert.Equal(0, sendFileFeature.Offset); Assert.Equal(4, sendFileFeature.Length); }
public async Task 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(); await content.CopyToAsync(result); MultipartMemoryStreamProvider multipart = await content.ReadAsMultipartAsync(); // 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); } }
public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long?start, long?end, long contentLength) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); var sendFile = new TestSendFileFeature(); var httpContext = GetHttpContext(GetFileProvider(path)); httpContext.Features.Set <IHttpResponseBodyFeature>(sendFile); var appEnvironment = new Mock <IWebHostEnvironment>(); appEnvironment.Setup(app => app.WebRootFileProvider) .Returns(GetFileProvider(path)); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(start, end); requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); httpContext.Request.Method = HttpMethods.Get; // Act await ExecuteAsync(httpContext, path, "text/plain", enableRangeProcessing : true); // Assert start = start ?? 33 - end; end = start + contentLength - 1; var httpResponse = httpContext.Response; Assert.Equal(Path.Combine("TestFiles", "FilePathResultTestFile.txt"), sendFile.Name); Assert.Equal(start, sendFile.Offset); Assert.Equal(contentLength, sendFile.Length); Assert.Equal(CancellationToken.None, sendFile.Token); var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 33); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(contentLength, httpResponse.ContentLength); }
public void GetContentRangeLength_DifferentValidScenarios_AllReturnNonZero() { ContentRangeHeaderValue result = null; CallGetContentRangeLength("bytes 1-2/3", 0, 11, out result); Assert.Equal("bytes", result.Unit); Assert.Equal(1, result.From); Assert.Equal(2, result.To); Assert.Equal(3, result.Length); Assert.True(result.HasRange); Assert.True(result.HasLength); CallGetContentRangeLength(" custom 1234567890123456789-1234567890123456799/*", 1, 48, out result); Assert.Equal("custom", result.Unit); Assert.Equal(1234567890123456789, result.From); Assert.Equal(1234567890123456799, result.To); Assert.Null(result.Length); Assert.True(result.HasRange); Assert.False(result.HasLength); // Note that the final space should be skipped by GetContentRangeLength() and be considered by the returned // value. CallGetContentRangeLength(" custom * / 123 ", 1, 15, out result); Assert.Equal("custom", result.Unit); Assert.Null(result.From); Assert.Null(result.To); Assert.Equal(123, result.Length); Assert.False(result.HasRange); Assert.True(result.HasLength); // Note that we don't have a public constructor for value 'bytes */*' since the RFC doesn't mention a // scenario for it. However, if a server returns this value, we're flexible and accept it. CallGetContentRangeLength("bytes */*", 0, 9, out result); Assert.Equal("bytes", result.Unit); Assert.Null(result.From); Assert.Null(result.To); Assert.Null(result.Length); Assert.False(result.HasRange); Assert.False(result.HasLength); }
public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long?start, long?end, long contentLength) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); result.EnableRangeProcessing = true; var sendFile = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set <IHttpSendFileFeature>(sendFile); var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(start, end); requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); httpContext.Request.Method = HttpMethods.Get; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert start = start ?? 34 - end; end = start + contentLength - 1; var httpResponse = actionContext.HttpContext.Response; Assert.Equal(Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")), sendFile.Name); Assert.Equal(start, sendFile.Offset); Assert.Equal(contentLength, sendFile.Length); Assert.Equal(CancellationToken.None, sendFile.Token); var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 34); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(contentLength, httpResponse.ContentLength); }
public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { // Arrange var path = Path.GetFullPath("helllo.txt"); var contentType = "text/plain; charset=us-ascii; p1=p1-value"; var appEnvironment = new Mock <IWebHostEnvironment>(); appEnvironment.Setup(app => app.WebRootFileProvider) .Returns(GetFileProvider(path)); var httpContext = GetHttpContext(GetFileProvider(path)); httpContext.Response.Body = new MemoryStream(); var requestHeaders = httpContext.Request.GetTypedHeaders(); httpContext.Request.Headers.Range = rangeString; requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); // Act await ExecuteAsync(httpContext, path, contentType, enableRangeProcessing : true); // Assert var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(33); Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(0, httpResponse.ContentLength); Assert.Empty(body); }
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); result.EnableRangeProcessing = true; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; requestHeaders.Range = new RangeHeaderValue(0, 3); requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert var httpResponse = actionContext.HttpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); var contentRange = new ContentRangeHeaderValue(0, 3, 34); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal(4, httpResponse.ContentLength); Assert.Equal("File", body); }
public static async Task WriteFileAsync_RangeRequestedNotSatisfiable <TContext>( string rangeString, Func <PhysicalFileResult, TContext, Task> function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); result.EnableRangeProcessing = true; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; httpContext.Request.Headers.Range = rangeString; httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(34); Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Equal(0, httpResponse.ContentLength); Assert.Empty(body); }
/// <summary> /// Copies content headers. /// </summary> /// <param name="httpContent">Http content.</param> /// <param name="headerCollection">Header collection.</param> private static void CopyContentHeader(HttpContent httpContent, WebHeaderCollection headerCollection) { if (headerCollection["Content-Disposition"] != null) { httpContent.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(headerCollection["Content-Disposition"]); } if (headerCollection[HttpRequestHeader.ContentLocation] != null) { httpContent.Headers.ContentLocation = new Uri(headerCollection[HttpRequestHeader.ContentLocation]); } if (headerCollection[HttpRequestHeader.ContentRange] != null) { httpContent.Headers.ContentRange = ContentRangeHeaderValue.Parse(headerCollection[HttpRequestHeader.ContentRange]); } if (headerCollection[HttpRequestHeader.ContentType] != null) { httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse(headerCollection[HttpRequestHeader.ContentType]); } if (headerCollection[HttpRequestHeader.Expires] != null) { httpContent.Headers.Expires = DateTimeOffset.Parse(headerCollection[HttpRequestHeader.Expires], CultureInfo.InvariantCulture); } if (headerCollection[HttpRequestHeader.LastModified] != null) { httpContent.Headers.LastModified = DateTimeOffset.Parse(headerCollection[HttpRequestHeader.LastModified], CultureInfo.InvariantCulture); } if (headerCollection[HttpRequestHeader.ContentLength] != null) { httpContent.Headers.ContentLength = long.Parse(headerCollection[HttpRequestHeader.ContentLength], CultureInfo.InvariantCulture); } }
/// <summary> /// Perform the WebDAV call and fire the callback when finished. /// </summary> /// <param name="uri"></param> /// <param name="headers"></param> /// <param name="method"></param> /// <param name="content"></param> private async Task <HttpResponseMessage> HttpUploadRequest(Uri uri, HttpMethod method, Stream content, IDictionary <string, string> headers = null, long?startbytes = null, long?endbytes = null, long?totalLength = null) { using (var request = new HttpRequestMessage(method, uri)) { request.Headers.Connection.Add("Keep-Alive"); if (!string.IsNullOrWhiteSpace(UserAgent)) { request.Headers.UserAgent.Add(new ProductInfoHeaderValue(UserAgent, UserAgentVersion)); } else { request.Headers.UserAgent.Add(new ProductInfoHeaderValue("WebDAVClient", AssemblyVersion)); } if (headers != null) { foreach (string key in headers.Keys) { request.Headers.Add(key, headers[key]); } } // Need to send along content? if (content != null) { request.Content = new StreamContent(content); if (startbytes.HasValue && endbytes.HasValue) { var len = totalLength.HasValue ? totalLength.ToString() : "*"; request.Content.Headers.ContentRange = ContentRangeHeaderValue.Parse($"bytes {startbytes}-{endbytes}/{len}"); request.Content.Headers.ContentLength = endbytes - startbytes + 1; } } return(await _httpClientWrapper.SendUploadAsync(request).ConfigureAwait(false)); } }
public async Task WriteFileAsync_WritesRangeRequested(long?start, long?end, string expectedString, long contentLength) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); var result = new TestPhysicalFileResult(path, "text/plain"); result.EnableRangeProcessing = true; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; requestHeaders.Range = new RangeHeaderValue(start, end); httpContext.Request.Method = HttpMethods.Get; httpContext.Response.Body = new MemoryStream(); var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert start = start ?? 34 - end; end = start + contentLength - 1; var httpResponse = actionContext.HttpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 34); Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(contentLength, httpResponse.ContentLength); Assert.Equal(expectedString, body); }
public HttpResponseMessage Play(string filePath) { if (string.IsNullOrWhiteSpace(filePath)) { throw new HttpResponseException(HttpStatusCode.NotFound); } var fileInfo = new FileInfo(filePath); if (!fileInfo.Exists) { throw new HttpResponseException(HttpStatusCode.NotFound); } string val; if (!MimeNames.TryGetValue(Path.GetExtension(filePath), out val)) { fileInfo = new FileInfo(Path.ChangeExtension(filePath, ".mp4")); if (!fileInfo.Exists) { var fileName = Conversion.RemuxVideoToMp4(filePath, true); fileInfo = new FileInfo(fileName); } } var totalLength = fileInfo.Length; var rangeHeader = Request.Headers.Range; var response = new HttpResponseMessage(); 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) { Debug.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); }
/// <summary> /// Returns ContentRange from headers. /// </summary> /// <param name="headers">Headers collection</param> /// <returns>ContentRange object</returns> public static ContentRangeHeaderValue GetContentRange(this WebHeaderCollection headers) { Contract.Requires(headers != null); return(ContentRangeHeaderValue.Parse(headers["Content-Range"])); }
private void CheckInvalidParse(string input) { Assert.Throws <FormatException>(() => { ContentRangeHeaderValue.Parse(input); }); }
private void CheckValidParse(string input, ContentRangeHeaderValue expectedResult) { ContentRangeHeaderValue result = ContentRangeHeaderValue.Parse(input); Assert.Equal(expectedResult, result); }