Skip to content

Commit 406a0c7

Browse files
ilonatommyjaviercn
authored andcommitted
Allow 404 status code, log when no injection made and add unit test.
1 parent 95d125e commit 406a0c7

File tree

3 files changed

+79
-37
lines changed

3 files changed

+79
-37
lines changed

src/BuiltInTools/BrowserRefresh/BrowserRefreshMiddleware.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,16 @@ internal static class Log
233233
$"This may have been caused by the response's {HeaderNames.ContentEncoding}: '{{encoding}}'. " +
234234
"Consider disabling response compression.");
235235

236+
private static readonly Action<ILogger, int, string?, Exception?> _scriptInjectionSkipped = LoggerMessage.Define<int, string?>(
237+
LogLevel.Debug,
238+
new EventId(6, "ScriptInjectionSkipped"),
239+
"Browser refresh script injection skipped. Status code: {StatusCode}, Content type: {ContentType}");
240+
236241
public static void SetupResponseForBrowserRefresh(ILogger logger) => _setupResponseForBrowserRefresh(logger, null);
237242
public static void BrowserConfiguredForRefreshes(ILogger logger) => _browserConfiguredForRefreshes(logger, null);
238243
public static void FailedToConfiguredForRefreshes(ILogger logger) => _failedToConfigureForRefreshes(logger, null);
239244
public static void ResponseCompressionDetected(ILogger logger, StringValues encoding) => _responseCompressionDetected(logger, encoding, null);
245+
public static void ScriptInjectionSkipped(ILogger logger, int statusCode, string? contentType) => _scriptInjectionSkipped(logger, statusCode, contentType, null);
240246
}
241247
}
242248
}

src/BuiltInTools/BrowserRefresh/ResponseStreamWrapper.cs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,39 +95,44 @@ private void OnWrite()
9595
var response = _context.Response;
9696

9797
_isHtmlResponse =
98-
(response.StatusCode == StatusCodes.Status200OK || response.StatusCode == StatusCodes.Status500InternalServerError) &&
98+
(response.StatusCode == StatusCodes.Status200OK ||
99+
response.StatusCode == StatusCodes.Status404NotFound ||
100+
response.StatusCode == StatusCodes.Status500InternalServerError) &&
99101
MediaTypeHeaderValue.TryParse(response.ContentType, out var mediaType) &&
100102
mediaType.IsSubsetOf(s_textHtmlMediaType) &&
101103
(!mediaType.Charset.HasValue || mediaType.Charset.Equals("utf-8", StringComparison.OrdinalIgnoreCase));
102104

103-
if (_isHtmlResponse.Value)
105+
if (!_isHtmlResponse.Value)
104106
{
105-
BrowserRefreshMiddleware.Log.SetupResponseForBrowserRefresh(_logger);
106-
// Since we're changing the markup content, reset the content-length
107-
response.Headers.ContentLength = null;
107+
BrowserRefreshMiddleware.Log.ScriptInjectionSkipped(_logger, response.StatusCode, response.ContentType);
108+
return;
109+
}
110+
111+
BrowserRefreshMiddleware.Log.SetupResponseForBrowserRefresh(_logger);
112+
// Since we're changing the markup content, reset the content-length
113+
response.Headers.ContentLength = null;
108114

109-
_scriptInjectingStream = new ScriptInjectingStream(_baseStream);
115+
_scriptInjectingStream = new ScriptInjectingStream(_baseStream);
110116

111-
// By default, write directly to the script injection stream.
112-
// We may change the base stream below if we detect that the response
113-
// is compressed.
114-
_baseStream = _scriptInjectingStream;
117+
// By default, write directly to the script injection stream.
118+
// We may change the base stream below if we detect that the response
119+
// is compressed.
120+
_baseStream = _scriptInjectingStream;
115121

116-
// Check if the response has gzip Content-Encoding
117-
if (response.Headers.TryGetValue(HeaderNames.ContentEncoding, out var contentEncodingValues))
122+
// Check if the response has gzip Content-Encoding
123+
if (response.Headers.TryGetValue(HeaderNames.ContentEncoding, out var contentEncodingValues))
124+
{
125+
var contentEncoding = contentEncodingValues.FirstOrDefault();
126+
if (string.Equals(contentEncoding, "gzip", StringComparison.OrdinalIgnoreCase))
118127
{
119-
var contentEncoding = contentEncodingValues.FirstOrDefault();
120-
if (string.Equals(contentEncoding, "gzip", StringComparison.OrdinalIgnoreCase))
121-
{
122-
// Remove the Content-Encoding header since we'll be serving uncompressed content
123-
response.Headers.Remove(HeaderNames.ContentEncoding);
124-
125-
_pipe = new Pipe();
126-
var gzipStream = new GZipStream(_pipe.Reader.AsStream(leaveOpen: true), CompressionMode.Decompress, leaveOpen: true);
127-
128-
_gzipCopyTask = gzipStream.CopyToAsync(_scriptInjectingStream);
129-
_baseStream = _pipe.Writer.AsStream(leaveOpen: true);
130-
}
128+
// Remove the Content-Encoding header since we'll be serving uncompressed content
129+
response.Headers.Remove(HeaderNames.ContentEncoding);
130+
131+
_pipe = new Pipe();
132+
var gzipStream = new GZipStream(_pipe.Reader.AsStream(leaveOpen: true), CompressionMode.Decompress, leaveOpen: true);
133+
134+
_gzipCopyTask = gzipStream.CopyToAsync(_scriptInjectingStream);
135+
_baseStream = _pipe.Writer.AsStream(leaveOpen: true);
131136
}
132137
}
133138
}

