Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit b4eca8d

Browse files
committed
Do not serve response body for HEAD requests
1 parent b196708 commit b4eca8d

File tree

3 files changed

+167
-22
lines changed

3 files changed

+167
-22
lines changed

src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ private static PreconditionState GetMaxPreconditionState(params PreconditionStat
295295
{
296296
var response = context.HttpContext.Response;
297297
var httpResponseHeaders = response.GetTypedHeaders();
298+
var serveBody = !HttpMethods.IsHead(context.HttpContext.Request.Method);
298299

299300
// Range may be null for empty range header, invalid ranges, parsing errors, multiple ranges
300301
// and when the file length is zero.
@@ -306,7 +307,7 @@ private static PreconditionState GetMaxPreconditionState(params PreconditionStat
306307

307308
if (!isRangeRequest)
308309
{
309-
return (range: null, rangeLength: 0, serveBody: true);
310+
return (range: null, rangeLength: 0, serveBody);
310311
}
311312

312313
// Requested range is not satisfiable
@@ -330,7 +331,7 @@ private static PreconditionState GetMaxPreconditionState(params PreconditionStat
330331
// Overwrite the Content-Length header for valid range requests with the range length.
331332
var rangeLength = SetContentLength(response, range);
332333

333-
return (range, rangeLength, serveBody: true);
334+
return (range, rangeLength, serveBody);
334335
}
335336

336337
private static long SetContentLength(HttpResponse response, RangeItemHeaderValue range)

test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
using Microsoft.AspNetCore.Http;
88
using Microsoft.AspNetCore.Mvc.Abstractions;
99
using Microsoft.AspNetCore.Mvc.Infrastructure;
10-
using Microsoft.AspNetCore.Mvc.Internal;
1110
using Microsoft.AspNetCore.Routing;
1211
using Microsoft.AspNetCore.Testing.xunit;
1312
using Microsoft.Extensions.DependencyInjection;
1413
using Microsoft.Extensions.Logging;
1514
using Microsoft.Extensions.Logging.Abstractions;
16-
using Microsoft.Extensions.Logging.Testing;
1715
using Microsoft.Net.Http.Headers;
1816
using Moq;
1917
using Xunit;

test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs

Lines changed: 164 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using System;
54
using System.Net;
65
using System.Net.Http;
76
using System.Net.Http.Headers;
87
using System.Threading.Tasks;
9-
using Microsoft.AspNetCore.Mvc.Infrastructure;
108
using Microsoft.AspNetCore.Testing.xunit;
119
using Xunit;
1210

@@ -189,11 +187,13 @@ public async Task FileFromDisk_ReturnsFileWithFileName()
189187
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
190188
}
191189

192-
[Fact]
193-
public async Task FileFromDisk_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
190+
[Theory]
191+
[InlineData("GET", "This is a sample text file")]
192+
[InlineData("HEAD", "")]
193+
public async Task FileFromDisk_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored(string httpMethod, string expectedBody)
194194
{
195195
// Arrange
196-
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromDiskWithFileName");
196+
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), "http://localhost/DownloadFiles/DownloadFromDiskWithFileName");
197197
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
198198

199199
// Act
@@ -204,7 +204,7 @@ public async Task FileFromDisk_ReturnsFileWithFileName_RangeProcessingNotEnabled
204204
Assert.NotNull(response.Content.Headers.ContentType);
205205
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
206206
var body = await response.Content.ReadAsStringAsync();
207-
Assert.Equal("This is a sample text file", body);
207+
Assert.Equal(expectedBody, body);
208208
}
209209

210210
[Fact]
@@ -246,6 +246,41 @@ public async Task FileFromDisk_ReturnsFileWithFileName_IfRangeHeaderInvalid_Rang
246246
Assert.Equal("This is a sample text file", body);
247247
}
248248

249+
[Theory]
250+
[InlineData("", HttpStatusCode.OK)]
251+
[InlineData("bytes = 0-6", HttpStatusCode.PartialContent)]
252+
[InlineData("bytes = 17-25", HttpStatusCode.PartialContent)]
253+
[InlineData("bytes = 0-50", HttpStatusCode.PartialContent)]
254+
[InlineData("0-6", HttpStatusCode.OK)]
255+
[InlineData("bytes = ", HttpStatusCode.OK)]
256+
[InlineData("bytes = 1-4, 5-11", HttpStatusCode.OK)]
257+
[InlineData("bytes = 35-36", HttpStatusCode.RequestedRangeNotSatisfiable)]
258+
[InlineData("bytes = -0", HttpStatusCode.RequestedRangeNotSatisfiable)]
259+
public async Task FileFromDisk_ReturnsFileWithFileName_DoesNotServeBody_ForHeadRequest_WithLastModifiedAndEtag(string rangeString, HttpStatusCode httpStatusCode)
260+
{
261+
// Arrange
262+
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, "http://localhost/DownloadFiles/DownloadFromDiskWithFileName_WithLastModifiedAndEtag");
263+
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
264+
httpRequestMessage.Headers.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
265+
266+
// Act
267+
var response = await Client.SendAsync(httpRequestMessage);
268+
269+
// Assert
270+
Assert.Equal(httpStatusCode, response.StatusCode);
271+
272+
Assert.NotNull(response.Content.Headers.ContentType);
273+
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
274+
275+
var body = await response.Content.ReadAsStringAsync();
276+
Assert.NotNull(body);
277+
Assert.Equal(string.Empty, body);
278+
279+
var contentDisposition = response.Content.Headers.ContentDisposition.ToString();
280+
Assert.NotNull(contentDisposition);
281+
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
282+
}
283+
249284
[Fact]
250285
public async Task FileFromStream_ReturnsFile()
251286
{
@@ -347,11 +382,13 @@ public async Task FileFromStream_ReturnsFileWithFileName()
347382
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
348383
}
349384

