Renames some options

This commit is contained in:
Manu Mtz.-Almeida 2015-11-12 15:14:38 +01:00
parent 4b9ae1e081
commit ee70b8845a
4 changed files with 66 additions and 65 deletions

View File

@ -8,9 +8,9 @@ import (
type cors struct { type cors struct {
allowAllOrigins bool allowAllOrigins bool
allowedOriginFunc func(string) bool allowOriginFunc func(string) bool
allowedOrigins []string allowOrigins []string
exposedHeaders []string exposeHeaders []string
normalHeaders http.Header normalHeaders http.Header
preflightHeaders http.Header preflightHeaders http.Header
} }
@ -20,9 +20,9 @@ func newCors(config Config) *cors {
panic(err.Error()) panic(err.Error())
} }
return &cors{ return &cors{
allowedOriginFunc: config.AllowOriginFunc, allowOriginFunc: config.AllowOriginFunc,
allowAllOrigins: config.AllowAllOrigins, allowAllOrigins: config.AllowAllOrigins,
allowedOrigins: normalize(config.AllowedOrigins), allowOrigins: normalize(config.AllowOrigins),
normalHeaders: generateNormalHeaders(config), normalHeaders: generateNormalHeaders(config),
preflightHeaders: generatePreflightHeaders(config), preflightHeaders: generatePreflightHeaders(config),
} }
@ -54,13 +54,13 @@ func (cors *cors) validateOrigin(origin string) bool {
if cors.allowAllOrigins { if cors.allowAllOrigins {
return true return true
} }
for _, value := range cors.allowedOrigins { for _, value := range cors.allowOrigins {
if value == origin { if value == origin {
return true return true
} }
} }
if cors.allowedOriginFunc != nil { if cors.allowOriginFunc != nil {
return cors.allowedOriginFunc(origin) return cors.allowOriginFunc(origin)
} }
return false return false
} }

41
cors.go
View File

