/
CorsFeature.cs
107 lines (93 loc) · 4.7 KB
/
CorsFeature.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System;
using System.Collections.Generic;
using ServiceStack.Host.Handlers;
using ServiceStack.Web;
namespace ServiceStack
{
/// <summary>
/// Plugin adds support for Cross-origin resource sharing (CORS, see http://www.w3.org/TR/access-control/).
/// CORS allows to access resources from different domain which usually forbidden by origin policy.
/// </summary>
public class CorsFeature : IPlugin
{
public const string DefaultOrigin = "*";
public const string DefaultMethods = "GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD";
public const string DefaultHeaders = "Content-Type";
private readonly string allowedOrigins;
private readonly string allowedMethods;
private readonly string allowedHeaders;
private readonly string exposeHeaders;
private readonly int? maxAge;
private readonly bool allowCredentials;
private readonly ICollection<string> allowOriginWhitelist;
public ICollection<string> AllowOriginWhitelist => allowOriginWhitelist;
public bool AutoHandleOptionsRequests { get; set; }
/// <summary>
/// Represents a default constructor with Allow Origin equals to "*", Allowed GET, POST, PUT, DELETE, OPTIONS request and allowed "Content-Type" header.
/// </summary>
public CorsFeature(string allowedOrigins = DefaultOrigin, string allowedMethods = DefaultMethods, string allowedHeaders = DefaultHeaders, bool allowCredentials = false,
string exposeHeaders = null, int? maxAge = null)
{
this.allowedOrigins = allowedOrigins;
this.allowedMethods = allowedMethods;
this.allowedHeaders = allowedHeaders;
this.allowCredentials = allowCredentials;
this.AutoHandleOptionsRequests = true;
this.exposeHeaders = exposeHeaders;
this.maxAge = maxAge;
}
public CorsFeature(ICollection<string> allowOriginWhitelist, string allowedMethods = DefaultMethods, string allowedHeaders = DefaultHeaders, bool allowCredentials = false,
string exposeHeaders = null, int? maxAge = null)
{
this.allowedMethods = allowedMethods;
this.allowedHeaders = allowedHeaders;
this.allowCredentials = allowCredentials;
this.allowOriginWhitelist = allowOriginWhitelist;
this.AutoHandleOptionsRequests = true;
this.exposeHeaders = exposeHeaders;
this.maxAge = maxAge;
}
public void Register(IAppHost appHost)
{
if (appHost.HasMultiplePlugins<CorsFeature>())
throw new NotSupportedException("CorsFeature has already been registered");
if (!string.IsNullOrEmpty(allowedOrigins) && allowOriginWhitelist == null)
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.AllowOrigin, allowedOrigins);
if (!string.IsNullOrEmpty(allowedMethods))
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.AllowMethods, allowedMethods);
if (!string.IsNullOrEmpty(allowedHeaders))
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.AllowHeaders, allowedHeaders);
if (allowCredentials)
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.AllowCredentials, "true");
if (exposeHeaders != null)
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.ExposeHeaders, exposeHeaders);
if (maxAge != null)
appHost.Config.GlobalResponseHeaders.Add(HttpHeaders.AccessControlMaxAge, maxAge.Value.ToString());
if (allowOriginWhitelist != null)
{
void allowOriginFilter(IRequest httpReq, IResponse httpRes)
{
var origin = httpReq.Headers.Get(HttpHeaders.Origin);
if (allowOriginWhitelist.Contains(origin))
{
httpRes.AddHeader(HttpHeaders.AllowOrigin, origin);
}
}
appHost.PreRequestFilters.Add(allowOriginFilter);
}
if (AutoHandleOptionsRequests)
{
//Handles Request and closes Response after emitting global HTTP Headers
var emitGlobalHeadersHandler = new CustomActionHandler(
(httpReq, httpRes) =>
{
httpRes.EndRequest(); //PreRequestFilters already written in CustomActionHandler
});
appHost.RawHttpHandlers.Add(httpReq =>
httpReq.HttpMethod == HttpMethods.Options
? emitGlobalHeadersHandler
: null);
}
}
}
}