350-
[Fact]
351-
public async Task FileFromStream_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
385+
[Theory]
386+
[InlineData("GET", "This is sample text from a stream")]
387+
[InlineData("HEAD", "")]
388+
public async Task FileFromStream_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored(string httpMethod, string expectedBody)
352389
{
353390
// Arrange
354-
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromStreamWithFileName");
391+
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), "http://localhost/DownloadFiles/DownloadFromStreamWithFileName");
355392
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
356393

357394
// Act
@@ -362,7 +399,7 @@ public async Task FileFromStream_ReturnsFileWithFileName_RangeProcessingNotEnabl
362399
Assert.NotNull(response.Content.Headers.ContentType);
363400
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
364401
var body = await response.Content.ReadAsStringAsync();
365-
Assert.Equal("This is sample text from a stream", body);
402+
Assert.Equal(expectedBody, body);
366403
}
367404

368405
[Fact]
@@ -402,6 +439,41 @@ public async Task FileFromStream_ReturnsFileWithFileName_IfRangeHeaderInvalid_Ra
402439
Assert.Equal("This is sample text from a stream", body);
403440
}
404441

442+
[Theory]
443+
[InlineData("", HttpStatusCode.OK)]
444+
[InlineData("bytes = 0-6", HttpStatusCode.PartialContent)]
445+
[InlineData("bytes = 17-25", HttpStatusCode.PartialContent)]
446+
[InlineData("bytes = 0-50", HttpStatusCode.PartialContent)]
447+
[InlineData("0-6", HttpStatusCode.OK)]
448+
[InlineData("bytes = ", HttpStatusCode.OK)]
449+
[InlineData("bytes = 1-4, 5-11", HttpStatusCode.OK)]
450+
[InlineData("bytes = 35-36", HttpStatusCode.RequestedRangeNotSatisfiable)]
451+
[InlineData("bytes = -0", HttpStatusCode.RequestedRangeNotSatisfiable)]
452+
public async Task FileFromStream_ReturnsFileWithFileName_DoesNotServeBody_ForHeadRequest(string rangeString, HttpStatusCode httpStatusCode)
453+
{
454+
// Arrange
455+
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, "http://localhost/DownloadFiles/DownloadFromStreamWithFileName_WithEtag");
456+
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
457+
httpRequestMessage.Headers.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
458+
459+
// Act
460+
var response = await Client.SendAsync(httpRequestMessage);
461+
462+
// Assert
463+
Assert.Equal(httpStatusCode, response.StatusCode);
464+
465+
Assert.NotNull(response.Content.Headers.ContentType);
466+
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
467+
468+
var body = await response.Content.ReadAsStringAsync();
469+
Assert.NotNull(body);
470+
Assert.Equal(string.Empty, body);
471+
472+
var contentDisposition = response.Content.Headers.ContentDisposition.ToString();
473+
Assert.NotNull(contentDisposition);
474+
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
475+
}
476+
405477
[Fact]
406478
public async Task FileFromBinaryData_ReturnsFile()
407479
{
@@ -506,11 +578,13 @@ public async Task FileFromBinaryData_ReturnsFileWithFileName()
506578
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
507579
}
508580

509-
[Fact]
510-
public async Task FileFromBinaryData_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
581+
[Theory]
582+
[InlineData("GET", "This is a sample text from a binary array")]
583+
[InlineData("HEAD", "")]
584+
public async Task FileFromBinaryData_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored(string httpMethod, string expectedBody)
511585
{
512586
// Arrange
513-
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName");
587+
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName");
514588
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
515589

516590
// Act
@@ -521,7 +595,7 @@ public async Task FileFromBinaryData_ReturnsFileWithFileName_RangeProcessingNotE
521595
Assert.NotNull(response.Content.Headers.ContentType);
522596
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
523597
var body = await response.Content.ReadAsStringAsync();
524-
Assert.Equal("This is a sample text from a binary array", body);
598+
Assert.Equal(expectedBody, body);
525599
}
526600