test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.IO.Pipelines;
55
using System.Runtime.CompilerServices;
6+
using System.Text;
67
using Microsoft.AspNetCore.Http;
78
using Microsoft.AspNetCore.Http.Features;
89
using Microsoft.Extensions.Logging.Abstractions;
@@ -555,8 +556,30 @@ public async Task InvokeAsync_DoesNotAttachHeaders_WhenAlreadyAttached()
555556
Assert.Equal("true", context.Response.Headers["ASPNETCORE-BROWSER-TOOLS"]);
556557
}
557558

558-
[Fact]
559-
public async Task InvokeAsync_AddsScriptToThePage()
559+
[Theory]
560+
[InlineData(500, "text/html")]
561+
[InlineData(404, "text/html")]
562+
[InlineData(200, "text/html")]
563+
public async Task InvokeAsync_AddsScriptToThePage_ForSupportedStatusCodes(int statusCode, string contentType)
564+
{
565+
// Act & Assert
566+
var responseContent = await TestBrowserRefreshMiddleware(statusCode, contentType, "Test Content");
567+
Assert.Contains("<script src=\"/_framework/aspnetcore-browser-refresh.js\"></script>", responseContent);
568+
}
569+
570+
[Theory]
571+
[InlineData(400, "text/html")] // Bad Request
572+
[InlineData(401, "text/html")] // Unauthorized
573+
[InlineData(404, "application/json")] // 404 with wrong content type
574+
[InlineData(200, "application/json")] // 200 with wrong content type
575+
public async Task InvokeAsync_DoesNotAddScript_ForUnsupportedStatusCodesOrContentTypes(int statusCode, string contentType)
576+
{
577+
// Act & Assert
578+
var responseContent = await TestBrowserRefreshMiddleware(statusCode, contentType, "Test Content", includeHtmlWrapper: false);
579+
Assert.DoesNotContain("<script src=\"/_framework/aspnetcore-browser-refresh.js\"></script>", responseContent);
580+
}
581+
582+
private async Task<string> TestBrowserRefreshMiddleware(int statusCode, string contentType, string content, bool includeHtmlWrapper = true)
560583
{
561584
// Arrange
562585
var stream = new MemoryStream();
@@ -575,24 +598,32 @@ public async Task InvokeAsync_AddsScriptToThePage()
575598

576599
var middleware = new BrowserRefreshMiddleware(async (context) =>
577600
{
601+
context.Response.StatusCode = statusCode;
602+
context.Response.ContentType = contentType;
578603

579-
context.Response.ContentType = "text/html";
580-
581-
await context.Response.WriteAsync("<html>");
582-
await context.Response.WriteAsync("<body>");
583-
await context.Response.WriteAsync("<h1>");
584-
await context.Response.WriteAsync("Hello world");
585-
await context.Response.WriteAsync("</h1>");
586-
await context.Response.WriteAsync("</body>");
587-
await context.Response.WriteAsync("</html>");
604+
if (includeHtmlWrapper)
605+
{
606+
await context.Response.WriteAsync("<html>");
607+
await context.Response.WriteAsync("<body>");
608+
await context.Response.WriteAsync("<h1>");
609+
await context.Response.WriteAsync(content);
610+
await context.Response.WriteAsync("</h1>");
611+
await context.Response.WriteAsync("</body>");
612+
await context.Response.WriteAsync("</html>");
613+
}
614+
else
615+
{
616+
await context.Response.WriteAsync(content);
617+
}
588618
}, NullLogger<BrowserRefreshMiddleware>.Instance);
589619

590620
// Act
591621
await middleware.InvokeAsync(context);
592622

593-
// Assert
623+
// Return response content and verify status code
594624
var responseContent = Encoding.UTF8.GetString(stream.ToArray());
595-
Assert.Equal("<html><body><h1>Hello world</h1><script src=\"/_framework/aspnetcore-browser-refresh.js\"></script></body></html>", responseContent);
625+
Assert.Equal(statusCode, context.Response.StatusCode);
626+
return responseContent;
596627
}
597628

598629
private class TestHttpResponseFeature : IHttpResponseFeature, IHttpResponseBodyFeature

0 commit comments

Comments
 (0)