1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-10 22:49:13 +08:00
Files
kubo/commands/http/handler_test.go
Juan Batiz-Benet 8f35c3bcd9 more serious CORS tests.
this commit introduces more serious CORS tests that check
status response codes, and run real HTTP requests.

License: MIT
Signed-off-by: Juan Batiz-Benet <juan@benet.ai>
2015-07-28 23:08:11 -07:00

341 lines
8.0 KiB
Go

package http
import (
"net/http"
"net/http/httptest"
"net/url"
"testing"
cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
cmds "github.com/ipfs/go-ipfs/commands"
ipfscmd "github.com/ipfs/go-ipfs/core/commands"
coremock "github.com/ipfs/go-ipfs/core/mock"
)
func assertHeaders(t *testing.T, resHeaders http.Header, reqHeaders map[string]string) {
for name, value := range reqHeaders {
if resHeaders.Get(name) != value {
t.Errorf("Invalid header '%s', wanted '%s', got '%s'", name, value, resHeaders.Get(name))
}
}
}
func assertStatus(t *testing.T, actual, expected int) {
if actual != expected {
t.Errorf("Expected status: %d got: %d", expected, actual)
}
}
func originCfg(origins []string) *ServerConfig {
return &ServerConfig{
CORSOpts: &cors.Options{
AllowedOrigins: origins,
},
}
}
type testCase struct {
Method string
Path string
Code int
Origin string
Referer string
AllowOrigins []string
ReqHeaders map[string]string
ResHeaders map[string]string
}
func getTestServer(t *testing.T, origins []string) *httptest.Server {
cmdsCtx, err := coremock.MockCmdsCtx()
if err != nil {
t.Error("failure to initialize mock cmds ctx", err)
return nil
}
cmdRoot := &cmds.Command{
Subcommands: map[string]*cmds.Command{
"version": ipfscmd.VersionCmd,
},
}
handler := NewHandler(cmdsCtx, cmdRoot, originCfg(origins))
return httptest.NewServer(handler)
}
func (tc *testCase) test(t *testing.T) {
// defaults
method := tc.Method
if method == "" {
method = "GET"
}
path := tc.Path
if path == "" {
path = "/api/v0/version"
}
expectCode := tc.Code
if expectCode == 0 {
expectCode = 200
}
// request
req, err := http.NewRequest(method, path, nil)
if err != nil {
t.Error(err)
return
}
for k, v := range tc.ReqHeaders {
req.Header.Add(k, v)
}
if tc.Origin != "" {
req.Header.Add("Origin", tc.Origin)
}
if tc.Referer != "" {
req.Header.Add("Referer", tc.Referer)
}
// server
server := getTestServer(t, tc.AllowOrigins)
if server == nil {
return
}
defer server.Close()
req.URL, err = url.Parse(server.URL + path)
if err != nil {
t.Error(err)
return
}
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Error(err)
return
}
// checks
t.Log("GET", server.URL+path, req.Header, res.Header)
assertHeaders(t, res.Header, tc.ResHeaders)
assertStatus(t, res.StatusCode, expectCode)
}
func TestDisallowedOrigins(t *testing.T) {
gtc := func(origin string, allowedOrigins []string) testCase {
return testCase{
Origin: origin,
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: "",
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusForbidden,
}
}
tcs := []testCase{
gtc("http://barbaz.com", nil),
gtc("http://barbaz.com", []string{"http://localhost"}),
gtc("http://127.0.0.1", []string{"http://localhost"}),
gtc("http://localhost", []string{"http://127.0.0.1"}),
gtc("http://127.0.0.1:1234", nil),
gtc("http://localhost:1234", nil),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestAllowedOrigins(t *testing.T) {
gtc := func(origin string, allowedOrigins []string) testCase {
return testCase{
Origin: origin,
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: origin,
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusOK,
}
}
tcs := []testCase{
gtc("http://barbaz.com", []string{"http://barbaz.com", "http://localhost"}),
gtc("http://localhost", []string{"http://barbaz.com", "http://localhost"}),
gtc("http://localhost", nil),
gtc("http://127.0.0.1", nil),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestWildcardOrigin(t *testing.T) {
gtc := func(origin string, allowedOrigins []string) testCase {
return testCase{
Origin: origin,
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: origin,
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusOK,
}
}
tcs := []testCase{
gtc("http://barbaz.com", []string{"*"}),
gtc("http://barbaz.com", []string{"http://localhost", "*"}),
gtc("http://127.0.0.1", []string{"http://localhost", "*"}),
gtc("http://localhost", []string{"http://127.0.0.1", "*"}),
gtc("http://127.0.0.1", []string{"*"}),
gtc("http://localhost", []string{"*"}),
gtc("http://127.0.0.1:1234", []string{"*"}),
gtc("http://localhost:1234", []string{"*"}),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestDisallowedReferer(t *testing.T) {
gtc := func(referer string, allowedOrigins []string) testCase {
return testCase{
Origin: "http://localhost",
Referer: referer,
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: "http://localhost",
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusForbidden,
}
}
tcs := []testCase{
gtc("http://foobar.com", nil),
gtc("http://localhost:1234", nil),
gtc("http://127.0.0.1:1234", nil),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestAllowedReferer(t *testing.T) {
gtc := func(referer string, allowedOrigins []string) testCase {
return testCase{
Origin: "http://localhost",
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: "http://localhost",
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusOK,
}
}
tcs := []testCase{
gtc("http://barbaz.com", []string{"http://barbaz.com", "http://localhost"}),
gtc("http://localhost", []string{"http://barbaz.com", "http://localhost"}),
gtc("http://localhost", nil),
gtc("http://127.0.0.1", nil),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestWildcardReferer(t *testing.T) {
gtc := func(origin string, allowedOrigins []string) testCase {
return testCase{
Origin: origin,
AllowOrigins: allowedOrigins,
ResHeaders: map[string]string{
ACAOrigin: origin,
ACAMethods: "",
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
},
Code: http.StatusOK,
}
}
tcs := []testCase{
gtc("http://barbaz.com", []string{"*"}),
gtc("http://barbaz.com", []string{"http://localhost", "*"}),
gtc("http://127.0.0.1", []string{"http://localhost", "*"}),
gtc("http://localhost", []string{"http://127.0.0.1", "*"}),
gtc("http://127.0.0.1", []string{"*"}),
gtc("http://localhost", []string{"*"}),
gtc("http://127.0.0.1:1234", []string{"*"}),
gtc("http://localhost:1234", []string{"*"}),
}
for _, tc := range tcs {
tc.test(t)
}
}
func TestAllowedMethod(t *testing.T) {
gtc := func(method string, ok bool) testCase {
code := http.StatusOK
hdrs := map[string]string{
ACAOrigin: "http://localhost",
ACAMethods: method,
ACACredentials: "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
}
if !ok {
hdrs[ACAOrigin] = ""
hdrs[ACAMethods] = ""
}
return testCase{
Method: "OPTIONS",
Origin: "http://localhost",
AllowOrigins: []string{"*"},
ReqHeaders: map[string]string{
"Access-Control-Request-Method": method,
},
ResHeaders: hdrs,
Code: code,
}
}
tcs := []testCase{
gtc("PUT", true),
gtc("GET", true),
gtc("FOOBAR", false),
}
for _, tc := range tcs {
tc.test(t)
}
}