527601
[Fact]
@@ -563,6 +637,41 @@ public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderInvali
563637
Assert.Equal("This is a sample text from a binary array", body);
564638
}
565639

640+
[Theory]
641+
[InlineData("", HttpStatusCode.OK)]
642+
[InlineData("bytes = 0-6", HttpStatusCode.PartialContent)]
643+
[InlineData("bytes = 17-25", HttpStatusCode.PartialContent)]
644+
[InlineData("bytes = 0-50", HttpStatusCode.PartialContent)]
645+
[InlineData("0-6", HttpStatusCode.OK)]
646+
[InlineData("bytes = ", HttpStatusCode.OK)]
647+
[InlineData("bytes = 1-4, 5-11", HttpStatusCode.OK)]
648+
[InlineData("bytes = 45-46", HttpStatusCode.RequestedRangeNotSatisfiable)]
649+
[InlineData("bytes = -0", HttpStatusCode.RequestedRangeNotSatisfiable)]
650+
public async Task FileFromBinaryData_ReturnsFileWithFileName_DoesNotServeBody_ForHeadRequest(string rangeString, HttpStatusCode httpStatusCode)
651+
{
652+
// Arrange
653+
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName_WithEtag");
654+
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
655+
httpRequestMessage.Headers.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
656+
657+
// Act
658+
var response = await Client.SendAsync(httpRequestMessage);
659+
660+
// Assert
661+
Assert.Equal(httpStatusCode, response.StatusCode);
662+
663+
Assert.NotNull(response.Content.Headers.ContentType);
664+
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
665+
666+
var body = await response.Content.ReadAsStringAsync();
667+
Assert.NotNull(body);
668+
Assert.Equal(string.Empty, body);
669+
670+
var contentDisposition = response.Content.Headers.ContentDisposition.ToString();
671+
Assert.NotNull(contentDisposition);
672+
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
673+
}
674+
566675
[Fact]
567676
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName()
568677
{
@@ -612,11 +721,13 @@ public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeRequest
612721
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
613722
}
614723

615-
[Fact]
616-
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
724+
[Theory]
725+
[InlineData("GET", "Sample text file as embedded resource.")]
726+
[InlineData("HEAD", "")]
727+
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored(string httpMethod, string expectedBody)
617728
{
618729
// Arrange
619-
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EmbeddedFiles/DownloadFileWithFileName_RangeProcessingNotEnabled");
730+
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), "http://localhost/EmbeddedFiles/DownloadFileWithFileName_RangeProcessingNotEnabled");
620731
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
621732

622733
// Act
@@ -627,7 +738,7 @@ public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeProcess
627738
Assert.NotNull(response.Content.Headers.ContentType);
628739
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
629740
var body = await response.Content.ReadAsStringAsync();
630-
Assert.Equal("Sample text file as embedded resource.", body);
741+
Assert.Equal(expectedBody, body);
631742
}
632743

633744
[Fact]
@@ -721,5 +832,40 @@ public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeRequest
721832
Assert.NotNull(contentDisposition);
722833
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
723834
}
835+
836+
[Theory]
837+
[InlineData("", HttpStatusCode.OK)]
838+
[InlineData("bytes = 0-6", HttpStatusCode.PartialContent)]
839+
[InlineData("bytes = 17-25", HttpStatusCode.PartialContent)]
840+
[InlineData("bytes = 0-50", HttpStatusCode.PartialContent)]
841+
[InlineData("0-6", HttpStatusCode.OK)]
842+
[InlineData("bytes = ", HttpStatusCode.OK)]
843+
[InlineData("bytes = 1-4, 5-11", HttpStatusCode.OK)]
844+
[InlineData("bytes = 45-46", HttpStatusCode.RequestedRangeNotSatisfiable)]
845+
[InlineData("bytes = -0", HttpStatusCode.RequestedRangeNotSatisfiable)]
846+
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_DoesNotServeBody_ForHeadRequest(string rangeString, HttpStatusCode httpStatusCode)
847+
{
848+
// Arrange
849+
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, "http://localhost/EmbeddedFiles/DownloadFileWithFileName");
850+
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
851+
httpRequestMessage.Headers.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
852+
853+
// Act
854+
var response = await Client.SendAsync(httpRequestMessage);
855+
856+
// Assert
857+
Assert.Equal(httpStatusCode, response.StatusCode);
858+
859+
Assert.NotNull(response.Content.Headers.ContentType);
860+
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
861+
862+
var body = await response.Content.ReadAsStringAsync();
863+
Assert.NotNull(body);
864+
Assert.Equal(string.Empty, body);
865+
866+
var contentDisposition = response.Content.Headers.ContentDisposition.ToString();
867+
Assert.NotNull(contentDisposition);
868+
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
869+
}
724870
}
725871
}

0 commit comments

Comments
 (0)