From 5dcf47ef121a0a779d4805459ffc0aa6ee26a0f6 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 17 Nov 2016 17:36:18 -0800 Subject: [PATCH] PR comments incorporated --- SampleDestination/Startup.cs | 36 ------- SampleDestination/StatusMiddleware.cs | 35 ------- SampleDestination/hosting.json | 3 - SampleOrigin/Startup.cs | 35 ------- SampleOrigin/hosting.json | 3 - samples/README.md | 28 ++++++ .../SampleDestination}/Program.cs | 15 +-- .../SampleDestination.xproj | 0 samples/SampleDestination/Startup.cs | 29 ++++++ .../SampleDestination}/project.json | 5 +- .../SampleDestination}/web.config | 0 .../SampleOrigin}/Program.cs | 15 +-- .../SampleOrigin}/SampleOrigin.xproj | 0 samples/SampleOrigin/Startup.cs | 36 +++++++ .../SampleOrigin}/project.json | 6 +- .../SampleOrigin}/web.config | 0 .../SampleOrigin}/wwwroot/Index.html | 2 +- .../Infrastructure/CorsService.cs | 6 +- .../Internal/CORSLoggerExtensions.cs | 17 +++- .../CorsServiceTests.cs | 94 +++++++++++++++---- 20 files changed, 199 insertions(+), 166 deletions(-) delete mode 100644 SampleDestination/Startup.cs delete mode 100644 SampleDestination/StatusMiddleware.cs delete mode 100644 SampleDestination/hosting.json delete mode 100644 SampleOrigin/Startup.cs delete mode 100644 SampleOrigin/hosting.json create mode 100644 samples/README.md rename {SampleDestination => samples/SampleDestination}/Program.cs (55%) rename {SampleDestination => samples/SampleDestination}/SampleDestination.xproj (100%) create mode 100644 samples/SampleDestination/Startup.cs rename {SampleOrigin => samples/SampleDestination}/project.json (80%) rename {SampleDestination => samples/SampleDestination}/web.config (100%) rename {SampleOrigin => samples/SampleOrigin}/Program.cs (55%) rename {SampleOrigin => samples/SampleOrigin}/SampleOrigin.xproj (100%) create mode 100644 samples/SampleOrigin/Startup.cs rename {SampleDestination => samples/SampleOrigin}/project.json (75%) rename {SampleOrigin => samples/SampleOrigin}/web.config (100%) rename {SampleOrigin => samples/SampleOrigin}/wwwroot/Index.html (95%) diff --git a/SampleDestination/Startup.cs b/SampleDestination/Startup.cs deleted file mode 100644 index 5ea6b6d284..0000000000 --- a/SampleDestination/Startup.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace SampleDestination -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - services.AddCors(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - loggerFactory.AddConsole(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseCors(policy => policy.WithOrigins("http://origin.sample.com:8080").WithMethods("GET")); - app.UseMiddleware(); - } -} -} diff --git a/SampleDestination/StatusMiddleware.cs b/SampleDestination/StatusMiddleware.cs deleted file mode 100644 index 1f47c634ad..0000000000 --- a/SampleDestination/StatusMiddleware.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace SampleDestination -{ - public class StatusMiddleware - { - /// - /// Instantiates a new . - /// - /// The next middleware in the pipeline. - public StatusMiddleware(RequestDelegate next) - { - } - - /// - /// Writes the status of the request sent in response. Does not invoke later middleware in the pipeline. - /// - /// The of the current request. - /// A that completes when writing to the response is done. - public Task Invoke(HttpContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - return context.Response.WriteAsync(context.Response.StatusCode.ToString()); - } - - } -} diff --git a/SampleDestination/hosting.json b/SampleDestination/hosting.json deleted file mode 100644 index 804f92d481..0000000000 --- a/SampleDestination/hosting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "server.urls": "http://destination.sample.com:80" -} \ No newline at end of file diff --git a/SampleOrigin/Startup.cs b/SampleOrigin/Startup.cs deleted file mode 100644 index 68a679aec2..0000000000 --- a/SampleOrigin/Startup.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using System.IO; - -namespace SampleOrigin -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - loggerFactory.AddConsole(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseDefaultFiles(); - app.UseStaticFiles(); - } - } -} diff --git a/SampleOrigin/hosting.json b/SampleOrigin/hosting.json deleted file mode 100644 index 7d79e9d594..0000000000 --- a/SampleOrigin/hosting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "server.urls": "http://origin.sample.com:8080" -} \ No newline at end of file diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000000..c0b4a4414e --- /dev/null +++ b/samples/README.md @@ -0,0 +1,28 @@ +CORS Sample +=== +This sample consists of a request origin (SampleOrigin) and a request destination (SampleDestination). +Both have different domain names, to simulate a CORS request. + +Modify Hosts File +Windows: +Run a text editor (e.g. Notepad) as an Administrator. Open the hosts file on the path: "C:\Windows\System32\drivers\etc\hosts". + +Linux: +On a Terminal window, type "sudo nano /etc/hosts" and enter your admin password when prompted. + +In the hosts file, add the following to the bottom of the file: +127.0.0.1 destination.example.com +127.0.0.1 origin.example.com + +Save the file and close it. Then clear your browser history. + +Run the sample +*In a command prompt window, open the directory where you cloned the repository, and open the SampleDestination directory. Run the command: dotnet run +*Repeat the above step in the SampleOrigin directory. +*Open a browser window and go to http://origin.example.com +*Click the button to see CORS in action. + +If using Visual Studio to launch the request origin: +Open Visual Studio and in the launchSettings.json file for the SampleOrigin project, change the launchUrl under SampleOrigin to +http://origin.example.com:8080. Using the dropdown near the Start button, choose SampleOrigin before pressing Start to ensure that it uses Kestrel +and not IIS Express. diff --git a/SampleDestination/Program.cs b/samples/SampleDestination/Program.cs similarity index 55% rename from SampleDestination/Program.cs rename to samples/SampleDestination/Program.cs index 972cde8b8b..d964f308f5 100644 --- a/SampleDestination/Program.cs +++ b/samples/SampleDestination/Program.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System.IO; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; namespace SampleDestination { @@ -12,14 +10,9 @@ namespace SampleDestination { public static void Main(string[] args) { - var config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("hosting.json", optional: true) - .Build(); - var host = new WebHostBuilder() .UseKestrel() - .UseConfiguration(config) + .UseUrls("http://*:5000") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() diff --git a/SampleDestination/SampleDestination.xproj b/samples/SampleDestination/SampleDestination.xproj similarity index 100% rename from SampleDestination/SampleDestination.xproj rename to samples/SampleDestination/SampleDestination.xproj diff --git a/samples/SampleDestination/Startup.cs b/samples/SampleDestination/Startup.cs new file mode 100644 index 0000000000..1055b9f224 --- /dev/null +++ b/samples/SampleDestination/Startup.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace SampleDestination +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddCors(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddConsole(); + app.UseCors(policy => policy.WithOrigins("http://origin.example.com:8080")); + app.Run(async context => + { + await context.Response.WriteAsync("Status code of your request: " + context.Response.StatusCode.ToString()); + }); + } + } +} diff --git a/SampleOrigin/project.json b/samples/SampleDestination/project.json similarity index 80% rename from SampleOrigin/project.json rename to samples/SampleDestination/project.json index 130536ee70..4e96e2c773 100644 --- a/SampleOrigin/project.json +++ b/samples/SampleDestination/project.json @@ -4,13 +4,10 @@ "version": "1.1.0-*", "type": "platform" }, - "Microsoft.AspNetCore.Diagnostics": "1.2.0-*", "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", "Microsoft.Extensions.Logging.Console": "1.2.0-*", - "Microsoft.AspNetCore.StaticFiles": "1.2.0-*", - "Microsoft.Extensions.Configuration.FileExtensions": "1.2.0-*", - "Microsoft.Extensions.Configuration.Json": "1.2.0-*" + "Microsoft.AspNetCore.Cors": "1.2.0-*" }, "tools": { diff --git a/SampleDestination/web.config b/samples/SampleDestination/web.config similarity index 100% rename from SampleDestination/web.config rename to samples/SampleDestination/web.config diff --git a/SampleOrigin/Program.cs b/samples/SampleOrigin/Program.cs similarity index 55% rename from SampleOrigin/Program.cs rename to samples/SampleOrigin/Program.cs index 68ec70a0b2..3a51bfdf8b 100644 --- a/SampleOrigin/Program.cs +++ b/samples/SampleOrigin/Program.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System.IO; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; namespace SampleOrigin { @@ -12,14 +10,9 @@ namespace SampleOrigin { public static void Main(string[] args) { - var config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("hosting.json", optional: true) - .Build(); - var host = new WebHostBuilder() .UseKestrel() - .UseConfiguration(config) + .UseUrls("http://*:8080") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() diff --git a/SampleOrigin/SampleOrigin.xproj b/samples/SampleOrigin/SampleOrigin.xproj similarity index 100% rename from SampleOrigin/SampleOrigin.xproj rename to samples/SampleOrigin/SampleOrigin.xproj diff --git a/samples/SampleOrigin/Startup.cs b/samples/SampleOrigin/Startup.cs new file mode 100644 index 0000000000..01e05c1b4d --- /dev/null +++ b/samples/SampleOrigin/Startup.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace SampleOrigin +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddConsole(); + app.Run( context => + { + var fileInfoProvider = env.WebRootFileProvider; + var fileInfo = fileInfoProvider.GetFileInfo("/Index.html"); + context.Response.Headers.Add("Content-Type", "text/html; charset=utf-8"); + return context.Response.SendFileAsync(fileInfo); + }); + + app.Run(async context => + { + await context.Response.WriteAsync("Status code of your request: " + context.Response.StatusCode.ToString()); + }); + + } + } +} diff --git a/SampleDestination/project.json b/samples/SampleOrigin/project.json similarity index 75% rename from SampleDestination/project.json rename to samples/SampleOrigin/project.json index 6cb1686ef0..b4165727fd 100644 --- a/SampleDestination/project.json +++ b/samples/SampleOrigin/project.json @@ -4,13 +4,9 @@ "version": "1.1.0-*", "type": "platform" }, - "Microsoft.AspNetCore.Diagnostics": "1.2.0-*", "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*", - "Microsoft.AspNetCore.Cors": "1.2.0-*", - "Microsoft.Extensions.Configuration.FileExtensions": "1.2.0-*", - "Microsoft.Extensions.Configuration.Json": "1.2.0-preview1-*" + "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "tools": { diff --git a/SampleOrigin/web.config b/samples/SampleOrigin/web.config similarity index 100% rename from SampleOrigin/web.config rename to samples/SampleOrigin/web.config diff --git a/SampleOrigin/wwwroot/Index.html b/samples/SampleOrigin/wwwroot/Index.html similarity index 95% rename from SampleOrigin/wwwroot/Index.html rename to samples/SampleOrigin/wwwroot/Index.html index 3bc55efdbe..d9d8b74672 100644 --- a/SampleOrigin/wwwroot/Index.html +++ b/samples/SampleOrigin/wwwroot/Index.html @@ -14,7 +14,7 @@ function makeCORSRequest(method) { // Destination server with CORS enabled. - var url = 'http://destination.sample.com/api'; + var url = 'http://destination.example.com:5000/api'; var request = createCORSRequest(method , url); if (!request) { diff --git a/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs b/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs index 72e17d5365..c8a8e54d4e 100644 --- a/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs +++ b/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs @@ -99,13 +99,14 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure var origin = context.Request.Headers[CorsConstants.Origin]; if (StringValues.IsNullOrEmpty(origin)) { + _logger?.RequestDoesNotHaveOriginHeader(); return; } if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin)) { _logger?.RequestHasOriginHeader(); - _logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource."); + _logger?.PolicyFailure($"Request origin {origin} does not have permission to access the resource."); return; } @@ -121,13 +122,14 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure var origin = context.Request.Headers[CorsConstants.Origin]; if (StringValues.IsNullOrEmpty(origin)) { + _logger?.RequestDoesNotHaveOriginHeader(); return; } if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin)) { _logger?.RequestHasOriginHeader(); - _logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource."); + _logger?.PolicyFailure($"Request origin {origin} does not have permission to access the resource."); return; } diff --git a/src/Microsoft.AspNetCore.Cors/Internal/CORSLoggerExtensions.cs b/src/Microsoft.AspNetCore.Cors/Internal/CORSLoggerExtensions.cs index dc63aaf2ae..e744e95565 100644 --- a/src/Microsoft.AspNetCore.Cors/Internal/CORSLoggerExtensions.cs +++ b/src/Microsoft.AspNetCore.Cors/Internal/CORSLoggerExtensions.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Cors.Internal { private static readonly Action _isPreflightRequest; private static readonly Action _requestHasOriginHeader; + private static readonly Action _requestDoesNotHaveOriginHeader; private static readonly Action _policySuccess; private static readonly Action _policyFailure; @@ -18,21 +19,26 @@ namespace Microsoft.AspNetCore.Cors.Internal _isPreflightRequest = LoggerMessage.Define( LogLevel.Debug, 1, - "The request is preflight."); + "This is a preflight request."); _requestHasOriginHeader = LoggerMessage.Define( LogLevel.Debug, 2, "The request has an origin header."); + _requestDoesNotHaveOriginHeader = LoggerMessage.Define( + LogLevel.Debug, + 3, + "The request does not have an origin header."); + _policySuccess = LoggerMessage.Define( LogLevel.Information, - 3, + 4, "Policy execution successful."); _policyFailure = LoggerMessage.Define( LogLevel.Information, - 3, + 5, "Policy execution failed. {FailureReason}"); } @@ -46,6 +52,11 @@ namespace Microsoft.AspNetCore.Cors.Internal _requestHasOriginHeader(logger, null); } + public static void RequestDoesNotHaveOriginHeader(this ILogger logger) + { + _requestDoesNotHaveOriginHeader(logger, null); + } + public static void PolicySuccess(this ILogger logger) { _policySuccess(logger, null); diff --git a/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs b/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs index 617155ea43..d20adfaa4b 100644 --- a/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs +++ b/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs @@ -228,34 +228,38 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure Assert.Contains("PUT", result.AllowedMethods); } - public static TheoryData LoggingData + public static TheoryData PreflightRequests_LoggingData { get { - return new TheoryData + return new TheoryData { { "http://example.com", "PUT", null, + "The request has an origin header.", "Policy execution failed. Request origin http://example.com does not have permission to access the resource." }, { - "http://allowedexample.com", + "http://allowed.example.com", "DELETE", null, + "The request has an origin header.", "Policy execution failed. Request method DELETE not allowed in CORS policy." }, { - "http://allowedexample.com", + "http://allowed.example.com", "PUT", new[] { "test" }, + "The request has an origin header.", "Policy execution failed. One or more request header(s) not allowed in CORS policy." }, { - "http://allowedexample.com", + "http://allowed.example.com", "PUT", null, + "The request has an origin header.", "Policy execution successful." }, }; @@ -263,8 +267,8 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure } [Theory] - [MemberData(nameof(LoggingData))] - public void EvaluatePolicy_LoggingForPreflightRequests(string origin, string method, string[] headers, string logMessage) + [MemberData(nameof(PreflightRequests_LoggingData))] + public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader(string origin, string method, string[] headers, string originLogMessage, string policyLogMessage) { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); @@ -272,21 +276,59 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(method: "OPTIONS", origin: origin, accessControlRequestMethod: method, accessControlRequestHeaders: headers); var policy = new CorsPolicy(); - policy.Origins.Add("http://allowedexample.com"); + policy.Origins.Add("http://allowed.example.com"); policy.Methods.Add("PUT"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); - Assert.Equal("The request is preflight.", sink.Writes[0].State.ToString()); - Assert.Equal("The request has an origin header.", sink.Writes[1].State.ToString()); - Assert.Equal(logMessage, sink.Writes[2].State.ToString()); + Assert.Equal("This is a preflight request.", sink.Writes[0].State.ToString()); + Assert.Equal(originLogMessage, sink.Writes[1].State.ToString()); + Assert.Equal(policyLogMessage, sink.Writes[2].State.ToString()); + } + + [Fact] + public void EvaluatePolicy_LoggingForPreflightRequests_DoesNotHaveOriginHeader() + { + var sink = new TestSink(); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); + + var corsService = new CorsService(new TestCorsOptions(), loggerFactory); + var requestContext = GetHttpContext(method: "OPTIONS", origin: null, accessControlRequestMethod: "PUT"); + var policy = new CorsPolicy(); + policy.Origins.Add("http://allowed.example.com"); + policy.Methods.Add("PUT"); + + // Act + var result = corsService.EvaluatePolicy(requestContext, policy); + + Assert.Equal("This is a preflight request.", sink.Writes[0].State.ToString()); + Assert.Equal("The request does not have an origin header.", sink.Writes[1].State.ToString()); + } + + public static TheoryData NonPreflightRequests_LoggingData + { + get + { + return new TheoryData + { + { + "http://example.com", + "The request has an origin header.", + "Policy execution failed. Request origin http://example.com does not have permission to access the resource." + }, + { + "http://allowed.example.com", + "The request has an origin header.", + "Policy execution successful." + } + }; + } } [Theory] - [InlineData("http://allowedexample.com", "Policy execution successful.")] - [InlineData("http://example.com", "Policy execution failed. Request origin http://example.com does not have permission to access the resource.")] - public void EvaluatePolicy_LoggingForRequests(string origin, string logMessage) + [MemberData(nameof(NonPreflightRequests_LoggingData))] + public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader(string origin, string originlogMessage, string policyLogMessage) { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); @@ -294,13 +336,31 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(origin: origin); var policy = new CorsPolicy(); - policy.Origins.Add("http://allowedexample.com"); + policy.Origins.Add("http://allowed.example.com"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); - Assert.Equal("The request has an origin header.", sink.Writes[0].State.ToString()); - Assert.Equal(logMessage, sink.Writes[1].State.ToString()); + Assert.Equal(originlogMessage, sink.Writes[0].State.ToString()); + Assert.Equal(policyLogMessage, sink.Writes[1].State.ToString()); + } + + [Fact] + public void EvaluatePolicy_LoggingForNonPreflightRequests_DoesNotHaveOriginHeader() + { + var sink = new TestSink(); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); + + var corsService = new CorsService(new TestCorsOptions(), loggerFactory); + var requestContext = GetHttpContext(origin: null); + var policy = new CorsPolicy(); + policy.Origins.Add("http://allowed.example.com"); + + // Act + var result = corsService.EvaluatePolicy(requestContext, policy); + + var logMessage = Assert.Single(sink.Writes); + Assert.Equal("The request does not have an origin header.", logMessage.State.ToString()); } [Theory]