Compare commits

..

23 Commits
new ... master

Author SHA1 Message Date
Bo-Yi Wu
51f0ef8b07 Update .travis.yml 2017-09-17 10:20:32 +08:00
Bo-Yi Wu
88488351b0 update 1.9
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-27 00:58:24 +08:00
Javier Provecho Fernandez
567de19169 Merge pull request #27 from easonlin404/readme
Remove unnecessary comments.
2017-07-08 10:09:47 +02:00
Eason Lin
e641d4ab82 undo comments, cross support for wildcard origin 2017-07-03 00:16:58 +08:00
Eason Lin
1238974274 Change comments to ‘Default value is []’ 2017-06-28 13:58:35 +08:00
Matthew Baird
f894742c19 add support for wildcard cors origin (#24) 2017-06-27 23:27:08 -05:00
Eason Lin
796e03648c Remove unnecessary comments. 2017-06-28 08:45:17 +08:00
Eason Lin
5c9b3fa52c Unify ‘github.com’ wording with code. (#26) 2017-06-27 11:18:33 -05:00
Bo-Yi Wu
cf4846e6a6 using dev version
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-18 20:53:40 +08:00
Bo-Yi Wu
69f558022a update test version.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-18 20:48:59 +08:00
Bo-Yi Wu
30e66044d0 fix: revert gin link. (#20) 2017-03-18 07:45:46 -05:00
Bo-Yi Wu
bec00ec825 fix: remove AllowCredentials check for allow origins (#16) 2017-02-27 14:30:00 +08:00
Bo-Yi Wu
79e0d17cc9 fix: assert arguments error. (#15) 2017-02-27 08:34:08 +08:00
Bo-Yi Wu
da1a40b05a Merge pull request #13 from gin-contrib/test
fix testing from #11
2016-12-29 16:16:41 +08:00
Bo-Yi Wu
a22aeebf59 fix testing.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-12-28 07:22:26 +08:00
Jonathan
dbbc835584 Fix logic error for when setting allowedAllOrigins and allowedCredentials
`Access-Control-Allow-Origin` should returning `Origin` originally of
requests when allowCredentials and allowAllOrigins.
2016-12-28 06:57:52 +08:00
Bo-Yi Wu
d075cad469 update golang testing to 1.6.4 and 1.7.4
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-12-05 22:52:08 +08:00
Bo-Yi Wu
3f5d6253cd [ci skip] update gin gitter link.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-12-01 16:50:15 +08:00
Bo-Yi Wu
57b7130fd8 [ci skip] remove empty line.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-12-01 16:46:05 +08:00
Bo-Yi Wu
fb918bcd82 [ci skip] update readme
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-11-09 14:27:26 +08:00
Thomas Boerger
6ebcc5f9c7 Merge pull request #9 from se77en/dev
Add convert func to format headers and methods of http
2016-11-09 07:01:54 +01:00
Damon Zhao
25b01311da Add convert func to format headers and methods of http 2016-11-08 18:51:19 +08:00
Javier Provecho Fernandez
0202b02ec3 Merge pull request #7 from gin-contrib/new
Updates README
2016-10-31 09:50:56 +01:00
7 changed files with 84 additions and 51 deletions

View File

@ -2,9 +2,10 @@ language: go
sudo: false sudo: false
go: go:
- 1.5.4 - 1.6.x
- 1.6.3 - 1.7.x
- 1.7.3 - 1.8.x
- 1.9.x
- tip - tip
script: script:

View File

@ -4,8 +4,7 @@
[![codecov](https://codecov.io/gh/gin-contrib/cors/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/cors) [![codecov](https://codecov.io/gh/gin-contrib/cors/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/cors)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/cors)](https://goreportcard.com/report/github.com/gin-contrib/cors) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/cors)](https://goreportcard.com/report/github.com/gin-contrib/cors)
[![GoDoc](https://godoc.org/github.com/gin-contrib/cors?status.svg)](https://godoc.org/github.com/gin-contrib/cors) [![GoDoc](https://godoc.org/github.com/gin-contrib/cors?status.svg)](https://godoc.org/github.com/gin-contrib/cors)
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin)
Gin middleware/handler to enable CORS support. Gin middleware/handler to enable CORS support.
@ -13,16 +12,16 @@ Gin middleware/handler to enable CORS support.
### Start using it ### Start using it
1. Download and install it: Download and install it:
```sh ```sh
$ go get gopkg.in/gin-contrib/cors.v1 $ go get github.com/gin-contrib/cors
``` ```
2. Import it in your code: Import it in your code:
```go ```go
import "gopkg.in/gin-contrib/cors.v1" import "github.com/gin-contrib/cors"
``` ```
### Canonical example: ### Canonical example:
@ -33,8 +32,8 @@ package main
import ( import (
"time" "time"
"gopkg.in/gin-contrib/cors.v1" "github.com/gin-contrib/cors"
"gopkg.in/gin-gonic/gin.v1" "github.com/gin-gonic/gin"
) )
func main() { func main() {

View File

@ -3,11 +3,12 @@ package cors
import ( import (
"net/http" "net/http"
"gopkg.in/gin-gonic/gin.v1" "github.com/gin-gonic/gin"
) )
type cors struct { type cors struct {
allowAllOrigins bool allowAllOrigins bool
allowCredentials bool
allowOriginFunc func(string) bool allowOriginFunc func(string) bool
allowOrigins []string allowOrigins []string
exposeHeaders []string exposeHeaders []string
@ -22,6 +23,7 @@ func newCors(config Config) *cors {
return &cors{ return &cors{
allowOriginFunc: config.AllowOriginFunc, allowOriginFunc: config.AllowOriginFunc,
allowAllOrigins: config.AllowAllOrigins, allowAllOrigins: config.AllowAllOrigins,
allowCredentials: config.AllowCredentials,
allowOrigins: normalize(config.AllowOrigins), allowOrigins: normalize(config.AllowOrigins),
normalHeaders: generateNormalHeaders(config), normalHeaders: generateNormalHeaders(config),
preflightHeaders: generatePreflightHeaders(config), preflightHeaders: generatePreflightHeaders(config),

10
cors.go
View File

@ -5,7 +5,7 @@ import (
"strings" "strings"
"time" "time"
"gopkg.in/gin-gonic/gin.v1" "github.com/gin-gonic/gin"
) )
// Config represents all available options for the middleware. // Config represents all available options for the middleware.
@ -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 []
AllowOrigins []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
@ -28,8 +28,6 @@ type Config struct {
// 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.
// Default value is [] but "Origin" is always appended to the list.
AllowHeaders []string AllowHeaders []string
// AllowCredentials indicates whether the request can include user credentials like // AllowCredentials indicates whether the request can include user credentials like
@ -69,8 +67,8 @@ func (c Config) Validate() error {
return errors.New("conflict settings: all origins disabled") return errors.New("conflict settings: all origins disabled")
} }
for _, origin := range c.AllowOrigins { for _, origin := range c.AllowOrigins {
if !strings.HasPrefix(origin, "http://") && !strings.HasPrefix(origin, "https://") { if origin != "*" && !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 either be '*' or include http:// or https://")
} }
} }
return nil return nil

View File

@ -3,11 +3,12 @@ package cors
import ( import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings"
"testing" "testing"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/gin-gonic/gin.v1"
) )
func init() { func init() {
@ -94,6 +95,14 @@ func TestNormalize(t *testing.T) {
assert.Equal(t, values, []string{}) assert.Equal(t, values, []string{})
} }
func TestConvert(t *testing.T) {
methods := []string{"Get", "GET", "get"}
headers := []string{"X-CSRF-TOKEN", "X-CSRF-Token", "x-csrf-token"}
assert.Equal(t, []string{"GET", "GET", "GET"}, convert(methods, strings.ToUpper))
assert.Equal(t, []string{"X-Csrf-Token", "X-Csrf-Token", "X-Csrf-Token"}, convert(headers, http.CanonicalHeaderKey))
}
func TestGenerateNormalHeaders_AllowAllOrigins(t *testing.T) { func TestGenerateNormalHeaders_AllowAllOrigins(t *testing.T) {
header := generateNormalHeaders(Config{ header := generateNormalHeaders(Config{
AllowAllOrigins: false, AllowAllOrigins: false,
@ -123,7 +132,7 @@ func TestGenerateNormalHeaders_ExposedHeaders(t *testing.T) {
header := generateNormalHeaders(Config{ header := generateNormalHeaders(Config{
ExposeHeaders: []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)
} }
@ -157,7 +166,7 @@ func TestGeneratePreflightHeaders_AllowedMethods(t *testing.T) {
header := generatePreflightHeaders(Config{ header := generatePreflightHeaders(Config{
AllowMethods: []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)
} }
@ -166,7 +175,7 @@ func TestGeneratePreflightHeaders_AllowedHeaders(t *testing.T) {
header := generatePreflightHeaders(Config{ header := generatePreflightHeaders(Config{
AllowHeaders: []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)
} }
@ -208,7 +217,7 @@ func TestPassesAllowedOrigins(t *testing.T) {
AllowMethods: []string{" GeT ", "get", "post", "PUT ", "Head", "POST"}, AllowMethods: []string{" GeT ", "get", "post", "PUT ", "Head", "POST"},
AllowHeaders: []string{"Content-type", "timeStamp "}, AllowHeaders: []string{"Content-type", "timeStamp "},
ExposeHeaders: []string{"Data", "x-User"}, ExposeHeaders: []string{"Data", "x-User"},
AllowCredentials: true, AllowCredentials: false,
MaxAge: 12 * time.Hour, MaxAge: 12 * time.Hour,
AllowOriginFunc: func(origin string) bool { AllowOriginFunc: func(origin string) bool {
return origin == "http://github.com" return origin == "http://github.com"
@ -217,37 +226,43 @@ func TestPassesAllowedOrigins(t *testing.T) {
// no CORS request, origin == "" // no CORS request, origin == ""
w := performRequest(router, "GET", "") w := performRequest(router, "GET", "")
assert.Equal(t, w.Body.String(), "get") assert.Equal(t, "get", w.Body.String())
assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers")) assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
// allowed CORS request // allowed CORS request
w = performRequest(router, "GET", "http://google.com") w = performRequest(router, "GET", "http://google.com")
assert.Equal(t, w.Body.String(), "get") assert.Equal(t, "get", w.Body.String())
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://google.com") assert.Equal(t, "http://google.com", w.Header().Get("Access-Control-Allow-Origin"))
assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true") assert.Equal(t, "", w.Header().Get("Access-Control-Allow-Credentials"))
assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data,x-user") assert.Equal(t, "Data,X-User", w.Header().Get("Access-Control-Expose-Headers"))
w = performRequest(router, "GET", "http://github.com")
assert.Equal(t, "get", w.Body.String())
assert.Equal(t, "http://github.com", w.Header().Get("Access-Control-Allow-Origin"))
assert.Equal(t, "", w.Header().Get("Access-Control-Allow-Credentials"))
assert.Equal(t, "Data,X-User", w.Header().Get("Access-Control-Expose-Headers"))
// deny CORS request // deny CORS request
w = performRequest(router, "GET", "https://google.com") w = performRequest(router, "GET", "https://google.com")
assert.Equal(t, w.Code, 403) assert.Equal(t, 403, w.Code)
assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers")) assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
// allowed CORS prefligh request // allowed CORS prefligh request
w = performRequest(router, "OPTIONS", "http://github.com") w = performRequest(router, "OPTIONS", "http://github.com")
assert.Equal(t, w.Code, 200) assert.Equal(t, 200, w.Code)
assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://github.com") assert.Equal(t, "http://github.com", w.Header().Get("Access-Control-Allow-Origin"))
assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true") assert.Equal(t, "", w.Header().Get("Access-Control-Allow-Credentials"))
assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "get,post,put,head") assert.Equal(t, "GET,POST,PUT,HEAD", w.Header().Get("Access-Control-Allow-Methods"))
assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,timestamp") assert.Equal(t, "Content-Type,Timestamp", w.Header().Get("Access-Control-Allow-Headers"))
assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "43200") assert.Equal(t, "43200", w.Header().Get("Access-Control-Max-Age"))
// deny CORS prefligh request // deny CORS prefligh request
w = performRequest(router, "OPTIONS", "http://example.com") w = performRequest(router, "OPTIONS", "http://example.com")
assert.Equal(t, w.Code, 403) assert.Equal(t, 403, w.Code)
assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Methods")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Methods"))
@ -267,24 +282,26 @@ func TestPassesAllowedAllOrigins(t *testing.T) {
// no CORS request, origin == "" // no CORS request, origin == ""
w := performRequest(router, "GET", "") w := performRequest(router, "GET", "")
assert.Equal(t, w.Body.String(), "get") assert.Equal(t, "get", w.Body.String())
assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers")) assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
// allowed CORS request // allowed CORS request
w = performRequest(router, "POST", "example.com") w = performRequest(router, "POST", "example.com")
assert.Equal(t, w.Body.String(), "post") assert.Equal(t, "post", w.Body.String())
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, "Data2,X-User2", w.Header().Get("Access-Control-Expose-Headers"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
// 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, 200, w.Code)
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, "PATCH,GET,POST", w.Header().Get("Access-Control-Allow-Methods"))
assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,testheader") assert.Equal(t, "Content-Type,Testheader", w.Header().Get("Access-Control-Allow-Headers"))
assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "36000") assert.Equal(t, "36000", w.Header().Get("Access-Control-Max-Age"))
assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials")) assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
} }

View File

@ -3,8 +3,8 @@ package main
import ( import (
"time" "time"
"gopkg.in/gin-contrib/cors.v1" "github.com/gin-contrib/cors"
"gopkg.in/gin-gonic/gin.v1" "github.com/gin-gonic/gin"
) )
func main() { func main() {

View File

@ -7,13 +7,15 @@ import (
"time" "time"
) )
type converter func(string) string
func generateNormalHeaders(c Config) http.Header { func generateNormalHeaders(c Config) http.Header {
headers := make(http.Header) headers := make(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.ExposeHeaders) > 0 { if len(c.ExposeHeaders) > 0 {
exposeHeaders := normalize(c.ExposeHeaders) exposeHeaders := convert(normalize(c.ExposeHeaders), http.CanonicalHeaderKey)
headers.Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ",")) headers.Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ","))
} }
if c.AllowAllOrigins { if c.AllowAllOrigins {
@ -30,12 +32,12 @@ func generatePreflightHeaders(c Config) http.Header {
headers.Set("Access-Control-Allow-Credentials", "true") headers.Set("Access-Control-Allow-Credentials", "true")
} }
if len(c.AllowMethods) > 0 { if len(c.AllowMethods) > 0 {
allowMethods := normalize(c.AllowMethods) allowMethods := convert(normalize(c.AllowMethods), strings.ToUpper)
value := strings.Join(allowMethods, ",") value := strings.Join(allowMethods, ",")
headers.Set("Access-Control-Allow-Methods", value) headers.Set("Access-Control-Allow-Methods", value)
} }
if len(c.AllowHeaders) > 0 { if len(c.AllowHeaders) > 0 {
allowHeaders := normalize(c.AllowHeaders) allowHeaders := convert(normalize(c.AllowHeaders), http.CanonicalHeaderKey)
value := strings.Join(allowHeaders, ",") value := strings.Join(allowHeaders, ",")
headers.Set("Access-Control-Allow-Headers", value) headers.Set("Access-Control-Allow-Headers", value)
} }
@ -46,7 +48,13 @@ func generatePreflightHeaders(c Config) http.Header {
if c.AllowAllOrigins { if c.AllowAllOrigins {
headers.Set("Access-Control-Allow-Origin", "*") headers.Set("Access-Control-Allow-Origin", "*")
} else { } else {
headers.Set("Vary", "Origin") // Always set Vary headers
// see https://github.com/rs/cors/issues/10,
// https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
headers.Add("Vary", "Origin")
headers.Add("Vary", "Access-Control-Request-Method")
headers.Add("Vary", "Access-Control-Request-Headers")
} }
return headers return headers
} }
@ -67,3 +75,11 @@ func normalize(values []string) []string {
} }
return normalized return normalized
} }
func convert(s []string, c converter) []string {
var out []string
for _, i := range s {
out = append(out, c(i))
}
return out
}