@ -14,7 +14,7 @@ type Config struct {
// AllowedOrigins is a list of origins a cross-domain request can be executed from. // AllowedOrigins is a list of origins a cross-domain request can be executed from.
// If the special "*" value is present in the list, all origins will be allowed. // If the special "*" value is present in the list, all origins will be allowed.
// Default value is ["*"] // Default value is ["*"]
AllowedOrigins []string AllowOrigins []string
// AllowOriginFunc is a custom function to validate the origin. It take the origin // AllowOriginFunc is a custom function to validate the origin. It take the origin
// as argument and returns true if allowed or false otherwise. If this option is // as argument and returns true if allowed or false otherwise. If this option is
@ -23,47 +23,47 @@ type Config struct {
// AllowedMethods is a list of methods the client is allowed to use with // AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is simple methods (GET and POST) // cross-domain requests. Default value is simple methods (GET and POST)
AllowedMethods []string AllowMethods []string
// AllowedHeaders is list of non simple headers the client is allowed to use with // AllowedHeaders is list of non simple headers the client is allowed to use with
// cross-domain requests. // cross-domain requests.
// If the special "*" value is present in the list, all headers will be allowed. // If the special "*" value is present in the list, all headers will be allowed.
// Default value is [] but "Origin" is always appended to the list. // Default value is [] but "Origin" is always appended to the list.
AllowedHeaders []string AllowHeaders []string
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposedHeaders []string
// AllowCredentials indicates whether the request can include user credentials like // AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates. // cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool AllowCredentials bool
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposeHeaders []string
// MaxAge indicates how long (in seconds) the results of a preflight request // MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached // can be cached
MaxAge time.Duration MaxAge time.Duration
} }
func (c *Config) AddAllowedMethods(methods ...string) { func (c *Config) AddAllowMethods(methods ...string) {
c.AllowedMethods = append(c.AllowedMethods, methods...) c.AllowMethods = append(c.AllowMethods, methods...)
} }
func (c *Config) AddAllowedHeaders(headers ...string) { func (c *Config) AddAllowHeaders(headers ...string) {
c.AllowedHeaders = append(c.AllowedHeaders, headers...) c.AllowHeaders = append(c.AllowHeaders, headers...)
} }
func (c *Config) AddExposedHeaders(headers ...string) { func (c *Config) AddExposeHeaders(headers ...string) {
c.ExposedHeaders = append(c.ExposedHeaders, headers...) c.ExposeHeaders = append(c.ExposeHeaders, headers...)
} }
func (c Config) Validate() error { func (c Config) Validate() error {
if c.AllowAllOrigins && (c.AllowOriginFunc != nil || len(c.AllowedOrigins) > 0) { if c.AllowAllOrigins && (c.AllowOriginFunc != nil || len(c.AllowOrigins) > 0) {
return errors.New("conflict settings: all origins are allowed. AllowOriginFunc or AllowedOrigins is not needed") return errors.New("conflict settings: all origins are allowed. AllowOriginFunc or AllowedOrigins is not needed")
} }
if !c.AllowAllOrigins && c.AllowOriginFunc == nil && len(c.AllowedOrigins) == 0 { if !c.AllowAllOrigins && c.AllowOriginFunc == nil && len(c.AllowOrigins) == 0 {
return errors.New("conflict settings: all origins disabled") return errors.New("conflict settings: all origins disabled")
} }
for _, origin := range c.AllowedOrigins { for _, origin := range c.AllowOrigins {
if !strings.HasPrefix(origin, "http://") && !strings.HasPrefix(origin, "https://") { if !strings.HasPrefix(origin, "http://") && !strings.HasPrefix(origin, "https://") {
return errors.New("bad origin: origins must include http:// or https://") return errors.New("bad origin: origins must include http:// or https://")
} }
@ -73,16 +73,17 @@ func (c Config) Validate() error {
func DefaultConfig() Config { func DefaultConfig() Config {
return Config{ return Config{
AllowAllOrigins: true, AllowMethods: []string{"GET", "POST", "PUT", "HEAD"},
AllowedMethods: []string{"GET", "POST", "PUT", "HEAD"}, AllowHeaders: []string{"Origin", "Content-Length", "Content-Type"},
AllowedHeaders: []string{"Content-Type"},
AllowCredentials: false, AllowCredentials: false,
MaxAge: 12 * time.Hour, MaxAge: 12 * time.Hour,
} }
} }
func Default() gin.HandlerFunc { func Default() gin.HandlerFunc {
return New(DefaultConfig()) config := DefaultConfig()
config.AllowAllOrigins = true
return New(config)
} }
func New(config Config) gin.HandlerFunc { func New(config Config) gin.HandlerFunc {

View File

@ -44,7 +44,7 @@ func TestBadConfig(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
New(Config{ New(Config{
AllowAllOrigins: true, AllowAllOrigins: true,
AllowedOrigins: []string{"http://google.com"}, AllowOrigins: []string{"http://google.com"},
}) })
}) })
assert.Panics(t, func() { assert.Panics(t, func() {
@ -55,7 +55,7 @@ func TestBadConfig(t *testing.T) {
}) })
assert.Panics(t, func() { assert.Panics(t, func() {
New(Config{ New(Config{
AllowedOrigins: []string{"google.com"}, AllowOrigins: []string{"google.com"},
}) })
}) })
} }
@ -101,9 +101,9 @@ func TestGenerateNormalHeaders_AllowCredentials(t *testing.T) {
func TestGenerateNormalHeaders_ExposedHeaders(t *testing.T) { func TestGenerateNormalHeaders_ExposedHeaders(t *testing.T) {
header := generateNormalHeaders(Config{ header := generateNormalHeaders(Config{
ExposedHeaders: []string{"X-user", "xPassword"}, ExposeHeaders: []string{"X-user", "xPassword"},
}) })
assert.Equal(t, header.Get("Access-Control-Expose-Headers"), "x-user, xpassword") assert.Equal(t, header.Get("Access-Control-Expose-Headers"), "x-user,xpassword")
assert.Equal(t, header.Get("Vary"), "Origin") assert.Equal(t, header.Get("Vary"), "Origin")
assert.Len(t, header, 2) assert.Len(t, header, 2)
} }
@ -135,18 +135,18 @@ func TestGeneratePreflightHeaders_AllowCredentials(t *testing.T) {
func TestGeneratePreflightHeaders_AllowedMethods(t *testing.T) { func TestGeneratePreflightHeaders_AllowedMethods(t *testing.T) {
header := generatePreflightHeaders(Config{ header := generatePreflightHeaders(Config{
AllowedMethods: []string{"GET ", "post", "PUT", " put "}, AllowMethods: []string{"GET ", "post", "PUT", " put "},
}) })
assert.Equal(t, header.Get("Access-Control-Allow-Methods"), "get, post, put") assert.Equal(t, header.Get("Access-Control-Allow-Methods"), "get,post,put")
assert.Equal(t, header.Get("Vary"), "Origin") assert.Equal(t, header.Get("Vary"), "Origin")
assert.Len(t, header, 2) assert.Len(t, header, 2)
} }
func TestGeneratePreflightHeaders_AllowedHeaders(t *testing.T) { func TestGeneratePreflightHeaders_AllowedHeaders(t *testing.T) {
header := generatePreflightHeaders(Config{ header := generatePreflightHeaders(Config{
AllowedHeaders: []string{"X-user", "Content-Type"}, AllowHeaders: []string{"X-user", "Content-Type"},
}) })
assert.Equal(t, header.Get("Access-Control-Allow-Headers"), "x-user, content-type") assert.Equal(t, header.Get("Access-Control-Allow-Headers"), "x-user,content-type")
assert.Equal(t, header.Get("Vary"), "Origin") assert.Equal(t, header.Get("Vary"), "Origin")
assert.Len(t, header, 2) assert.Len(t, header, 2)
} }
@ -169,7 +169,7 @@ func TestValidateOrigin(t *testing.T) {
assert.True(t, cors.validateOrigin("example.com")) assert.True(t, cors.validateOrigin("example.com"))
cors = newCors(Config{ cors = newCors(Config{
AllowedOrigins: []string{"https://google.com", "https://github.com"}, AllowOrigins: []string{"https://google.com", "https://github.com"},
AllowOriginFunc: func(origin string) bool { AllowOriginFunc: func(origin string) bool {
return (origin == "http://news.ycombinator.com") return (origin == "http://news.ycombinator.com")
}, },
@ -184,10 +184,10 @@ func TestValidateOrigin(t *testing.T) {
func TestPassesAllowedOrigins(t *testing.T) { func TestPassesAllowedOrigins(t *testing.T) {
router := newTestRouter(Config{ router := newTestRouter(Config{
AllowedOrigins: []string{"http://google.com"}, AllowOrigins: []string{"http://google.com"},
AllowedMethods: []string{" GeT ", "get", "post", "PUT ", "Head", "POST"}, AllowMethods: []string{" GeT ", "get", "post", "PUT ", "Head", "POST"},
AllowedHeaders: []string{"Content-type", "timeStamp "}, AllowHeaders: []string{"Content-type", "timeStamp "},
ExposedHeaders: []string{"Data", "x-User"}, ExposeHeaders: []string{"Data", "x-User"},
AllowCredentials: true, AllowCredentials: true,
MaxAge: 12 * time.Hour, MaxAge: 12 * time.Hour,
AllowOriginFunc: func(origin string) bool { AllowOriginFunc: func(origin string) bool {
@ -207,7 +207,7 @@ func TestPassesAllowedOrigins(t *testing.T) {
assert.Equal(t, w.Body.String(), "get") assert.Equal(t, w.Body.String(), "get")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://google.com") assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://google.com")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true") assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true")
assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data, x-user") assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data,x-user")
// deny CORS request // deny CORS request
w = performRequest(router, "GET", "https://google.com") w = performRequest(router, "GET", "https://google.com")
@ -221,8 +221,8 @@ func TestPassesAllowedOrigins(t *testing.T) {
assert.Equal(t, w.Code, 200) assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://github.com") assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://github.com")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true") assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "get, post, put, head") assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "get,post,put,head")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type, timestamp") assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,timestamp")
assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "43200") assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "43200")
// deny CORS prefligh request // deny CORS prefligh request
@ -238,9 +238,9 @@ func TestPassesAllowedOrigins(t *testing.T) {
func TestPassesAllowedAllOrigins(t *testing.T) { func TestPassesAllowedAllOrigins(t *testing.T) {
router := newTestRouter(Config{ router := newTestRouter(Config{
AllowAllOrigins: true, AllowAllOrigins: true,
AllowedMethods: []string{" Patch ", "get", "post", "POST"}, AllowMethods: []string{" Patch ", "get", "post", "POST"},
AllowedHeaders: []string{"Content-type", " testheader "}, AllowHeaders: []string{"Content-type", " testheader "},
ExposedHeaders: []string{"Data2", "x-User2"}, ExposeHeaders: []string{"Data2", "x-User2"},
AllowCredentials: false, AllowCredentials: false,
MaxAge: 10 * time.Hour, MaxAge: 10 * time.Hour,
}) })
@ -256,15 +256,15 @@ func TestPassesAllowedAllOrigins(t *testing.T) {
w = performRequest(router, "POST", "example.com") w = performRequest(router, "POST", "example.com")
assert.Equal(t, w.Body.String(), "post") assert.Equal(t, w.Body.String(), "post")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*") assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*")
assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data2, x-user2") assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data2,x-user2")
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
// allowed CORS prefligh request // allowed CORS prefligh request
w = performRequest(router, "OPTIONS", "https://facebook.com") w = performRequest(router, "OPTIONS", "https://facebook.com")
assert.Equal(t, w.Code, 200) assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*") assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "patch, get, post") assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "patch,get,post")
assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type, testheader") assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,testheader")
assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "36000") assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "36000")
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
} }

View File

@ -12,9 +12,9 @@ func generateNormalHeaders(c Config) http.Header {
if c.AllowCredentials { if c.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true") headers.Set("Access-Control-Allow-Credentials", "true")
} }
if len(c.ExposedHeaders) > 0 { if len(c.ExposeHeaders) > 0 {
exposedHeaders := normalize(c.ExposedHeaders) exposeHeaders := normalize(c.ExposeHeaders)
headers.Set("Access-Control-Expose-Headers", strings.Join(exposedHeaders, ", ")) headers.Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ","))
} }
if c.AllowAllOrigins { if c.AllowAllOrigins {
headers.Set("Access-Control-Allow-Origin", "*") headers.Set("Access-Control-Allow-Origin", "*")
@ -29,14 +29,14 @@ func generatePreflightHeaders(c Config) http.Header {
if c.AllowCredentials { if c.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true") headers.Set("Access-Control-Allow-Credentials", "true")
} }
if len(c.AllowedMethods) > 0 { if len(c.AllowMethods) > 0 {
allowedMethods := normalize(c.AllowedMethods) allowMethods := normalize(c.AllowMethods)
value := strings.Join(allowedMethods, ", ") value := strings.Join(allowMethods, ",")
headers.Set("Access-Control-Allow-Methods", value) headers.Set("Access-Control-Allow-Methods", value)
} }
if len(c.AllowedHeaders) > 0 { if len(c.AllowHeaders) > 0 {
allowedHeaders := normalize(c.AllowedHeaders) allowHeaders := normalize(c.AllowHeaders)
value := strings.Join(allowedHeaders, ", ") value := strings.Join(allowHeaders, ",")
headers.Set("Access-Control-Allow-Headers", value) headers.Set("Access-Control-Allow-Headers", value)
} }
if c.MaxAge > time.Duration(0) { if c.MaxAge > time.Duration(0) {