cors_test.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package cors
  2. import (
  3. "net/http"
  4. "net/http/httptest"
  5. "testing"
  6. "time"
  7. "github.com/gin-gonic/gin"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func init() {
  11. gin.SetMode(gin.TestMode)
  12. }
  13. func newTestRouter(config Config) *gin.Engine {
  14. router := gin.New()
  15. router.Use(New(config))
  16. router.GET("/", func(c *gin.Context) {
  17. c.String(200, "get")
  18. })
  19. router.POST("/", func(c *gin.Context) {
  20. c.String(200, "post")
  21. })
  22. router.PATCH("/", func(c *gin.Context) {
  23. c.String(200, "patch")
  24. })
  25. return router
  26. }
  27. func performRequest(r http.Handler, method, origin string) *httptest.ResponseRecorder {
  28. req, _ := http.NewRequest(method, "/", nil)
  29. if len(origin) > 0 {
  30. req.Header.Set("Origin", origin)
  31. }
  32. w := httptest.NewRecorder()
  33. r.ServeHTTP(w, req)
  34. return w
  35. }
  36. func TestBadConfig(t *testing.T) {
  37. assert.Panics(t, func() { New(Config{}) })
  38. assert.Panics(t, func() {
  39. New(Config{
  40. AllowAllOrigins: true,
  41. AllowOrigins: []string{"http://google.com"},
  42. })
  43. })
  44. assert.Panics(t, func() {
  45. New(Config{
  46. AllowAllOrigins: true,
  47. AllowOriginFunc: func(origin string) bool { return false },
  48. })
  49. })
  50. assert.Panics(t, func() {
  51. New(Config{
  52. AllowOrigins: []string{"google.com"},
  53. })
  54. })
  55. }
  56. func TestNormalize(t *testing.T) {
  57. values := normalize([]string{
  58. "http-Access ", "Post", "POST", " poSt ",
  59. "HTTP-Access", "",
  60. })
  61. assert.Equal(t, values, []string{"http-access", "post", ""})
  62. values = normalize(nil)
  63. assert.Nil(t, values)
  64. values = normalize([]string{})
  65. assert.Equal(t, values, []string{})
  66. }
  67. func TestGenerateNormalHeaders_AllowAllOrigins(t *testing.T) {
  68. header := generateNormalHeaders(Config{
  69. AllowAllOrigins: false,
  70. })
  71. assert.Equal(t, header.Get("Access-Control-Allow-Origin"), "")
  72. assert.Equal(t, header.Get("Vary"), "Origin")
  73. assert.Len(t, header, 1)
  74. header = generateNormalHeaders(Config{
  75. AllowAllOrigins: true,
  76. })
  77. assert.Equal(t, header.Get("Access-Control-Allow-Origin"), "*")
  78. assert.Equal(t, header.Get("Vary"), "")
  79. assert.Len(t, header, 1)
  80. }
  81. func TestGenerateNormalHeaders_AllowCredentials(t *testing.T) {
  82. header := generateNormalHeaders(Config{
  83. AllowCredentials: true,
  84. })
  85. assert.Equal(t, header.Get("Access-Control-Allow-Credentials"), "true")
  86. assert.Equal(t, header.Get("Vary"), "Origin")
  87. assert.Len(t, header, 2)
  88. }
  89. func TestGenerateNormalHeaders_ExposedHeaders(t *testing.T) {
  90. header := generateNormalHeaders(Config{
  91. ExposeHeaders: []string{"X-user", "xPassword"},
  92. })
  93. assert.Equal(t, header.Get("Access-Control-Expose-Headers"), "x-user,xpassword")
  94. assert.Equal(t, header.Get("Vary"), "Origin")
  95. assert.Len(t, header, 2)
  96. }
  97. func TestGeneratePreflightHeaders(t *testing.T) {
  98. header := generatePreflightHeaders(Config{
  99. AllowAllOrigins: false,
  100. })
  101. assert.Equal(t, header.Get("Access-Control-Allow-Origin"), "")
  102. assert.Equal(t, header.Get("Vary"), "Origin")
  103. assert.Len(t, header, 1)
  104. header = generateNormalHeaders(Config{
  105. AllowAllOrigins: true,
  106. })
  107. assert.Equal(t, header.Get("Access-Control-Allow-Origin"), "*")
  108. assert.Equal(t, header.Get("Vary"), "")
  109. assert.Len(t, header, 1)
  110. }
  111. func TestGeneratePreflightHeaders_AllowCredentials(t *testing.T) {
  112. header := generatePreflightHeaders(Config{
  113. AllowCredentials: true,
  114. })
  115. assert.Equal(t, header.Get("Access-Control-Allow-Credentials"), "true")
  116. assert.Equal(t, header.Get("Vary"), "Origin")
  117. assert.Len(t, header, 2)
  118. }
  119. func TestGeneratePreflightHeaders_AllowedMethods(t *testing.T) {
  120. header := generatePreflightHeaders(Config{
  121. AllowMethods: []string{"GET ", "post", "PUT", " put "},
  122. })
  123. assert.Equal(t, header.Get("Access-Control-Allow-Methods"), "get,post,put")
  124. assert.Equal(t, header.Get("Vary"), "Origin")
  125. assert.Len(t, header, 2)
  126. }
  127. func TestGeneratePreflightHeaders_AllowedHeaders(t *testing.T) {
  128. header := generatePreflightHeaders(Config{
  129. AllowHeaders: []string{"X-user", "Content-Type"},
  130. })
  131. assert.Equal(t, header.Get("Access-Control-Allow-Headers"), "x-user,content-type")
  132. assert.Equal(t, header.Get("Vary"), "Origin")
  133. assert.Len(t, header, 2)
  134. }
  135. func TestGeneratePreflightHeaders_MaxAge(t *testing.T) {
  136. header := generatePreflightHeaders(Config{
  137. MaxAge: 12 * time.Hour,
  138. })
  139. assert.Equal(t, header.Get("Access-Control-Max-Age"), "43200") // 12*60*60
  140. assert.Equal(t, header.Get("Vary"), "Origin")
  141. assert.Len(t, header, 2)
  142. }
  143. func TestValidateOrigin(t *testing.T) {
  144. cors := newCors(Config{
  145. AllowAllOrigins: true,
  146. })
  147. assert.True(t, cors.validateOrigin("http://google.com"))
  148. assert.True(t, cors.validateOrigin("https://google.com"))
  149. assert.True(t, cors.validateOrigin("example.com"))
  150. cors = newCors(Config{
  151. AllowOrigins: []string{"https://google.com", "https://github.com"},
  152. AllowOriginFunc: func(origin string) bool {
  153. return (origin == "http://news.ycombinator.com")
  154. },
  155. })
  156. assert.False(t, cors.validateOrigin("http://google.com"))
  157. assert.True(t, cors.validateOrigin("https://google.com"))
  158. assert.True(t, cors.validateOrigin("https://github.com"))
  159. assert.True(t, cors.validateOrigin("http://news.ycombinator.com"))
  160. assert.False(t, cors.validateOrigin("http://example.com"))
  161. assert.False(t, cors.validateOrigin("google.com"))
  162. }
  163. func TestPassesAllowedOrigins(t *testing.T) {
  164. router := newTestRouter(Config{
  165. AllowOrigins: []string{"http://google.com"},
  166. AllowMethods: []string{" GeT ", "get", "post", "PUT ", "Head", "POST"},
  167. AllowHeaders: []string{"Content-type", "timeStamp "},
  168. ExposeHeaders: []string{"Data", "x-User"},
  169. AllowCredentials: true,
  170. MaxAge: 12 * time.Hour,
  171. AllowOriginFunc: func(origin string) bool {
  172. return origin == "http://github.com"
  173. },
  174. })
  175. // no CORS request, origin == ""
  176. w := performRequest(router, "GET", "")
  177. assert.Equal(t, w.Body.String(), "get")
  178. assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
  179. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  180. assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
  181. // allowed CORS request
  182. w = performRequest(router, "GET", "http://google.com")
  183. assert.Equal(t, w.Body.String(), "get")
  184. assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://google.com")
  185. assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true")
  186. assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data,x-user")
  187. // deny CORS request
  188. w = performRequest(router, "GET", "https://google.com")
  189. assert.Equal(t, w.Code, 403)
  190. assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
  191. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  192. assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
  193. // allowed CORS prefligh request
  194. w = performRequest(router, "OPTIONS", "http://github.com")
  195. assert.Equal(t, w.Code, 200)
  196. assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "http://github.com")
  197. assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "true")
  198. assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "get,post,put,head")
  199. assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,timestamp")
  200. assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "43200")
  201. // deny CORS prefligh request
  202. w = performRequest(router, "OPTIONS", "http://example.com")
  203. assert.Equal(t, w.Code, 403)
  204. assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
  205. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  206. assert.Empty(t, w.Header().Get("Access-Control-Allow-Methods"))
  207. assert.Empty(t, w.Header().Get("Access-Control-Allow-Headers"))
  208. assert.Empty(t, w.Header().Get("Access-Control-Max-Age"))
  209. }
  210. func TestPassesAllowedAllOrigins(t *testing.T) {
  211. router := newTestRouter(Config{
  212. AllowAllOrigins: true,
  213. AllowMethods: []string{" Patch ", "get", "post", "POST"},
  214. AllowHeaders: []string{"Content-type", " testheader "},
  215. ExposeHeaders: []string{"Data2", "x-User2"},
  216. AllowCredentials: false,
  217. MaxAge: 10 * time.Hour,
  218. })
  219. // no CORS request, origin == ""
  220. w := performRequest(router, "GET", "")
  221. assert.Equal(t, w.Body.String(), "get")
  222. assert.Empty(t, w.Header().Get("Access-Control-Allow-Origin"))
  223. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  224. assert.Empty(t, w.Header().Get("Access-Control-Expose-Headers"))
  225. // allowed CORS request
  226. w = performRequest(router, "POST", "example.com")
  227. assert.Equal(t, w.Body.String(), "post")
  228. assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*")
  229. assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "data2,x-user2")
  230. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  231. // allowed CORS prefligh request
  232. w = performRequest(router, "OPTIONS", "https://facebook.com")
  233. assert.Equal(t, w.Code, 200)
  234. assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*")
  235. assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "patch,get,post")
  236. assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "content-type,testheader")
  237. assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "36000")
  238. assert.Empty(t, w.Header().Get("Access-Control-Allow-Credentials"))
  239. }