Merge pull request #95 from aspnet/jbagga/Logging78
Addresses #69 and #78
This commit is contained in:
commit
52ba62c4d1
19
CORS.sln
19
CORS.sln
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.24720.0
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{84FE6872-A610-4CEC-855F-A84CBF1F40FC}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{84FE6872-A610-4CEC-855F-A84CBF1F40FC}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -20,6 +19,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{53
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CorsMiddlewareWebSite", "test\WebSites\CorsMiddlewareWebSite\CorsMiddlewareWebSite.xproj", "{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CorsMiddlewareWebSite", "test\WebSites\CorsMiddlewareWebSite\CorsMiddlewareWebSite.xproj", "{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{960E0703-A8A5-44DF-AA87-B7C614683B3C}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SampleDestination", "samples\SampleDestination\SampleDestination.xproj", "{F6675DC1-AA21-453B-89B6-DA425FB9C3A5}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SampleOrigin", "samples\SampleOrigin\SampleOrigin.xproj", "{99460370-AE5D-4DC9-8DBF-04DF66D6B21D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -38,6 +43,14 @@ Global
|
||||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F6675DC1-AA21-453B-89B6-DA425FB9C3A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F6675DC1-AA21-453B-89B6-DA425FB9C3A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F6675DC1-AA21-453B-89B6-DA425FB9C3A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F6675DC1-AA21-453B-89B6-DA425FB9C3A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{99460370-AE5D-4DC9-8DBF-04DF66D6B21D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{99460370-AE5D-4DC9-8DBF-04DF66D6B21D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{99460370-AE5D-4DC9-8DBF-04DF66D6B21D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{99460370-AE5D-4DC9-8DBF-04DF66D6B21D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -47,5 +60,7 @@ Global
|
||||||
{F05BE96F-F869-4408-A480-96935B4835EE} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
|
{F05BE96F-F869-4408-A480-96935B4835EE} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
|
||||||
{538380BF-0D4C-4E30-8F41-E75C4B1C01FA} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
|
{538380BF-0D4C-4E30-8F41-E75C4B1C01FA} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
|
||||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB} = {538380BF-0D4C-4E30-8F41-E75C4B1C01FA}
|
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB} = {538380BF-0D4C-4E30-8F41-E75C4B1C01FA}
|
||||||
|
{F6675DC1-AA21-453B-89B6-DA425FB9C3A5} = {960E0703-A8A5-44DF-AA87-B7C614683B3C}
|
||||||
|
{99460370-AE5D-4DC9-8DBF-04DF66D6B21D} = {960E0703-A8A5-44DF-AA87-B7C614683B3C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# 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
|
||||||
|
To run this CORS sample, modify the hosts file to register the hostnames `destination.example.com` and `origin.example.com`.
|
||||||
|
### 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
|
||||||
|
The SampleOrigin application will use port 5001, and SampleDestination will use 5000. Please ensure there are no other processes using those ports before running the CORS 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:5001`
|
||||||
|
* Input a method and header to create a CORS request or use one of the example buttons to see CORS in action
|
||||||
|
|
||||||
|
As an example, apart from `GET`, `HEAD` and `POST` requests, `PUT` requests are allowed in the CORS policy on SampleDestination. Any others, like `DELETE`, `OPTIONS` etc. are not allowed and throw an error.
|
||||||
|
`Cache-Control` has been added as an allowed header to the sample. Any other headers are not allowed and throw an error. You may leave the header name and value blank.
|
||||||
|
|
||||||
|
To edit the policy, please see `app.UseCors()` method in the `Startup.cs` file of SampleDestination.
|
||||||
|
|
||||||
|
**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:5001`.
|
||||||
|
Using the dropdown near the Start button, choose SampleOrigin before pressing Start to ensure that it uses Kestrel and not IIS Express.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace SampleDestination
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseKestrel()
|
||||||
|
.UseUrls("http://*:5000")
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>f6675dc1-aa21-453b-89b6-da425fb9c3a5</ProjectGuid>
|
||||||
|
<RootNamespace>SampleDestination</RootNamespace>
|
||||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DnxInvisibleContent Include="bower.json" />
|
||||||
|
<DnxInvisibleContent Include=".bowerrc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// 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:5001")
|
||||||
|
.WithMethods("PUT")
|
||||||
|
.WithHeaders("Cache-Control"));
|
||||||
|
|
||||||
|
app.Run(async context =>
|
||||||
|
{
|
||||||
|
var responseHeaders = context.Response.Headers;
|
||||||
|
context.Response.ContentType = "text/plain";
|
||||||
|
foreach (var responseHeader in responseHeaders)
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync("\n" + responseHeader.Key + ": " + responseHeader.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.Response.WriteAsync("\nStatus code of your request: " + context.Response.StatusCode.ToString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"version": "1.1.0-*",
|
||||||
|
"type": "platform"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*",
|
||||||
|
"Microsoft.Extensions.Logging.Console": "1.2.0-*",
|
||||||
|
"Microsoft.AspNetCore.Cors": "1.2.0-*"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frameworks": {
|
||||||
|
"netcoreapp1.0": {
|
||||||
|
"imports": [
|
||||||
|
"dotnet5.6",
|
||||||
|
"portable-net45+win8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"buildOptions": {
|
||||||
|
"emitEntryPoint": true,
|
||||||
|
"preserveCompilationContext": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"runtimeOptions": {
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Server": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"publishOptions": {
|
||||||
|
"include": [
|
||||||
|
"wwwroot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace SampleOrigin
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseKestrel()
|
||||||
|
.UseUrls("http://*:5001")
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>99460370-ae5d-4dc9-8dbf-04df66d6b21d</ProjectGuid>
|
||||||
|
<RootNamespace>SampleOrigin</RootNamespace>
|
||||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DnxInvisibleContent Include="bower.json" />
|
||||||
|
<DnxInvisibleContent Include=".bowerrc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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.ContentType = "text/html";
|
||||||
|
return context.Response.SendFileAsync(fileInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"version": "1.1.0-*",
|
||||||
|
"type": "platform"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*",
|
||||||
|
"Microsoft.Extensions.Logging.Console": "1.2.0-*"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frameworks": {
|
||||||
|
"netcoreapp1.0": {
|
||||||
|
"imports": [
|
||||||
|
"dotnet5.6",
|
||||||
|
"portable-net45+win8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"buildOptions": {
|
||||||
|
"emitEntryPoint": true,
|
||||||
|
"preserveCompilationContext": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"runtimeOptions": {
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Server": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"publishOptions": {
|
||||||
|
"include": [
|
||||||
|
"wwwroot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 15px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 5px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
background-color: indianred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gray {
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>CORS Sample</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// Make the CORS request.
|
||||||
|
function makeCORSRequest(method, headerName, headerValue) {
|
||||||
|
// Destination server with CORS enabled.
|
||||||
|
var url = 'http://destination.example.com:5000/';
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open(method, url, true);
|
||||||
|
if (headerName && headerValue) {
|
||||||
|
request.setRequestHeader(headerName, headerValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
alert('CORS not supported');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response handlers.
|
||||||
|
request.onload = function () {
|
||||||
|
var text = request.responseText;
|
||||||
|
alert('Response from CORS ' + method + ' request to ' + url + ': ' + text);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function () {
|
||||||
|
alert('There was an error making the request for method ' + method);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>CORS Sample</p>
|
||||||
|
Method: <input type="text" id="methodName" /><br /><br />
|
||||||
|
Header Name: <input type="text" id="headerName" /> Header Value: <input type="text" id="headerValue" /><br /><br />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('headerValue')
|
||||||
|
.addEventListener("keyup", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
document.getElementById("CORS").click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class="button gray" id="CORS" type="submit" onclick="makeCORSRequest(document.getElementById('methodName').value, document.getElementById('headerName').value, document.getElementById('headerValue').value);">Make a CORS Request</button><br /><br /><br /><br />
|
||||||
|
|
||||||
|
Method DELETE is not allowed:<button class="button red" id="InvalidMethodCORS" type="submit" onclick="makeCORSRequest('DELETE', 'Cache-Control', 'no-cache');">Invalid Method CORS Request</button>
|
||||||
|
Method PUT is allowed:<button class="button green" id="ValidMethodCORS" type="submit" onclick="makeCORSRequest('PUT', 'Cache-Control', 'no-cache');">Valid Method CORS Request</button><br /><br />
|
||||||
|
|
||||||
|
Header 'Max-Forwards' not supported:<button class="button red" id="InvalidHeaderCORS" type="submit" onclick="makeCORSRequest('PUT', 'Max-Forwards', '2');">Invalid Header CORS Request</button>
|
||||||
|
Header 'Cache-Control' is supported:<button class="button green" id="ValidHeaderCORS" type="submit" onclick="makeCORSRequest('PUT', 'Cache-Control', 'no-cache');">Valid Header CORS Request</button><br /><br />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -5,7 +5,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Cors.Internal;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
|
@ -17,12 +19,23 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
public class CorsService : ICorsService
|
public class CorsService : ICorsService
|
||||||
{
|
{
|
||||||
private readonly CorsOptions _options;
|
private readonly CorsOptions _options;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="CorsService"/>.
|
/// Creates a new instance of the <see cref="CorsService"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">The option model representing <see cref="CorsOptions"/>.</param>
|
/// <param name="options">The option model representing <see cref="CorsOptions"/>.</param>
|
||||||
public CorsService(IOptions<CorsOptions> options)
|
public CorsService(IOptions<CorsOptions> options)
|
||||||
|
: this(options, loggerFactory: null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="CorsService"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The option model representing <see cref="CorsOptions"/>.</param>
|
||||||
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
|
public CorsService(IOptions<CorsOptions> options, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
if (options == null)
|
if (options == null)
|
||||||
{
|
{
|
||||||
|
|
@ -30,6 +43,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
_options = options.Value;
|
_options = options.Value;
|
||||||
|
_logger = loggerFactory?.CreateLogger<CorsService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -69,6 +83,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
if (string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase) &&
|
if (string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase) &&
|
||||||
!StringValues.IsNullOrEmpty(accessControlRequestMethod))
|
!StringValues.IsNullOrEmpty(accessControlRequestMethod))
|
||||||
{
|
{
|
||||||
|
_logger?.IsPreflightRequest();
|
||||||
EvaluatePreflightRequest(context, policy, corsResult);
|
EvaluatePreflightRequest(context, policy, corsResult);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -82,21 +97,40 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
||||||
{
|
{
|
||||||
var origin = context.Request.Headers[CorsConstants.Origin];
|
var origin = context.Request.Headers[CorsConstants.Origin];
|
||||||
if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
if (StringValues.IsNullOrEmpty(origin))
|
||||||
{
|
{
|
||||||
|
_logger?.RequestDoesNotHaveOriginHeader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger?.RequestHasOriginHeader(origin);
|
||||||
|
if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
||||||
|
{
|
||||||
|
_logger?.PolicyFailure();
|
||||||
|
_logger?.OriginNotAllowed(origin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddOriginToResult(origin, policy, result);
|
AddOriginToResult(origin, policy, result);
|
||||||
result.SupportsCredentials = policy.SupportsCredentials;
|
result.SupportsCredentials = policy.SupportsCredentials;
|
||||||
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
|
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
|
||||||
|
_logger?.PolicySuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
||||||
{
|
{
|
||||||
var origin = context.Request.Headers[CorsConstants.Origin];
|
var origin = context.Request.Headers[CorsConstants.Origin];
|
||||||
if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
if (StringValues.IsNullOrEmpty(origin))
|
||||||
{
|
{
|
||||||
|
_logger?.RequestDoesNotHaveOriginHeader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger?.RequestHasOriginHeader(origin);
|
||||||
|
if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
||||||
|
{
|
||||||
|
_logger?.PolicyFailure();
|
||||||
|
_logger?.OriginNotAllowed(origin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,16 +158,25 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
|
_logger?.PolicyFailure();
|
||||||
|
_logger?.AccessControlMethodNotAllowed(accessControlRequestMethod);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!policy.AllowAnyHeader &&
|
if (!policy.AllowAnyHeader &&
|
||||||
requestHeaders != null &&
|
requestHeaders != null)
|
||||||
!requestHeaders.All(header => CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase) ||
|
|
||||||
policy.Headers.Contains(header, StringComparer.OrdinalIgnoreCase)))
|
|
||||||
{
|
{
|
||||||
return;
|
foreach (var requestHeader in requestHeaders)
|
||||||
|
{
|
||||||
|
if (!CorsConstants.SimpleRequestHeaders.Contains(requestHeader, StringComparer.OrdinalIgnoreCase) &&
|
||||||
|
!policy.Headers.Contains(requestHeader, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger?.PolicyFailure();
|
||||||
|
_logger?.RequestHeaderNotAllowed(requestHeader);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddOriginToResult(origin, policy, result);
|
AddOriginToResult(origin, policy, result);
|
||||||
|
|
@ -141,6 +184,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
result.PreflightMaxAge = policy.PreflightMaxAge;
|
result.PreflightMaxAge = policy.PreflightMaxAge;
|
||||||
result.AllowedMethods.Add(accessControlRequestMethod);
|
result.AllowedMethods.Add(accessControlRequestMethod);
|
||||||
AddHeaderValues(result.AllowedHeaders, requestHeaders);
|
AddHeaderValues(result.AllowedHeaders, requestHeaders);
|
||||||
|
_logger?.PolicySuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -261,4 +305,4 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Cors.Internal
|
||||||
|
{
|
||||||
|
internal static class CORSLoggerExtensions
|
||||||
|
{
|
||||||
|
private static readonly Action<ILogger, Exception> _isPreflightRequest;
|
||||||
|
private static readonly Action<ILogger, string, Exception> _requestHasOriginHeader;
|
||||||
|
private static readonly Action<ILogger, Exception> _requestDoesNotHaveOriginHeader;
|
||||||
|
private static readonly Action<ILogger, Exception> _policySuccess;
|
||||||
|
private static readonly Action<ILogger, Exception> _policyFailure;
|
||||||
|
private static readonly Action<ILogger, string, Exception> _originNotAllowed;
|
||||||
|
private static readonly Action<ILogger, string, Exception> _accessControlMethodNotAllowed;
|
||||||
|
private static readonly Action<ILogger, string, Exception> _requestHeaderNotAllowed;
|
||||||
|
|
||||||
|
static CORSLoggerExtensions()
|
||||||
|
{
|
||||||
|
_isPreflightRequest = LoggerMessage.Define(
|
||||||
|
LogLevel.Debug,
|
||||||
|
1,
|
||||||
|
"The request is a preflight request.");
|
||||||
|
|
||||||
|
_requestHasOriginHeader = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Debug,
|
||||||
|
2,
|
||||||
|
"The request has an origin header: '{origin}'.");
|
||||||
|
|
||||||
|
_requestDoesNotHaveOriginHeader = LoggerMessage.Define(
|
||||||
|
LogLevel.Debug,
|
||||||
|
3,
|
||||||
|
"The request does not have an origin header.");
|
||||||
|
|
||||||
|
_policySuccess = LoggerMessage.Define(
|
||||||
|
LogLevel.Information,
|
||||||
|
4,
|
||||||
|
"Policy execution successful.");
|
||||||
|
|
||||||
|
_policyFailure = LoggerMessage.Define(
|
||||||
|
LogLevel.Information,
|
||||||
|
5,
|
||||||
|
"Policy execution failed.");
|
||||||
|
|
||||||
|
_originNotAllowed = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Information,
|
||||||
|
6,
|
||||||
|
"Request origin {origin} does not have permission to access the resource.");
|
||||||
|
|
||||||
|
_accessControlMethodNotAllowed = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Information,
|
||||||
|
7,
|
||||||
|
"Request method {accessControlRequestMethod} not allowed in CORS policy.");
|
||||||
|
|
||||||
|
_requestHeaderNotAllowed = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Information,
|
||||||
|
8,
|
||||||
|
"Request header '{requestHeader}' not allowed in CORS policy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void IsPreflightRequest(this ILogger logger)
|
||||||
|
{
|
||||||
|
_isPreflightRequest(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestHasOriginHeader(this ILogger logger, string origin)
|
||||||
|
{
|
||||||
|
_requestHasOriginHeader(logger, origin, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestDoesNotHaveOriginHeader(this ILogger logger)
|
||||||
|
{
|
||||||
|
_requestDoesNotHaveOriginHeader(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PolicySuccess(this ILogger logger)
|
||||||
|
{
|
||||||
|
_policySuccess(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PolicyFailure(this ILogger logger)
|
||||||
|
{
|
||||||
|
_policyFailure(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OriginNotAllowed(this ILogger logger, string origin)
|
||||||
|
{
|
||||||
|
_originNotAllowed(logger, origin, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AccessControlMethodNotAllowed(this ILogger logger, string accessControlMethod)
|
||||||
|
{
|
||||||
|
_accessControlMethodNotAllowed(logger, accessControlMethod, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestHeaderNotAllowed(this ILogger logger, string requestHeader)
|
||||||
|
{
|
||||||
|
_requestHeaderNotAllowed(logger, requestHeader, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
"Microsoft.AspNetCore.Http.Extensions": "1.2.0-*",
|
"Microsoft.AspNetCore.Http.Extensions": "1.2.0-*",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "1.2.0-*",
|
"Microsoft.Extensions.Configuration.Abstractions": "1.2.0-*",
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "1.2.0-*",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "1.2.0-*",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "1.2.0-*",
|
||||||
"Microsoft.Extensions.Options": "1.2.0-*",
|
"Microsoft.Extensions.Options": "1.2.0-*",
|
||||||
"NETStandard.Library": "1.6.1-*"
|
"NETStandard.Library": "1.6.1-*"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Cors.Infrastructure
|
namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
|
|
@ -227,6 +228,162 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
Assert.Contains("PUT", result.AllowedMethods);
|
Assert.Contains("PUT", result.AllowedMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<LogData> PreflightRequests_LoggingData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new TheoryData<LogData>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new LogData {
|
||||||
|
Origin = "http://example.com",
|
||||||
|
Method = "PUT",
|
||||||
|
Headers = null,
|
||||||
|
OriginLogMessage = "The request has an origin header: 'http://example.com'.",
|
||||||
|
PolicyLogMessage = "Policy execution failed.",
|
||||||
|
FailureReason = "Request origin http://example.com does not have permission to access the resource."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new LogData {
|
||||||
|
Origin = "http://allowed.example.com",
|
||||||
|
Method = "DELETE",
|
||||||
|
Headers = null,
|
||||||
|
OriginLogMessage = "The request has an origin header: 'http://allowed.example.com'.",
|
||||||
|
PolicyLogMessage = "Policy execution failed.",
|
||||||
|
FailureReason = "Request method DELETE not allowed in CORS policy."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new LogData {
|
||||||
|
Origin = "http://allowed.example.com",
|
||||||
|
Method = "PUT",
|
||||||
|
Headers = new[] { "test" },
|
||||||
|
OriginLogMessage = "The request has an origin header: 'http://allowed.example.com'.",
|
||||||
|
PolicyLogMessage = "Policy execution failed.",
|
||||||
|
FailureReason = "Request header 'test' not allowed in CORS policy."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(PreflightRequests_LoggingData))]
|
||||||
|
public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader_PolicyFailed(LogData logData)
|
||||||
|
{
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
|
||||||
|
var requestContext = GetHttpContext(method: "OPTIONS", origin: logData.Origin, accessControlRequestMethod: logData.Method, accessControlRequestHeaders: logData.Headers);
|
||||||
|
var policy = new CorsPolicy();
|
||||||
|
policy.Origins.Add("http://allowed.example.com");
|
||||||
|
policy.Methods.Add("PUT");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||||
|
|
||||||
|
Assert.Equal("The request is a preflight request.", sink.Writes[0].State.ToString());
|
||||||
|
Assert.Equal(logData.OriginLogMessage, sink.Writes[1].State.ToString());
|
||||||
|
Assert.Equal(logData.PolicyLogMessage, sink.Writes[2].State.ToString());
|
||||||
|
Assert.Equal(logData.FailureReason, sink.Writes[3].State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader_PolicySucceeded()
|
||||||
|
{
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
|
||||||
|
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://allowed.example.com", 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("The request is a preflight request.", sink.Writes[0].State.ToString());
|
||||||
|
Assert.Equal("The request has an origin header: 'http://allowed.example.com'.", sink.Writes[1].State.ToString());
|
||||||
|
Assert.Equal("Policy execution successful.", 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("The request is a preflight request.", sink.Writes[0].State.ToString());
|
||||||
|
Assert.Equal("The request does not have an origin header.", sink.Writes[1].State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader_PolicyFailed()
|
||||||
|
{
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
|
||||||
|
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||||
|
var policy = new CorsPolicy();
|
||||||
|
policy.Origins.Add("http://allowed.example.com");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||||
|
|
||||||
|
Assert.Equal("The request has an origin header: 'http://example.com'.", sink.Writes[0].State.ToString());
|
||||||
|
Assert.Equal("Policy execution failed.", sink.Writes[1].State.ToString());
|
||||||
|
Assert.Equal("Request origin http://example.com does not have permission to access the resource.", sink.Writes[2].State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader_PolicySucceeded()
|
||||||
|
{
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
|
||||||
|
var requestContext = GetHttpContext(origin: "http://allowed.example.com");
|
||||||
|
var policy = new CorsPolicy();
|
||||||
|
policy.Origins.Add("http://allowed.example.com");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||||
|
|
||||||
|
Assert.Equal("The request has an origin header: 'http://allowed.example.com'.", sink.Writes[0].State.ToString());
|
||||||
|
Assert.Equal("Policy execution successful.", 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]
|
[Theory]
|
||||||
[InlineData("OpTions")]
|
[InlineData("OpTions")]
|
||||||
[InlineData("OPTIONS")]
|
[InlineData("OPTIONS")]
|
||||||
|
|
@ -446,7 +603,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void EaluatePolicy_DoesCaseSensitiveComparison()
|
public void EvaluatePolicy_DoesCaseSensitiveComparison()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var corsService = new CorsService(new TestCorsOptions());
|
var corsService = new CorsService(new TestCorsOptions());
|
||||||
|
|
@ -913,5 +1070,15 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LogData
|
||||||
|
{
|
||||||
|
public string Origin { get; set; }
|
||||||
|
public string Method { get; set; }
|
||||||
|
public string[] Headers { get; set; }
|
||||||
|
public string OriginLogMessage { get; set; }
|
||||||
|
public string PolicyLogMessage { get; set; }
|
||||||
|
public string FailureReason { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue