github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/gateway_test.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"net/url"
    13  	"os"
    14  	"runtime"
    15  	"strconv"
    16  
    17  	"strings"
    18  	"sync"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/go-redis/redis"
    23  	"github.com/gorilla/websocket"
    24  	proxyproto "github.com/pires/go-proxyproto"
    25  	msgpack "gopkg.in/vmihailenco/msgpack.v2"
    26  
    27  	"github.com/TykTechnologies/tyk/apidef"
    28  	"github.com/TykTechnologies/tyk/cli"
    29  	"github.com/TykTechnologies/tyk/config"
    30  	"github.com/TykTechnologies/tyk/storage"
    31  	"github.com/TykTechnologies/tyk/test"
    32  	"github.com/TykTechnologies/tyk/user"
    33  )
    34  
    35  const defaultListenPort = 8080
    36  
    37  func TestMain(m *testing.M) {
    38  	os.Exit(InitTestMain(context.Background(), m))
    39  }
    40  
    41  func createNonThrottledSession() *user.SessionState {
    42  	session := new(user.SessionState)
    43  	session.Rate = 100.0
    44  	session.Allowance = session.Rate
    45  	session.LastCheck = time.Now().Unix()
    46  	session.Per = 1.0
    47  	session.QuotaRenewalRate = 300 // 5 minutes
    48  	session.QuotaRenews = time.Now().Unix()
    49  	session.QuotaRemaining = 10
    50  	session.QuotaMax = 10
    51  	session.Alias = "TEST-ALIAS"
    52  	session.Mutex = &sync.RWMutex{}
    53  	return session
    54  }
    55  
    56  func TestAA(t *testing.T) {
    57  	ts := StartTest()
    58  
    59  	ts.Start()
    60  	defer ts.Close()
    61  
    62  	BuildAndLoadAPI(func(spec *APISpec) {
    63  		spec.Proxy.ListenPath = "/"
    64  	})
    65  
    66  	ts.Run(t, []test.TestCase{
    67  		{Code: 200},
    68  	}...)
    69  
    70  }
    71  
    72  type tykErrorResponse struct {
    73  	Error string
    74  }
    75  
    76  func testKey(testName string, name string) string {
    77  	return fmt.Sprintf("%s-%s", testName, name)
    78  }
    79  
    80  func TestParambasedAuth(t *testing.T) {
    81  	ts := StartTest()
    82  	defer ts.Close()
    83  
    84  	BuildAndLoadAPI(func(spec *APISpec) {
    85  		spec.Auth.UseParam = true
    86  		spec.UseKeylessAccess = false
    87  		spec.Proxy.ListenPath = "/"
    88  	})
    89  
    90  	key := CreateSession(func(s *user.SessionState) {
    91  		s.SetAccessRights(map[string]user.AccessDefinition{"test": {
    92  			APIID: "test", Versions: []string{"v1"},
    93  		}})
    94  		s.Mutex = &sync.RWMutex{}
    95  	})
    96  
    97  	form := url.Values{}
    98  	form.Add("foo", "swiggetty")
    99  	form.Add("bar", "swoggetty")
   100  	form.Add("baz", "swoogetty")
   101  
   102  	expectedBody := `"Form":{"authorization":"` + key + `","bar":"swoggetty","baz":"swoogetty","foo":"swiggetty"}`
   103  
   104  	ts.Run(t, test.TestCase{
   105  		Method:    "POST",
   106  		Path:      "/?authorization=" + key,
   107  		Headers:   map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
   108  		Data:      string(form.Encode()),
   109  		Code:      200,
   110  		BodyMatch: expectedBody,
   111  	})
   112  }
   113  
   114  func TestStripPathWithURLRewrite(t *testing.T) {
   115  	ts := StartTest()
   116  	defer ts.Close()
   117  	defer ResetTestConfig()
   118  
   119  	t.Run("rewrite URL containing listen path", func(t *testing.T) {
   120  		BuildAndLoadAPI(func(spec *APISpec) {
   121  			version := spec.VersionData.Versions["v1"]
   122  			json.Unmarshal([]byte(`{
   123                  "use_extended_paths": true,
   124                  "extended_paths": {
   125                          "url_rewrites": [{
   126                                  "path": "/anything/",
   127                                  "match_pattern": "/anything/(.*)",
   128                                  "method": "GET",
   129  				"rewrite_to":"/something/$1"
   130                          }]
   131                  }
   132              }`), &version)
   133  			spec.VersionData.Versions["v1"] = version
   134  			spec.Proxy.ListenPath = "/myapi/"
   135  			spec.Proxy.StripListenPath = true
   136  
   137  		})
   138  
   139  		ts.Run(t, []test.TestCase{
   140  			{Path: "/myapi/anything/a/myapi/b/c", BodyMatch: `"Url":"/something/a/myapi/b/c"`},
   141  		}...)
   142  	})
   143  }
   144  
   145  func TestSkipTargetPassEscapingOff(t *testing.T) {
   146  	ts := StartTest()
   147  	defer ts.Close()
   148  	defer ResetTestConfig()
   149  
   150  	t.Run("With escaping, default", func(t *testing.T) {
   151  		globalConf := config.Global()
   152  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   153  		config.SetGlobal(globalConf)
   154  
   155  		BuildAndLoadAPI(func(spec *APISpec) {
   156  			spec.Proxy.ListenPath = "/"
   157  		})
   158  
   159  		ts.Run(t, []test.TestCase{
   160  			{Path: "/(abc,xyz)?arg=val", BodyMatch: `"Url":"/%28abc,xyz%29\?arg=val`},
   161  			{Path: "/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/%28abc,xyz%29\?arg=val`},
   162  		}...)
   163  	})
   164  
   165  	t.Run("Without escaping", func(t *testing.T) {
   166  		globalConf := config.Global()
   167  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   168  		config.SetGlobal(globalConf)
   169  
   170  		BuildAndLoadAPI(func(spec *APISpec) {
   171  			spec.Proxy.ListenPath = "/"
   172  		})
   173  
   174  		ts.Run(t, []test.TestCase{
   175  			{Path: "/(abc,xyz)?arg=val", BodyMatch: `"Url":"/\(abc,xyz\)\?arg=val"`},
   176  			{Path: "/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/%28abc,xyz%29\?arg=val"`},
   177  		}...)
   178  	})
   179  
   180  	t.Run("With escaping, listen path and target URL are set, StripListenPath is OFF", func(t *testing.T) {
   181  		globalConf := config.Global()
   182  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   183  		config.SetGlobal(globalConf)
   184  
   185  		BuildAndLoadAPI(func(spec *APISpec) {
   186  			spec.Proxy.StripListenPath = false
   187  			spec.Proxy.ListenPath = "/listen_me"
   188  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   189  		})
   190  
   191  		ts.Run(t, []test.TestCase{
   192  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   193  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   194  		}...)
   195  	})
   196  
   197  	t.Run("Without escaping, listen path and target URL are set, StripListenPath is OFF", func(t *testing.T) {
   198  		globalConf := config.Global()
   199  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   200  		config.SetGlobal(globalConf)
   201  
   202  		BuildAndLoadAPI(func(spec *APISpec) {
   203  			spec.Proxy.StripListenPath = false
   204  			spec.Proxy.ListenPath = "/listen_me"
   205  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   206  		})
   207  
   208  		ts.Run(t, []test.TestCase{
   209  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/\(abc,xyz\)\?arg=val"`},
   210  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   211  		}...)
   212  	})
   213  
   214  	t.Run("With escaping, listen path and target URL are set, StripListenPath is ON", func(t *testing.T) {
   215  		globalConf := config.Global()
   216  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   217  		config.SetGlobal(globalConf)
   218  
   219  		BuildAndLoadAPI(func(spec *APISpec) {
   220  			spec.Proxy.StripListenPath = true
   221  			spec.Proxy.ListenPath = "/listen_me"
   222  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   223  		})
   224  
   225  		ts.Run(t, []test.TestCase{
   226  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   227  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   228  		}...)
   229  	})
   230  
   231  	t.Run("Without escaping, listen path and target URL are set, StripListenPath is ON", func(t *testing.T) {
   232  		globalConf := config.Global()
   233  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   234  		config.SetGlobal(globalConf)
   235  
   236  		BuildAndLoadAPI(func(spec *APISpec) {
   237  			spec.Proxy.StripListenPath = true
   238  			spec.Proxy.ListenPath = "/listen_me"
   239  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   240  		})
   241  
   242  		ts.Run(t, []test.TestCase{
   243  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/\(abc,xyz\)\?arg=val"`},
   244  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   245  		}...)
   246  	})
   247  }
   248  
   249  func TestSkipTargetPassEscapingOffWithSkipURLCleaningTrue(t *testing.T) {
   250  	globalConf := config.Global()
   251  	globalConf.HttpServerOptions.OverrideDefaults = true
   252  	globalConf.HttpServerOptions.SkipURLCleaning = true
   253  	config.SetGlobal(globalConf)
   254  	defer ResetTestConfig()
   255  
   256  	// here we expect that test gateway will be sending to test upstream requests with not cleaned URI
   257  	// so test upstream shouldn't reply with 301 and process them as well
   258  	prevSkipClean := defaultTestConfig.HttpServerOptions.OverrideDefaults &&
   259  		defaultTestConfig.HttpServerOptions.SkipURLCleaning
   260  	testServerRouter.SkipClean(true)
   261  	defer testServerRouter.SkipClean(prevSkipClean)
   262  
   263  	ts := StartTest()
   264  	defer ts.Close()
   265  
   266  	t.Run("With escaping, default", func(t *testing.T) {
   267  		globalConf := config.Global()
   268  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   269  		config.SetGlobal(globalConf)
   270  
   271  		BuildAndLoadAPI(func(spec *APISpec) {
   272  			spec.Proxy.ListenPath = "/"
   273  		})
   274  
   275  		ts.Run(t, []test.TestCase{
   276  			{Path: "/abc/xyz/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/abc/xyz/http%3A%2F%2Ftest.com\?arg=val`},
   277  		}...)
   278  	})
   279  
   280  	t.Run("Without escaping, default", func(t *testing.T) {
   281  		globalConf := config.Global()
   282  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   283  		config.SetGlobal(globalConf)
   284  
   285  		BuildAndLoadAPI(func(spec *APISpec) {
   286  			spec.Proxy.ListenPath = "/"
   287  		})
   288  
   289  		ts.Run(t, []test.TestCase{
   290  			{Path: "/abc/xyz/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/abc/xyz/http%3A%2F%2Ftest.com\?arg=val`},
   291  		}...)
   292  	})
   293  
   294  	t.Run("With escaping, listen path and target URL are set, StripListenPath is OFF", func(t *testing.T) {
   295  		globalConf := config.Global()
   296  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   297  		config.SetGlobal(globalConf)
   298  
   299  		BuildAndLoadAPI(func(spec *APISpec) {
   300  			spec.Proxy.StripListenPath = false
   301  			spec.Proxy.ListenPath = "/listen_me"
   302  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   303  		})
   304  
   305  		ts.Run(t, []test.TestCase{
   306  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   307  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   308  			{Path: "/listen_me/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/http%3A%2F%2Ftest.com\?arg=val`},
   309  		}...)
   310  	})
   311  
   312  	t.Run("Without escaping, listen path and target URL are set, StripListenPath is OFF", func(t *testing.T) {
   313  		globalConf := config.Global()
   314  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   315  		config.SetGlobal(globalConf)
   316  
   317  		BuildAndLoadAPI(func(spec *APISpec) {
   318  			spec.Proxy.StripListenPath = false
   319  			spec.Proxy.ListenPath = "/listen_me"
   320  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   321  		})
   322  
   323  		ts.Run(t, []test.TestCase{
   324  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/\(abc,xyz\)\?arg=val"`},
   325  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/%28abc,xyz%29\?arg=val"`},
   326  			{Path: "/listen_me/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/sent_to_me/listen_me/http%3A%2F%2Ftest.com\?arg=val`},
   327  		}...)
   328  	})
   329  
   330  	t.Run("With escaping, listen path and target URL are set, StripListenPath is ON", func(t *testing.T) {
   331  		globalConf := config.Global()
   332  		globalConf.HttpServerOptions.SkipTargetPathEscaping = false
   333  		config.SetGlobal(globalConf)
   334  
   335  		BuildAndLoadAPI(func(spec *APISpec) {
   336  			spec.Proxy.StripListenPath = true
   337  			spec.Proxy.ListenPath = "/listen_me"
   338  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   339  		})
   340  
   341  		ts.Run(t, []test.TestCase{
   342  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   343  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   344  			{Path: "/listen_me/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/sent_to_me/http%3A%2F%2Ftest.com\?arg=val`},
   345  		}...)
   346  	})
   347  
   348  	t.Run("Without escaping, listen path and target URL are set, StripListenPath is ON", func(t *testing.T) {
   349  		globalConf := config.Global()
   350  		globalConf.HttpServerOptions.SkipTargetPathEscaping = true
   351  		config.SetGlobal(globalConf)
   352  
   353  		BuildAndLoadAPI(func(spec *APISpec) {
   354  			spec.Proxy.StripListenPath = true
   355  			spec.Proxy.ListenPath = "/listen_me"
   356  			spec.Proxy.TargetURL = TestHttpAny + "/sent_to_me"
   357  		})
   358  
   359  		ts.Run(t, []test.TestCase{
   360  			{Path: "/listen_me/(abc,xyz)?arg=val", BodyMatch: `"Url":"/sent_to_me/\(abc,xyz\)\?arg=val"`},
   361  			{Path: "/listen_me/%28abc,xyz%29?arg=val", BodyMatch: `"Url":"/sent_to_me/%28abc,xyz%29\?arg=val"`},
   362  			{Path: "/listen_me/http%3A%2F%2Ftest.com?arg=val", BodyMatch: `"Url":"/sent_to_me/http%3A%2F%2Ftest.com\?arg=val`},
   363  		}...)
   364  	})
   365  
   366  }
   367  
   368  func TestQuota(t *testing.T) {
   369  	ts := StartTest()
   370  	defer ts.Close()
   371  
   372  	var keyID string
   373  
   374  	var webhookWG sync.WaitGroup
   375  	webhook := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   376  		if r.Header.Get("X-Tyk-Test-Header") != "Tyk v1.BANANA" {
   377  			t.Error("Custom webhook header not set", r.Header)
   378  		}
   379  
   380  		var data map[string]string
   381  		body, _ := ioutil.ReadAll(r.Body)
   382  		json.Unmarshal(body, &data)
   383  
   384  		if data["event"] != "QuotaExceeded" || data["message"] != "Key Quota Limit Exceeded" || data["key"] != keyID {
   385  			t.Error("Webhook payload not match", data)
   386  		}
   387  
   388  		webhookWG.Done()
   389  	}))
   390  	defer webhook.Close()
   391  
   392  	BuildAndLoadAPI(func(spec *APISpec) {
   393  		spec.UseKeylessAccess = false
   394  		spec.Proxy.ListenPath = "/"
   395  
   396  		version := spec.VersionData.Versions["v1"]
   397  		json.Unmarshal([]byte(`{
   398  			"use_extended_paths": true,
   399  			"extended_paths": {
   400  				"ignored":[{
   401  					"path": "/get",
   402  					"method_actions": {"GET": {"action": "no_action"}}
   403  				}]
   404  			}
   405  		}`), &version)
   406  		spec.VersionData.Versions["v1"] = version
   407  
   408  		json.Unmarshal([]byte(`
   409  		{ "events": { "QuotaExceeded":
   410  			[{
   411  				"handler_name":"eh_log_handler",
   412  				"handler_meta": {
   413  					"prefix": "LOG-HANDLER-PREFIX"
   414  				}
   415  			},
   416  			{
   417  				"handler_name":"eh_web_hook_handler",
   418  				"handler_meta": {
   419  					"method": "POST",
   420  					"target_path": "`+webhook.URL+`",
   421  					"template_path": "templates/default_webhook.json",
   422  					"header_map": {"X-Tyk-Test-Header": "Tyk v1.BANANA"},
   423  					"event_timeout": 10
   424  				}
   425  			}]
   426  		}}`), &spec.EventHandlers)
   427  	})
   428  
   429  	// Create session with Quota = 2
   430  	keyID = CreateSession(func(s *user.SessionState) {
   431  		s.QuotaMax = 2
   432  		s.Mutex = &sync.RWMutex{}
   433  	})
   434  
   435  	authHeaders := map[string]string{
   436  		"authorization": keyID,
   437  	}
   438  
   439  	webhookWG.Add(1)
   440  	ts.Run(t, []test.TestCase{
   441  		{Path: "/", Headers: authHeaders, Code: 200},
   442  		// Ignored path should not affect quota
   443  		{Path: "/get", Headers: authHeaders, Code: 200},
   444  		{Path: "/", Headers: authHeaders, Code: 200},
   445  		{Path: "/", Headers: authHeaders, Code: 403, BodyMatch: `"error": "Quota exceeded"`},
   446  		// Ignored path works without auth
   447  		{Path: "/get", Code: 200},
   448  	}...)
   449  	webhookWG.Wait()
   450  }
   451  
   452  func TestAnalytics(t *testing.T) {
   453  	ts := StartTest(TestConfig{
   454  		Delay: 20 * time.Millisecond,
   455  	})
   456  	defer ts.Close()
   457  	base := config.Global()
   458  
   459  	BuildAndLoadAPI(func(spec *APISpec) {
   460  		spec.UseKeylessAccess = false
   461  		spec.Proxy.ListenPath = "/"
   462  	})
   463  
   464  	// Cleanup before test
   465  	// let records to to be sent
   466  	time.Sleep(recordsBufferFlushInterval + 50)
   467  	analytics.Store.GetAndDeleteSet(analyticsKeyName)
   468  
   469  	t.Run("Log errors", func(t *testing.T) {
   470  		ts.Run(t, []test.TestCase{
   471  			{Path: "/", Code: 401},
   472  			{Path: "/", Code: 401},
   473  		}...)
   474  
   475  		// let records to to be sent
   476  		time.Sleep(recordsBufferFlushInterval + 50)
   477  
   478  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   479  		if len(results) != 2 {
   480  			t.Error("Should return 2 record", len(results))
   481  		}
   482  
   483  		var record AnalyticsRecord
   484  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   485  		if record.ResponseCode != 401 {
   486  			t.Error("Analytics record do not match: ", record)
   487  		}
   488  	})
   489  
   490  	t.Run("Log success", func(t *testing.T) {
   491  		key := CreateSession()
   492  
   493  		authHeaders := map[string]string{
   494  			"authorization": key,
   495  		}
   496  
   497  		ts.Run(t, test.TestCase{
   498  			Path: "/", Headers: authHeaders, Code: 200,
   499  		})
   500  
   501  		// let records to to be sent
   502  		time.Sleep(recordsBufferFlushInterval + 50)
   503  
   504  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   505  		if len(results) != 1 {
   506  			t.Error("Should return 1 record: ", len(results))
   507  		}
   508  
   509  		var record AnalyticsRecord
   510  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   511  		if record.ResponseCode != 200 {
   512  			t.Error("Analytics record do not match", record)
   513  		}
   514  	})
   515  
   516  	t.Run("Detailed analytics with api spec config enabled", func(t *testing.T) {
   517  		defer func() {
   518  			config.SetGlobal(base)
   519  		}()
   520  		globalConf := config.Global()
   521  		globalConf.AnalyticsConfig.EnableDetailedRecording = false
   522  		config.SetGlobal(globalConf)
   523  
   524  		BuildAndLoadAPI(func(spec *APISpec) {
   525  			spec.UseKeylessAccess = false
   526  			spec.Proxy.ListenPath = "/"
   527  			spec.EnableDetailedRecording = true
   528  		})
   529  
   530  		key := CreateSession()
   531  
   532  		authHeaders := map[string]string{
   533  			"authorization": key,
   534  		}
   535  
   536  		ts.Run(t, test.TestCase{
   537  			Path: "/", Headers: authHeaders, Code: 200,
   538  		})
   539  
   540  		// let records to to be sent
   541  		time.Sleep(recordsBufferFlushInterval + 50)
   542  
   543  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   544  		if len(results) != 1 {
   545  			t.Error("Should return 1 record: ", len(results))
   546  		}
   547  
   548  		var record AnalyticsRecord
   549  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   550  		if record.ResponseCode != 200 {
   551  			t.Error("Analytics record do not match", record)
   552  		}
   553  
   554  		if record.RawRequest == "" {
   555  			t.Error("Detailed request info not found", record)
   556  		}
   557  
   558  		if record.RawResponse == "" {
   559  			t.Error("Detailed response info not found", record)
   560  		}
   561  	})
   562  
   563  	t.Run("Detailed analytics with only key flag set", func(t *testing.T) {
   564  		defer func() {
   565  			config.SetGlobal(base)
   566  		}()
   567  		globalConf := config.Global()
   568  		globalConf.AnalyticsConfig.EnableDetailedRecording = false
   569  		config.SetGlobal(globalConf)
   570  
   571  		BuildAndLoadAPI(func(spec *APISpec) {
   572  			spec.UseKeylessAccess = false
   573  			spec.Proxy.ListenPath = "/"
   574  			spec.EnableDetailedRecording = false
   575  		})
   576  
   577  		key := CreateSession(func(sess *user.SessionState) {
   578  			sess.EnableDetailedRecording = true
   579  			sess.Mutex = &sync.RWMutex{}
   580  		})
   581  
   582  		authHeaders := map[string]string{
   583  			"authorization": key,
   584  		}
   585  
   586  		ts.Run(t, test.TestCase{
   587  			Path: "/", Headers: authHeaders, Code: 200,
   588  		})
   589  
   590  		// let records to to be sent
   591  		time.Sleep(recordsBufferFlushInterval + 50)
   592  
   593  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   594  		if len(results) != 1 {
   595  			t.Error("Should return 1 record: ", len(results))
   596  		}
   597  
   598  		var record AnalyticsRecord
   599  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   600  		if record.ResponseCode != 200 {
   601  			t.Error("Analytics record do not match", record)
   602  		}
   603  
   604  		if record.RawRequest == "" {
   605  			t.Error("Detailed request info not found", record)
   606  		}
   607  
   608  		if record.RawResponse == "" {
   609  			t.Error("Detailed response info not found", record)
   610  		}
   611  	})
   612  	t.Run("Detailed analytics", func(t *testing.T) {
   613  		defer func() {
   614  			config.SetGlobal(base)
   615  		}()
   616  		globalConf := config.Global()
   617  		globalConf.AnalyticsConfig.EnableDetailedRecording = true
   618  		config.SetGlobal(globalConf)
   619  
   620  		BuildAndLoadAPI(func(spec *APISpec) {
   621  			spec.UseKeylessAccess = false
   622  			spec.Proxy.ListenPath = "/"
   623  		})
   624  
   625  		key := CreateSession()
   626  
   627  		authHeaders := map[string]string{
   628  			"authorization": key,
   629  		}
   630  
   631  		ts.Run(t, test.TestCase{
   632  			Path: "/", Headers: authHeaders, Code: 200,
   633  		})
   634  
   635  		// let records to to be sent
   636  		time.Sleep(recordsBufferFlushInterval + 50)
   637  
   638  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   639  		if len(results) != 1 {
   640  			t.Error("Should return 1 record: ", len(results))
   641  		}
   642  
   643  		var record AnalyticsRecord
   644  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   645  		if record.ResponseCode != 200 {
   646  			t.Error("Analytics record do not match", record)
   647  		}
   648  
   649  		if record.RawRequest == "" {
   650  			t.Error("Detailed request info not found", record)
   651  		}
   652  
   653  		if record.RawResponse == "" {
   654  			t.Error("Detailed response info not found", record)
   655  		}
   656  	})
   657  
   658  	t.Run("Detailed analytics with latency", func(t *testing.T) {
   659  		defer func() {
   660  			config.SetGlobal(base)
   661  		}()
   662  		globalConf := config.Global()
   663  		globalConf.AnalyticsConfig.EnableDetailedRecording = true
   664  		config.SetGlobal(globalConf)
   665  		ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   666  			// We are delaying the response by 2 ms. This is important because anytime
   667  			// less than 0 eg  0.2 ms will be round off to 0 which is not good to check if we have
   668  			// latency correctly set.
   669  			time.Sleep(2 * time.Millisecond)
   670  		}))
   671  		defer ls.Close()
   672  		BuildAndLoadAPI(func(spec *APISpec) {
   673  			spec.UseKeylessAccess = false
   674  			spec.Proxy.ListenPath = "/"
   675  			spec.Proxy.TargetURL = ls.URL
   676  		})
   677  
   678  		key := CreateSession()
   679  
   680  		authHeaders := map[string]string{
   681  			"authorization": key,
   682  		}
   683  
   684  		ts.Run(t, test.TestCase{
   685  			Path: "/", Headers: authHeaders, Code: 200,
   686  		})
   687  
   688  		// let records to to be sent
   689  		time.Sleep(recordsBufferFlushInterval + 50)
   690  
   691  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   692  		if len(results) != 1 {
   693  			t.Error("Should return 1 record: ", len(results))
   694  		}
   695  
   696  		var record AnalyticsRecord
   697  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
   698  		if record.ResponseCode != 200 {
   699  			t.Error("Analytics record do not match", record)
   700  		}
   701  
   702  		if record.RawRequest == "" {
   703  			t.Error("Detailed request info not found", record)
   704  		}
   705  
   706  		if record.RawResponse == "" {
   707  			t.Error("Detailed response info not found", record)
   708  		}
   709  		if record.Latency.Total == 0 {
   710  			t.Error("expected total latency to be set")
   711  		}
   712  		if record.Latency.Upstream == 0 {
   713  			t.Error("expected upstream latency to be set")
   714  		}
   715  		if record.Latency.Total != record.RequestTime {
   716  			t.Errorf("expected %d got %d", record.RequestTime, record.Latency.Total)
   717  		}
   718  	})
   719  
   720  	t.Run("Detailed analytics with cache", func(t *testing.T) {
   721  		defer func() {
   722  			config.SetGlobal(base)
   723  		}()
   724  		globalConf := config.Global()
   725  		globalConf.AnalyticsConfig.EnableDetailedRecording = true
   726  		config.SetGlobal(globalConf)
   727  
   728  		BuildAndLoadAPI(func(spec *APISpec) {
   729  			spec.UseKeylessAccess = false
   730  			spec.Proxy.ListenPath = "/"
   731  			spec.CacheOptions = apidef.CacheOptions{
   732  				CacheTimeout:         120,
   733  				EnableCache:          true,
   734  				CacheAllSafeRequests: true,
   735  			}
   736  		})
   737  
   738  		key := CreateSession()
   739  
   740  		authHeaders := map[string]string{
   741  			"authorization": key,
   742  		}
   743  
   744  		ts.Run(t, []test.TestCase{
   745  			{Path: "/", Headers: authHeaders, Code: 200},
   746  			{Path: "/", Headers: authHeaders, Code: 200},
   747  		}...)
   748  
   749  		// let records to to be sent
   750  		time.Sleep(recordsBufferFlushInterval + 50)
   751  
   752  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
   753  		if len(results) != 2 {
   754  			t.Fatal("Should return 1 record: ", len(results))
   755  		}
   756  
   757  		// Take second cached request
   758  		var record AnalyticsRecord
   759  		msgpack.Unmarshal([]byte(results[1].(string)), &record)
   760  		if record.ResponseCode != 200 {
   761  			t.Error("Analytics record do not match", record)
   762  		}
   763  
   764  		if record.RawRequest == "" {
   765  			t.Error("Detailed request info not found", record)
   766  		}
   767  
   768  		if record.RawResponse == "" {
   769  			t.Error("Detailed response info not found", record)
   770  		}
   771  	})
   772  }
   773  
   774  func TestListener(t *testing.T) {
   775  	// Trick to get spec JSON, without loading API
   776  	// Specs will be reseted when we do `StartTest`
   777  	specs := BuildAndLoadAPI()
   778  	specJSON, _ := json.Marshal(specs[0].APIDefinition)
   779  	listJSON := fmt.Sprintf(`\[%s\]`, string(specJSON))
   780  
   781  	ts := StartTest()
   782  	defer ts.Close()
   783  
   784  	tests := []test.TestCase{
   785  		// Cleanup before tests
   786  		{Method: "DELETE", Path: "/tyk/apis/test", AdminAuth: true},
   787  		{Method: "GET", Path: "/tyk/reload/?block=true", AdminAuth: true, Code: 200},
   788  
   789  		{Method: "GET", Path: "/sample", Code: 404},
   790  		{Method: "GET", Path: "/tyk/apis/", Code: 403},
   791  		{Method: "GET", Path: "/tyk/apis/", AdminAuth: true, Code: 200, BodyMatch: `\[\]`},
   792  		{Method: "GET", Path: "/tyk/apis", Code: 403},
   793  		{Method: "GET", Path: "/tyk/apis", AdminAuth: true, Code: 200},
   794  		{Method: "POST", Path: "/tyk/apis", Data: sampleAPI, AdminAuth: true, Code: 200},
   795  		{Method: "GET", Path: "/tyk/apis/", AdminAuth: true, Code: 200, BodyMatch: `\[\]`},
   796  		{Method: "POST", Path: "/tyk/apis/mismatch", AdminAuth: true, Code: 400},
   797  		{Method: "GET", Path: "/tyk/apis/test", AdminAuth: true, Code: 404},
   798  		// API definitions not reloaded yet
   799  		{Method: "GET", Path: "/sample", Code: 404},
   800  		{Method: "GET", Path: "/tyk/reload/?block=true", AdminAuth: true, Code: 200},
   801  		{Method: "GET", Path: "/tyk/apis/test", AdminAuth: true, Code: 200, BodyMatch: string(specJSON)},
   802  		{Method: "GET", Path: "/tyk/apis/", AdminAuth: true, Code: 200, BodyMatch: listJSON},
   803  		{Method: "GET", Path: "/sample", Code: 200},
   804  		{Method: "GET", Path: "/samplefoo", Code: 200},
   805  		{Method: "GET", Path: "/sample/", Code: 200},
   806  		{Method: "GET", Path: "/sample/foo", Code: 200},
   807  	}
   808  
   809  	// have all needed reload ticks ready
   810  	go func() {
   811  		for i := 0; i < 4*4; i++ {
   812  			ReloadTestCase.Tick()
   813  		}
   814  	}()
   815  
   816  	ts.RunExt(t, tests...)
   817  }
   818  
   819  // Admin api located on separate port
   820  func TestControlListener(t *testing.T) {
   821  	ts := StartTest(TestConfig{
   822  		sepatateControlAPI: true,
   823  	})
   824  	defer ts.Close()
   825  
   826  	tests := []test.TestCase{
   827  		{Method: "GET", Path: "/", Code: 404},
   828  		{Method: "GET", Path: "/tyk/apis", Code: 404},
   829  
   830  		// Querying control API
   831  		{Method: "GET", Path: "/", Code: 404, ControlRequest: true},
   832  		{Method: "GET", Path: "/tyk/apis", Code: 403, ControlRequest: true},
   833  		{Method: "GET", Path: "/tyk/apis/", Code: 200, AdminAuth: true, ControlRequest: true},
   834  	}
   835  
   836  	ts.RunExt(t, tests...)
   837  	DoReload()
   838  	ts.RunExt(t, tests...)
   839  }
   840  
   841  func TestHttpPprof(t *testing.T) {
   842  	old := cli.HTTPProfile
   843  	defer func() { cli.HTTPProfile = old }()
   844  
   845  	ts := StartTest(TestConfig{
   846  		sepatateControlAPI: true,
   847  	})
   848  
   849  	ts.Run(t, []test.TestCase{
   850  		{Path: "/debug/pprof/", Code: 404},
   851  		{Path: "/debug/pprof/", Code: 404, ControlRequest: true},
   852  	}...)
   853  	ts.Close()
   854  
   855  	*cli.HTTPProfile = true
   856  
   857  	ts.Start()
   858  	ts.Run(t, []test.TestCase{
   859  		{Path: "/debug/pprof/", Code: 404},
   860  		{Path: "/debug/pprof/", Code: 200, ControlRequest: true},
   861  		{Path: "/debug/pprof/heap", Code: 200, ControlRequest: true},
   862  	}...)
   863  	ts.Close()
   864  }
   865  
   866  func TestManagementNodeRedisEvents(t *testing.T) {
   867  	defer ResetTestConfig()
   868  	globalConf := config.Global()
   869  	globalConf.ManagementNode = false
   870  	config.SetGlobal(globalConf)
   871  
   872  	t.Run("Without signing:", func(t *testing.T) {
   873  		msg := redis.Message{
   874  			Payload: `{"Command": "NoticeGatewayDRLNotification"}`,
   875  		}
   876  
   877  		callbackRun := false
   878  		shouldHandle := func(got NotificationCommand) {
   879  			callbackRun = true
   880  			if want := NoticeGatewayDRLNotification; got != want {
   881  				t.Fatalf("want %q, got %q", want, got)
   882  			}
   883  		}
   884  		handleRedisEvent(&msg, shouldHandle, nil)
   885  		if !callbackRun {
   886  			t.Fatalf("Should run callback")
   887  		}
   888  		globalConf.ManagementNode = true
   889  		config.SetGlobal(globalConf)
   890  		notHandle := func(got NotificationCommand) {
   891  			t.Fatalf("should have not handled redis event")
   892  		}
   893  		handleRedisEvent(msg, notHandle, nil)
   894  	})
   895  
   896  	t.Run("With signature", func(t *testing.T) {
   897  		globalConf := config.Global()
   898  		globalConf.AllowInsecureConfigs = false
   899  		config.SetGlobal(globalConf)
   900  
   901  		n := Notification{
   902  			Command: NoticeGroupReload,
   903  			Payload: string("test"),
   904  		}
   905  		n.Sign()
   906  		msg := redis.Message{}
   907  		payload, _ := json.Marshal(n)
   908  		msg.Payload = string(payload)
   909  
   910  		callbackRun := false
   911  		shouldHandle := func(got NotificationCommand) {
   912  			callbackRun = true
   913  			if want := NoticeGroupReload; got != want {
   914  				t.Fatalf("want %q, got %q", want, got)
   915  			}
   916  		}
   917  
   918  		handleRedisEvent(&msg, shouldHandle, nil)
   919  		if !callbackRun {
   920  			t.Fatalf("Should run callback")
   921  		}
   922  
   923  		n.Signature = "wrong"
   924  		payload, _ = json.Marshal(n)
   925  		msg.Payload = string(payload)
   926  
   927  		valid := false
   928  		shouldFail := func(got NotificationCommand) {
   929  			valid = true
   930  		}
   931  		handleRedisEvent(&msg, shouldFail, nil)
   932  		if valid {
   933  			t.Fatalf("Should fail validation")
   934  		}
   935  	})
   936  }
   937  
   938  func TestListenPathTykPrefix(t *testing.T) {
   939  	ts := StartTest()
   940  	defer ts.Close()
   941  
   942  	BuildAndLoadAPI(func(spec *APISpec) {
   943  		spec.Proxy.ListenPath = "/tyk-foo/"
   944  	})
   945  
   946  	ts.Run(t, test.TestCase{
   947  		Path: "/tyk-foo/",
   948  		Code: 200,
   949  	})
   950  }
   951  
   952  func TestReloadGoroutineLeakWithCircuitBreaker(t *testing.T) {
   953  	ts := StartTest()
   954  	defer ts.Close()
   955  
   956  	globalConf := config.Global()
   957  	globalConf.EnableJSVM = false
   958  	config.SetGlobal(globalConf)
   959  	defer ResetTestConfig()
   960  
   961  	specs := BuildAndLoadAPI(func(spec *APISpec) {
   962  		spec.Proxy.ListenPath = "/"
   963  		UpdateAPIVersion(spec, "v1", func(version *apidef.VersionInfo) {
   964  			version.ExtendedPaths = apidef.ExtendedPathsSet{
   965  				CircuitBreaker: []apidef.CircuitBreakerMeta{
   966  					{
   967  						Path:                 "/",
   968  						Method:               http.MethodGet,
   969  						ThresholdPercent:     0.5,
   970  						Samples:              5,
   971  						ReturnToServiceAfter: 10,
   972  					},
   973  				},
   974  			}
   975  		})
   976  	})
   977  
   978  	before := runtime.NumGoroutine()
   979  
   980  	LoadAPI(specs...) // just doing DoReload() doesn't load anything as BuildAndLoadAPI cleans up folder with API specs
   981  
   982  	time.Sleep(100 * time.Millisecond)
   983  
   984  	after := runtime.NumGoroutine()
   985  
   986  	if before < after {
   987  		t.Errorf("Goroutine leak, was: %d, after reload: %d", before, after)
   988  	}
   989  }
   990  
   991  func listenProxyProto(ls net.Listener) error {
   992  	pl := &proxyproto.Listener{Listener: ls}
   993  	for {
   994  		conn, err := pl.Accept()
   995  		if err != nil {
   996  			return err
   997  		}
   998  		recv := make([]byte, 4)
   999  		_, err = conn.Read(recv)
  1000  		if err != nil {
  1001  			return err
  1002  		}
  1003  		if _, err := conn.Write([]byte("pong")); err != nil {
  1004  			return err
  1005  		}
  1006  	}
  1007  }
  1008  
  1009  func TestProxyProtocol(t *testing.T) {
  1010  	l, err := net.Listen("tcp", "127.0.0.1:0")
  1011  	if err != nil {
  1012  		t.Fatal(err)
  1013  	}
  1014  	defer l.Close()
  1015  	go listenProxyProto(l)
  1016  	ts := StartTest()
  1017  	defer ts.Close()
  1018  	rp, err := net.Listen("tcp", "127.0.0.1:0")
  1019  	if err != nil {
  1020  		t.Fatal(err)
  1021  	}
  1022  	_, port, err := net.SplitHostPort(rp.Addr().String())
  1023  	if err != nil {
  1024  		t.Fatal(err)
  1025  	}
  1026  	p, err := strconv.Atoi(port)
  1027  	if err != nil {
  1028  		t.Fatal(err)
  1029  	}
  1030  	EnablePort(p, "tcp")
  1031  	defer ResetTestConfig()
  1032  
  1033  	proxyAddr := rp.Addr().String()
  1034  	rp.Close()
  1035  	BuildAndLoadAPI(func(spec *APISpec) {
  1036  		spec.Proxy.ListenPath = "/"
  1037  		spec.Protocol = "tcp"
  1038  		spec.EnableProxyProtocol = true
  1039  		spec.ListenPort = p
  1040  		spec.Proxy.TargetURL = l.Addr().String()
  1041  	})
  1042  
  1043  	// we want to check if the gateway started listening on the tcp port.
  1044  	ls, err := net.Dial("tcp", proxyAddr)
  1045  	if err != nil {
  1046  		t.Fatalf("expected the proxy to listen on address %s", proxyAddr)
  1047  	}
  1048  	defer ls.Close()
  1049  	ls.Write([]byte("ping"))
  1050  	recv := make([]byte, 4)
  1051  	_, err = ls.Read(recv)
  1052  	if err != nil {
  1053  		t.Fatalf("err: %v", err)
  1054  	}
  1055  	if !bytes.Equal(recv, []byte("pong")) {
  1056  		t.Fatalf("bad: %v", recv)
  1057  	}
  1058  }
  1059  
  1060  func TestProxyUserAgent(t *testing.T) {
  1061  	ts := StartTest()
  1062  	defer ts.Close()
  1063  
  1064  	BuildAndLoadAPI(func(spec *APISpec) {
  1065  		spec.Proxy.ListenPath = "/"
  1066  	})
  1067  
  1068  	ts.Run(t, []test.TestCase{
  1069  		{
  1070  			Headers:   map[string]string{"User-Agent": ""},
  1071  			BodyMatch: fmt.Sprintf(`"User-Agent":"%s"`, defaultUserAgent),
  1072  		},
  1073  		{
  1074  			Headers:   map[string]string{"User-Agent": "SomeAgent"},
  1075  			BodyMatch: `"User-Agent":"SomeAgent"`,
  1076  		},
  1077  	}...)
  1078  }
  1079  
  1080  func TestSkipUrlCleaning(t *testing.T) {
  1081  	globalConf := config.Global()
  1082  	globalConf.HttpServerOptions.OverrideDefaults = true
  1083  	globalConf.HttpServerOptions.SkipURLCleaning = true
  1084  	config.SetGlobal(globalConf)
  1085  	defer ResetTestConfig()
  1086  
  1087  	ts := StartTest()
  1088  	defer ts.Close()
  1089  
  1090  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1091  		w.Write([]byte(r.URL.Path))
  1092  	}))
  1093  	defer s.Close()
  1094  
  1095  	BuildAndLoadAPI(func(spec *APISpec) {
  1096  		spec.Proxy.ListenPath = "/"
  1097  		spec.Proxy.TargetURL = s.URL
  1098  	})
  1099  
  1100  	ts.Run(t, test.TestCase{
  1101  		Path: "/http://example.com", BodyMatch: "/http://example.com", Code: 200,
  1102  	})
  1103  }
  1104  
  1105  func TestMultiTargetProxy(t *testing.T) {
  1106  	ts := StartTest()
  1107  	defer ts.Close()
  1108  
  1109  	BuildAndLoadAPI(func(spec *APISpec) {
  1110  		spec.VersionData.NotVersioned = false
  1111  		spec.VersionData.Versions = map[string]apidef.VersionInfo{
  1112  			"vdef": {Name: "vdef"},
  1113  			"vother": {
  1114  				Name:           "vother",
  1115  				OverrideTarget: TestHttpAny + "/vother",
  1116  			},
  1117  		}
  1118  		spec.Proxy.ListenPath = "/"
  1119  	})
  1120  
  1121  	ts.Run(t, []test.TestCase{
  1122  		{
  1123  			Headers:   map[string]string{"version": "vdef"},
  1124  			JSONMatch: map[string]string{"Url": `"/"`},
  1125  			Code:      200,
  1126  		},
  1127  		{
  1128  			Headers:   map[string]string{"version": "vother"},
  1129  			JSONMatch: map[string]string{"Url": `"/vother"`},
  1130  			Code:      200,
  1131  		},
  1132  	}...)
  1133  }
  1134  
  1135  func TestCustomDomain(t *testing.T) {
  1136  	t.Run("With custom domain support", func(t *testing.T) {
  1137  		globalConf := config.Global()
  1138  		globalConf.EnableCustomDomains = true
  1139  		config.SetGlobal(globalConf)
  1140  		defer ResetTestConfig()
  1141  
  1142  		ts := StartTest()
  1143  		defer ts.Close()
  1144  
  1145  		BuildAndLoadAPI(
  1146  			func(spec *APISpec) {
  1147  				spec.Domain = "host1"
  1148  				spec.Proxy.ListenPath = "/with_domain"
  1149  			},
  1150  			func(spec *APISpec) {
  1151  				spec.Domain = ""
  1152  				spec.Proxy.ListenPath = "/without_domain"
  1153  			},
  1154  		)
  1155  
  1156  		ts.Run(t, []test.TestCase{
  1157  			{Code: 200, Path: "/with_domain", Domain: "host1"},
  1158  			{Code: 404, Path: "/with_domain"},
  1159  			{Code: 200, Path: "/without_domain"},
  1160  			{Code: 200, Path: "/tyk/keys", AdminAuth: true},
  1161  		}...)
  1162  	})
  1163  
  1164  	t.Run("Without custom domain support", func(t *testing.T) {
  1165  		ts := StartTest()
  1166  		defer ts.Close()
  1167  
  1168  		BuildAndLoadAPI(
  1169  			func(spec *APISpec) {
  1170  				spec.Domain = "host1.local."
  1171  				spec.Proxy.ListenPath = "/"
  1172  			},
  1173  			func(spec *APISpec) {
  1174  				spec.Domain = ""
  1175  				spec.Proxy.ListenPath = "/"
  1176  			},
  1177  		)
  1178  
  1179  		ts.Run(t, []test.TestCase{
  1180  			{Code: 200, Path: "/with_domain", Domain: "host1"},
  1181  			{Code: 200, Path: "/with_domain"},
  1182  			{Code: 200, Path: "/without_domain"},
  1183  			{Code: 200, Path: "/tyk/keys", AdminAuth: true},
  1184  		}...)
  1185  	})
  1186  }
  1187  
  1188  func TestHelloHealthcheck(t *testing.T) {
  1189  	ts := StartTest()
  1190  	defer ts.Close()
  1191  
  1192  	t.Run("Without APIs", func(t *testing.T) {
  1193  		ts.Run(t, []test.TestCase{
  1194  			{Method: "GET", Path: "/hello", Code: 200},
  1195  		}...)
  1196  	})
  1197  
  1198  	t.Run("With APIs", func(t *testing.T) {
  1199  		BuildAndLoadAPI(func(spec *APISpec) {
  1200  			spec.Proxy.ListenPath = "/sample"
  1201  		})
  1202  
  1203  		ts.Run(t, []test.TestCase{
  1204  			{Method: "GET", Path: "/hello", Code: 200},
  1205  			{Method: "GET", Path: "/sample/hello", Code: 200},
  1206  		}...)
  1207  	})
  1208  }
  1209  
  1210  func TestCacheAllSafeRequests(t *testing.T) {
  1211  	ts := StartTest()
  1212  	defer ts.Close()
  1213  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1214  	defer cache.DeleteScanMatch("*")
  1215  
  1216  	BuildAndLoadAPI(func(spec *APISpec) {
  1217  		spec.CacheOptions = apidef.CacheOptions{
  1218  			CacheTimeout:         120,
  1219  			EnableCache:          true,
  1220  			CacheAllSafeRequests: true,
  1221  		}
  1222  		spec.Proxy.ListenPath = "/"
  1223  	})
  1224  
  1225  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1226  
  1227  	ts.Run(t, []test.TestCase{
  1228  		{Method: "GET", Path: "/", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1229  		{Method: "GET", Path: "/", HeadersMatch: headerCache},
  1230  		{Method: "POST", Path: "/", HeadersNotMatch: headerCache},
  1231  		{Method: "POST", Path: "/", HeadersNotMatch: headerCache},
  1232  		{Method: "GET", Path: "/", HeadersMatch: headerCache},
  1233  	}...)
  1234  }
  1235  
  1236  func TestCacheAllSafeRequestsWithCachedHeaders(t *testing.T) {
  1237  	ts := StartTest()
  1238  	defer ts.Close()
  1239  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1240  	defer cache.DeleteScanMatch("*")
  1241  	authorization := "authorization"
  1242  	tenant := "tenant-id"
  1243  
  1244  	BuildAndLoadAPI(func(spec *APISpec) {
  1245  		spec.CacheOptions = apidef.CacheOptions{
  1246  			CacheTimeout:         120,
  1247  			EnableCache:          true,
  1248  			CacheAllSafeRequests: true,
  1249  			CacheByHeaders:       []string{authorization, tenant},
  1250  		}
  1251  		spec.UseKeylessAccess = true
  1252  		spec.Proxy.ListenPath = "/"
  1253  	})
  1254  
  1255  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1256  	sess1token := CreateSession(func(s *user.SessionState) {
  1257  		s.Rate = 1
  1258  		s.Per = 60
  1259  		s.Mutex = &sync.RWMutex{}
  1260  	})
  1261  	sess2token := CreateSession(func(s *user.SessionState) {
  1262  		s.Rate = 1
  1263  		s.Per = 60
  1264  		s.Mutex = &sync.RWMutex{}
  1265  	})
  1266  
  1267  	ts.Run(t, []test.TestCase{
  1268  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{authorization: sess1token}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1269  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{authorization: sess1token}, HeadersMatch: headerCache},
  1270  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{authorization: sess2token}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1271  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{tenant: "Some UUID"}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1272  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{tenant: "Some UUID"}, HeadersMatch: headerCache},
  1273  		{Method: http.MethodGet, Path: "/", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1274  		{Method: http.MethodGet, Path: "/", HeadersMatch: headerCache},
  1275  		{Method: http.MethodGet, Path: "/", Headers: map[string]string{tenant: "Some UUID", authorization: sess2token}, HeadersNotMatch: headerCache},
  1276  	}...)
  1277  }
  1278  
  1279  func TestCacheWithAdvanceUrlRewrite(t *testing.T) {
  1280  	ts := StartTest()
  1281  	defer ts.Close()
  1282  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1283  	defer cache.DeleteScanMatch("*")
  1284  
  1285  	BuildAndLoadAPI(func(spec *APISpec) {
  1286  		version := spec.VersionData.Versions["v1"]
  1287  		version.UseExtendedPaths = true
  1288  		version.ExtendedPaths = apidef.ExtendedPathsSet{
  1289  			URLRewrite: []apidef.URLRewriteMeta{
  1290  				{
  1291  					Path:         "/test",
  1292  					Method:       http.MethodGet,
  1293  					MatchPattern: "/test(.*)",
  1294  					Triggers: []apidef.RoutingTrigger{
  1295  						{
  1296  							On: "all",
  1297  							Options: apidef.RoutingTriggerOptions{
  1298  								HeaderMatches: map[string]apidef.StringRegexMap{
  1299  									"rewritePath": {
  1300  										MatchPattern: "newpath",
  1301  									},
  1302  								},
  1303  							},
  1304  							RewriteTo: "/newpath",
  1305  						},
  1306  					},
  1307  				},
  1308  			},
  1309  			Cached: []string{"/test"},
  1310  		}
  1311  		spec.CacheOptions = apidef.CacheOptions{
  1312  			CacheTimeout: 120,
  1313  			EnableCache:  true,
  1314  		}
  1315  		spec.Proxy.ListenPath = "/"
  1316  		spec.VersionData.Versions["v1"] = version
  1317  	})
  1318  
  1319  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1320  	matchHeaders := map[string]string{"rewritePath": "newpath"}
  1321  	randomheaders := map[string]string{"something": "abcd"}
  1322  
  1323  	ts.Run(t, []test.TestCase{
  1324  		{Method: http.MethodGet, Path: "/test", Headers: matchHeaders, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1325  		{Method: http.MethodGet, Path: "/test", Headers: matchHeaders, HeadersMatch: headerCache},
  1326  		//Even if trigger condition failed, as response is cached
  1327  		// will still get redirected response
  1328  		{Method: http.MethodGet, Path: "/test", Headers: randomheaders, HeadersMatch: headerCache, BodyMatch: `"Url":"/newpath"`},
  1329  		{Method: http.MethodPost, Path: "/test", HeadersNotMatch: headerCache},
  1330  		{Method: http.MethodGet, Path: "/test", HeadersMatch: headerCache},
  1331  	}...)
  1332  }
  1333  
  1334  func TestCachePostRequest(t *testing.T) {
  1335  	ts := StartTest()
  1336  	defer ts.Close()
  1337  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1338  	defer cache.DeleteScanMatch("*")
  1339  	tenant := "tenant-id"
  1340  
  1341  	BuildAndLoadAPI(func(spec *APISpec) {
  1342  		spec.CacheOptions = apidef.CacheOptions{
  1343  			CacheTimeout:         120,
  1344  			EnableCache:          true,
  1345  			CacheAllSafeRequests: false,
  1346  			CacheByHeaders:       []string{tenant},
  1347  		}
  1348  
  1349  		UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) {
  1350  			v.ExtendedPaths.AdvanceCacheConfig = []apidef.CacheMeta{
  1351  				{
  1352  					Method:        http.MethodPost,
  1353  					Path:          "/",
  1354  					CacheKeyRegex: "\"id\":[^,]*",
  1355  				},
  1356  			}
  1357  		})
  1358  
  1359  		spec.Proxy.ListenPath = "/"
  1360  	})
  1361  
  1362  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1363  
  1364  	ts.Run(t, []test.TestCase{
  1365  		{Method: http.MethodPost, Path: "/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1366  		{Method: http.MethodPost, Path: "/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1367  		{Method: http.MethodPost, Path: "/", Data: "{\"id\":\"2\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1368  		// if regex match returns nil, then request body is ignored while generating cache key
  1369  		{Method: http.MethodPost, Path: "/", Data: "{\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1370  		{Method: http.MethodPost, Path: "/", Data: "{\"name\":\"test2\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1371  		{Method: http.MethodPost, Path: "/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1372  		{Method: http.MethodPost, Path: "/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersMatch: headerCache},
  1373  	}...)
  1374  }
  1375  
  1376  func TestAdvanceCachePutRequest(t *testing.T) {
  1377  	ts := StartTest()
  1378  	defer ts.Close()
  1379  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1380  	defer cache.DeleteScanMatch("*")
  1381  	tenant := "tenant-id"
  1382  
  1383  	BuildAndLoadAPI(func(spec *APISpec) {
  1384  		spec.CacheOptions = apidef.CacheOptions{
  1385  			CacheTimeout:           120,
  1386  			EnableCache:            true,
  1387  			CacheAllSafeRequests:   true,
  1388  			CacheOnlyResponseCodes: []int{404}, // should not influence because of AdvanceCacheConfig.CacheOnlyResponseCodes
  1389  			CacheByHeaders:         []string{tenant},
  1390  		}
  1391  		spec.Proxy.ListenPath = "/"
  1392  
  1393  		UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) {
  1394  			json.Unmarshal([]byte(`[{
  1395  						"method":"PUT",
  1396  						"path":"/put/",
  1397  						"cache_key_regex":"\"id\":[^,]*",
  1398  						"cache_response_codes":[200]
  1399  					},{
  1400  						"method":"PATCH",
  1401  						"path":"/patch/",
  1402  						"cache_key_regex":"\"id\":[^,]*",
  1403  						"cache_response_codes":[200]
  1404  					},{
  1405  						"method":"DELETE",
  1406  						"path":"/delete/",
  1407  						"cache_response_codes":[200]
  1408  					},{
  1409  						"method":"PUT",
  1410  						"path":"/full-body-hash/",
  1411  						"cache_response_codes":[200],
  1412  						"cache_key_regex":".*"
  1413  					}
  1414                                  ]`), &v.ExtendedPaths.AdvanceCacheConfig)
  1415  		})
  1416  		spec.Proxy.ListenPath = "/"
  1417  	})
  1418  
  1419  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1420  
  1421  	ts.Run(t, []test.TestCase{
  1422  		{Method: http.MethodPut, Path: "/put/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond}, // 0
  1423  		{Method: http.MethodPut, Path: "/put/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1424  		{Method: http.MethodPut, Path: "/put/", Data: "{\"id\":\"2\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1425  		// if regex match returns nil, then request body is ignored while generating cache key
  1426  		{Method: http.MethodPut, Path: "/put/", Data: "{\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1427  		{Method: http.MethodPut, Path: "/put/", Data: "{\"name\":\"test2\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1428  		{Method: http.MethodPut, Path: "/put/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{"someheader": "someUUID"}, HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1429  		// test when no body and no headers
  1430  		{Method: http.MethodPut, Path: "/put/", HeadersMatch: headerCache},
  1431  		// test CacheByHeaders change - header added
  1432  		{Method: http.MethodPut, Path: "/put/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1433  		{Method: http.MethodPut, Path: "/put/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersMatch: headerCache},
  1434  
  1435  		// PATCH
  1436  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1437  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond}, // 10
  1438  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"id\":\"2\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1439  		// if regex match returns nil, then request body is ignored while generating cache key
  1440  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1441  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"name\":\"test2\"}", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1442  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{"someheader": "someUUID"}, HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1443  		// test when no body and no headers
  1444  		{Method: http.MethodPatch, Path: "/patch/", HeadersMatch: headerCache},
  1445  		// test CacheByHeaders change - header added
  1446  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1447  		{Method: http.MethodPatch, Path: "/patch/", Data: "{\"name\":\"test2\"}", Headers: map[string]string{tenant: "someUUID"}, HeadersMatch: headerCache},
  1448  
  1449  		// DELETE
  1450  		{Method: http.MethodDelete, Path: "/delete/", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1451  		{Method: http.MethodDelete, Path: "/delete/", HeadersMatch: headerCache, Delay: 10 * time.Millisecond},
  1452  		{Method: http.MethodDelete, Path: "/delete/", Headers: map[string]string{tenant: "someUUID"}, HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond}, // 20
  1453  		{Method: http.MethodDelete, Path: "/delete/", Headers: map[string]string{tenant: "someUUID"}, HeadersMatch: headerCache},
  1454  
  1455  		// Put with full body hash
  1456  		{Method: http.MethodPut, Path: "/full-body-hash/", Data: "{\"id\":\"1\",\"name\":\"test\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1457  		{Method: http.MethodPut, Path: "/full-body-hash/", Data: "{\"id\":\"1\",\"name\":\"test2\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1458  		{Method: http.MethodPut, Path: "/full-body-hash/", Data: "{\"id\":\"2\",\"name\":\"test2\"}", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1459  		{Method: http.MethodPut, Path: "/full-body-hash/", Data: "{\"id\":\"2\",\"name\":\"test2\"}", HeadersMatch: headerCache},
  1460  	}...)
  1461  }
  1462  
  1463  func TestCacheAllSafeRequestsWithAdvancedCacheEndpoint(t *testing.T) {
  1464  	ts := StartTest()
  1465  	defer ts.Close()
  1466  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1467  	defer cache.DeleteScanMatch("*")
  1468  
  1469  	BuildAndLoadAPI(func(spec *APISpec) {
  1470  		spec.CacheOptions = apidef.CacheOptions{
  1471  			CacheTimeout:           120,
  1472  			EnableCache:            true,
  1473  			CacheAllSafeRequests:   true,
  1474  			CacheOnlyResponseCodes: []int{200}, // should not influence because of AdvanceCacheConfig.CacheOnlyResponseCodes
  1475  		}
  1476  
  1477  		UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) {
  1478  			json.Unmarshal([]byte(`[{
  1479  						"method":"PUT",
  1480  						"path":"/",
  1481  						"cache_key_regex":"\"id\":[^,]*",
  1482  						"cache_response_codes":[404]
  1483  					}
  1484                                 ]`), &v.ExtendedPaths.AdvanceCacheConfig)
  1485  		})
  1486  		spec.Proxy.ListenPath = "/"
  1487  	})
  1488  
  1489  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1490  
  1491  	ts.Run(t, []test.TestCase{
  1492  		// Make sure CacheAllSafeRequests is working
  1493  		{Method: http.MethodGet, Path: "/", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
  1494  		{Method: http.MethodGet, Path: "/", HeadersMatch: headerCache},
  1495  	}...)
  1496  }
  1497  
  1498  func TestCacheEtag(t *testing.T) {
  1499  	ts := StartTest()
  1500  	defer ts.Close()
  1501  	cache := storage.RedisCluster{KeyPrefix: "cache-"}
  1502  	defer cache.DeleteScanMatch("*")
  1503  
  1504  	upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1505  		w.Header().Set("Etag", "12345")
  1506  		w.Write([]byte("body"))
  1507  	}))
  1508  
  1509  	BuildAndLoadAPI(func(spec *APISpec) {
  1510  		spec.CacheOptions = apidef.CacheOptions{
  1511  			CacheTimeout:         120,
  1512  			EnableCache:          true,
  1513  			CacheAllSafeRequests: true,
  1514  		}
  1515  		spec.Proxy.ListenPath = "/"
  1516  		spec.Proxy.TargetURL = upstream.URL
  1517  	})
  1518  
  1519  	headerCache := map[string]string{"x-tyk-cached-response": "1"}
  1520  	invalidEtag := map[string]string{"If-None-Match": "invalid"}
  1521  	validEtag := map[string]string{"If-None-Match": "12345"}
  1522  
  1523  	ts.Run(t, []test.TestCase{
  1524  		{Method: "GET", Path: "/", HeadersNotMatch: headerCache, Delay: 100 * time.Millisecond},
  1525  		{Method: "GET", Path: "/", HeadersMatch: headerCache, BodyMatch: "body"},
  1526  		{Method: "GET", Path: "/", Headers: invalidEtag, HeadersMatch: headerCache, BodyMatch: "body"},
  1527  		{Method: "GET", Path: "/", Headers: validEtag, HeadersMatch: headerCache, BodyNotMatch: "body"},
  1528  	}...)
  1529  }
  1530  
  1531  // func TestWebsocketsUpstreamUpgradeRequest(t *testing.T) {
  1532  // 	// setup spec and do test HTTP upgrade-request
  1533  // 	globalConf := config.Global()
  1534  // 	globalConf.HttpServerOptions.EnableWebSockets = true
  1535  // 	config.SetGlobal(globalConf)
  1536  // 	defer ResetTestConfig()
  1537  
  1538  // 	ts := StartTest()
  1539  // 	defer ts.Close()
  1540  
  1541  // 	BuildAndLoadAPI(func(spec *APISpec) {
  1542  // 		spec.Proxy.ListenPath = "/"
  1543  // 	})
  1544  
  1545  // 	ts.Run(t, test.TestCase{
  1546  // 		Path: "/ws",
  1547  // 		Headers: map[string]string{
  1548  // 			"Connection":            "Upgrade",
  1549  // 			"Upgrade":               "websocket",
  1550  // 			"Sec-Websocket-Version": "13",
  1551  // 			"Sec-Websocket-Key":     "abc",
  1552  // 		},
  1553  // 		Code: http.StatusSwitchingProtocols,
  1554  // 	})
  1555  // }
  1556  
  1557  func TestWebsocketsSeveralOpenClose(t *testing.T) {
  1558  	globalConf := config.Global()
  1559  	globalConf.HttpServerOptions.EnableWebSockets = true
  1560  	config.SetGlobal(globalConf)
  1561  	defer ResetTestConfig()
  1562  
  1563  	ts := StartTest()
  1564  	defer ts.Close()
  1565  
  1566  	BuildAndLoadAPI(func(spec *APISpec) {
  1567  		spec.Proxy.ListenPath = "/"
  1568  	})
  1569  
  1570  	baseURL := strings.Replace(ts.URL, "http://", "ws://", -1)
  1571  
  1572  	// connect 1st time, send and read message, close connection
  1573  	conn1, _, err := websocket.DefaultDialer.Dial(baseURL+"/ws", nil)
  1574  	if err != nil {
  1575  		t.Fatalf("cannot make websocket connection: %v", err)
  1576  	}
  1577  	err = conn1.WriteMessage(websocket.BinaryMessage, []byte("test message 1"))
  1578  	if err != nil {
  1579  		t.Fatalf("cannot write message: %v", err)
  1580  	}
  1581  	_, p, err := conn1.ReadMessage()
  1582  	if err != nil {
  1583  		t.Fatalf("cannot read message: %v", err)
  1584  	}
  1585  	if string(p) != "reply to message: test message 1" {
  1586  		t.Error("Unexpected reply:", string(p))
  1587  	}
  1588  	conn1.Close()
  1589  
  1590  	// connect 2nd time, send and read message, but don't close yet
  1591  	conn2, _, err := websocket.DefaultDialer.Dial(baseURL+"/ws", nil)
  1592  	if err != nil {
  1593  		t.Fatalf("cannot make websocket connection: %v", err)
  1594  	}
  1595  	err = conn2.WriteMessage(websocket.BinaryMessage, []byte("test message 2"))
  1596  	if err != nil {
  1597  		t.Fatalf("cannot write message: %v", err)
  1598  	}
  1599  	_, p, err = conn2.ReadMessage()
  1600  	if err != nil {
  1601  		t.Fatalf("cannot read message: %v", err)
  1602  	}
  1603  	if string(p) != "reply to message: test message 2" {
  1604  		t.Error("Unexpected reply:", string(p))
  1605  	}
  1606  
  1607  	// connect 3d time having one connection already open before, send and read message
  1608  	conn3, _, err := websocket.DefaultDialer.Dial(baseURL+"/ws", nil)
  1609  	if err != nil {
  1610  		t.Fatalf("cannot make websocket connection: %v", err)
  1611  	}
  1612  	err = conn3.WriteMessage(websocket.BinaryMessage, []byte("test message 3"))
  1613  	if err != nil {
  1614  		t.Fatalf("cannot write message: %v", err)
  1615  	}
  1616  	_, p, err = conn3.ReadMessage()
  1617  	if err != nil {
  1618  		t.Fatalf("cannot read message: %v", err)
  1619  	}
  1620  	if string(p) != "reply to message: test message 3" {
  1621  		t.Error("Unexpected reply:", string(p))
  1622  	}
  1623  
  1624  	// check that we still can interact via 2nd connection we did before
  1625  	err = conn2.WriteMessage(websocket.BinaryMessage, []byte("new test message 2"))
  1626  	if err != nil {
  1627  		t.Fatalf("cannot write message: %v", err)
  1628  	}
  1629  	_, p, err = conn2.ReadMessage()
  1630  	if err != nil {
  1631  		t.Fatalf("cannot read message: %v", err)
  1632  	}
  1633  	if string(p) != "reply to message: new test message 2" {
  1634  		t.Error("Unexpected reply:", string(p))
  1635  	}
  1636  
  1637  	// check that we still can interact via 3d connection we did before
  1638  	err = conn3.WriteMessage(websocket.BinaryMessage, []byte("new test message 3"))
  1639  	if err != nil {
  1640  		t.Fatalf("cannot write message: %v", err)
  1641  	}
  1642  	_, p, err = conn3.ReadMessage()
  1643  	if err != nil {
  1644  		t.Fatalf("cannot read message: %v", err)
  1645  	}
  1646  	if string(p) != "reply to message: new test message 3" {
  1647  		t.Error("Unexpected reply:", string(p))
  1648  	}
  1649  
  1650  	// clean up connections
  1651  	conn2.Close()
  1652  	conn3.Close()
  1653  }
  1654  
  1655  func TestWebsocketsAndHTTPEndpointMatch(t *testing.T) {
  1656  	globalConf := config.Global()
  1657  	globalConf.HttpServerOptions.EnableWebSockets = true
  1658  	config.SetGlobal(globalConf)
  1659  	defer ResetTestConfig()
  1660  
  1661  	ts := StartTest()
  1662  	defer ts.Close()
  1663  
  1664  	BuildAndLoadAPI(func(spec *APISpec) {
  1665  		spec.Proxy.ListenPath = "/"
  1666  	})
  1667  
  1668  	baseURL := strings.Replace(ts.URL, "http://", "ws://", -1)
  1669  
  1670  	// connect to ws, send 1st message and check reply
  1671  	wsConn, _, err := websocket.DefaultDialer.Dial(baseURL+"/ws", nil)
  1672  	if err != nil {
  1673  		t.Fatalf("cannot make websocket connection: %v", err)
  1674  	}
  1675  	err = wsConn.WriteMessage(websocket.BinaryMessage, []byte("test message 1"))
  1676  	if err != nil {
  1677  		t.Fatalf("cannot write message: %v", err)
  1678  	}
  1679  	_, p, err := wsConn.ReadMessage()
  1680  	if err != nil {
  1681  		t.Fatalf("cannot read message: %v", err)
  1682  	}
  1683  	if string(p) != "reply to message: test message 1" {
  1684  		t.Error("Unexpected reply:", string(p))
  1685  	}
  1686  
  1687  	// make 1st http request
  1688  	ts.Run(t, test.TestCase{
  1689  		Method: "GET",
  1690  		Path:   "/abc",
  1691  		Code:   http.StatusOK,
  1692  	})
  1693  
  1694  	// send second WS connection upgrade request
  1695  	// connect to ws, send 1st message and check reply
  1696  	wsConn2, _, err := websocket.DefaultDialer.Dial(baseURL+"/ws", nil)
  1697  	if err != nil {
  1698  		t.Fatalf("cannot make websocket connection: %v", err)
  1699  	}
  1700  	err = wsConn2.WriteMessage(websocket.BinaryMessage, []byte("test message 1 to ws 2"))
  1701  	if err != nil {
  1702  		t.Fatalf("cannot write message: %v", err)
  1703  	}
  1704  	_, p, err = wsConn2.ReadMessage()
  1705  	if err != nil {
  1706  		t.Fatalf("cannot read message: %v", err)
  1707  	}
  1708  	if string(p) != "reply to message: test message 1 to ws 2" {
  1709  		t.Error("Unexpected reply:", string(p))
  1710  	}
  1711  	wsConn2.Close()
  1712  
  1713  	// send second message to WS and check reply
  1714  	err = wsConn.WriteMessage(websocket.BinaryMessage, []byte("test message 2"))
  1715  	if err != nil {
  1716  		t.Fatalf("cannot write message: %v", err)
  1717  	}
  1718  	_, p, err = wsConn.ReadMessage()
  1719  	if err != nil {
  1720  		t.Fatalf("cannot read message: %v", err)
  1721  	}
  1722  	if string(p) != "reply to message: test message 2" {
  1723  		t.Error("Unexpected reply:", string(p))
  1724  	}
  1725  
  1726  	// make 2nd http request
  1727  	ts.Run(t, test.TestCase{
  1728  		Method: "GET",
  1729  		Path:   "/abc",
  1730  		Code:   http.StatusOK,
  1731  	})
  1732  
  1733  	wsConn.Close()
  1734  
  1735  	// make 3d http request after closing WS connection
  1736  	ts.Run(t, test.TestCase{
  1737  		Method: "GET",
  1738  		Path:   "/abc",
  1739  		Code:   http.StatusOK,
  1740  	})
  1741  }
  1742  
  1743  func createTestUptream(t *testing.T, allowedConns int, readsPerConn int) net.Listener {
  1744  	l, _ := net.Listen("tcp", "127.0.0.1:0")
  1745  	go func() {
  1746  		conns := 0
  1747  
  1748  		for {
  1749  			conn, err := l.Accept()
  1750  			if err != nil {
  1751  				return
  1752  			}
  1753  			conns++
  1754  
  1755  			if conns > allowedConns {
  1756  				t.Fatal("Too many connections")
  1757  				conn.Close()
  1758  				return
  1759  			}
  1760  
  1761  			reads := 0
  1762  			go func() {
  1763  				for {
  1764  					buf := make([]byte, 1024)
  1765  					conn.SetDeadline(time.Now().Add(50 * time.Millisecond))
  1766  					_, err := conn.Read(buf)
  1767  					if err != nil {
  1768  						conn.Close()
  1769  						return
  1770  					}
  1771  					reads++
  1772  
  1773  					if reads > readsPerConn {
  1774  						t.Error("Too many reads per conn")
  1775  						conn.Close()
  1776  						return
  1777  					}
  1778  
  1779  					conn.SetDeadline(time.Now().Add(50 * time.Millisecond))
  1780  					conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"))
  1781  				}
  1782  			}()
  1783  		}
  1784  	}()
  1785  
  1786  	return l
  1787  }
  1788  
  1789  func TestKeepAliveConns(t *testing.T) {
  1790  	ts := StartTest()
  1791  	defer ts.Close()
  1792  	defer ResetTestConfig()
  1793  
  1794  	t.Run("Should use same connection", func(t *testing.T) {
  1795  		// set keep alive option
  1796  		globalConf := config.Global()
  1797  		globalConf.ProxyCloseConnections = false
  1798  		config.SetGlobal(globalConf)
  1799  
  1800  		// Allow 1 connection with 3 reads
  1801  		upstream := createTestUptream(t, 1, 3)
  1802  		defer upstream.Close()
  1803  
  1804  		BuildAndLoadAPI(func(spec *APISpec) {
  1805  			spec.Proxy.ListenPath = "/"
  1806  			spec.Proxy.TargetURL = "http://" + upstream.Addr().String()
  1807  		})
  1808  
  1809  		ts.Run(t, []test.TestCase{
  1810  			{Code: 200},
  1811  			{Code: 200},
  1812  			{Code: 200},
  1813  		}...)
  1814  	})
  1815  
  1816  	t.Run("Should use separate connection", func(t *testing.T) {
  1817  		globalConf := config.Global()
  1818  		globalConf.ProxyCloseConnections = true
  1819  		config.SetGlobal(globalConf)
  1820  
  1821  		// Allow 3 connections with 1 read
  1822  		upstream := createTestUptream(t, 3, 1)
  1823  		defer upstream.Close()
  1824  
  1825  		BuildAndLoadAPI(func(spec *APISpec) {
  1826  			spec.Proxy.ListenPath = "/"
  1827  			spec.Proxy.TargetURL = "http://" + upstream.Addr().String()
  1828  		})
  1829  
  1830  		ts.Run(t, []test.TestCase{
  1831  			{Code: 200},
  1832  			{Code: 200},
  1833  			{Code: 200},
  1834  		}...)
  1835  	})
  1836  
  1837  	t.Run("Should respect max_conn_time", func(t *testing.T) {
  1838  		globalConf := config.Global()
  1839  		globalConf.ProxyCloseConnections = false
  1840  		globalConf.MaxConnTime = 1
  1841  		config.SetGlobal(globalConf)
  1842  
  1843  		// Allow 2 connection with 2 reads
  1844  		upstream := createTestUptream(t, 2, 2)
  1845  		defer upstream.Close()
  1846  
  1847  		spec := BuildAndLoadAPI(func(spec *APISpec) {
  1848  			spec.Proxy.ListenPath = "/"
  1849  			spec.Proxy.TargetURL = "http://" + upstream.Addr().String()
  1850  		})[0]
  1851  
  1852  		ts.Run(t, []test.TestCase{
  1853  			{Code: 200},
  1854  			{Code: 200},
  1855  		}...)
  1856  
  1857  		// Set in past to re-create transport
  1858  		spec.HTTPTransportCreated = time.Now().Add(-time.Minute)
  1859  
  1860  		// Should be called in new connection
  1861  		// We already made 2 requests above, so 3th in same not allowed
  1862  		ts.Run(t, test.TestCase{Code: 200})
  1863  	})
  1864  }
  1865  
  1866  // TestRateLimitForAPIAndRateLimitAndQuotaCheck ensures that the Rate Limit for the key is applied before the rate limit
  1867  // for the API. Meaning that a single token cannot reduce service availability for other tokens by simply going over the
  1868  // API's global rate limit.
  1869  func TestRateLimitForAPIAndRateLimitAndQuotaCheck(t *testing.T) {
  1870  	defer ResetTestConfig()
  1871  	ts := StartTest()
  1872  	defer ts.Close()
  1873  
  1874  	globalCfg := config.Global()
  1875  	globalCfg.EnableNonTransactionalRateLimiter = false
  1876  	globalCfg.EnableSentinelRateLimiter = true
  1877  	config.SetGlobal(globalCfg)
  1878  
  1879  	BuildAndLoadAPI(func(spec *APISpec) {
  1880  		spec.APIID += "_" + time.Now().String()
  1881  		spec.UseKeylessAccess = false
  1882  		spec.DisableRateLimit = false
  1883  		spec.OrgID = "default"
  1884  		spec.GlobalRateLimit = apidef.GlobalRateLimit{
  1885  			Rate: 2,
  1886  			Per:  60,
  1887  		}
  1888  		spec.Proxy.ListenPath = "/"
  1889  	})
  1890  
  1891  	sess1token := CreateSession(func(s *user.SessionState) {
  1892  		s.Rate = 1
  1893  		s.Per = 60
  1894  		s.Mutex = &sync.RWMutex{}
  1895  	})
  1896  	defer FallbackKeySesionManager.RemoveSession(sess1token, false)
  1897  
  1898  	sess2token := CreateSession(func(s *user.SessionState) {
  1899  		s.Rate = 1
  1900  		s.Per = 60
  1901  		s.Mutex = &sync.RWMutex{}
  1902  	})
  1903  	defer FallbackKeySesionManager.RemoveSession(sess2token, false)
  1904  
  1905  	ts.Run(t, []test.TestCase{
  1906  		{Headers: map[string]string{"Authorization": sess1token}, Code: http.StatusOK, Path: "/", Delay: 100 * time.Millisecond},
  1907  		{Headers: map[string]string{"Authorization": sess1token}, Code: http.StatusTooManyRequests, Path: "/"},
  1908  		{Headers: map[string]string{"Authorization": sess2token}, Code: http.StatusOK, Path: "/", Delay: 100 * time.Millisecond},
  1909  		{Headers: map[string]string{"Authorization": sess2token}, Code: http.StatusTooManyRequests, Path: "/"},
  1910  	}...)
  1911  }
  1912  
  1913  func TestTracing(t *testing.T) {
  1914  	ts := StartTest()
  1915  	defer ts.Close()
  1916  
  1917  	prepareStorage()
  1918  	spec := BuildAPI(func(spec *APISpec) {
  1919  		spec.UseKeylessAccess = false
  1920  	})[0]
  1921  
  1922  	keyID := CreateSession(func(s *user.SessionState) { s.Mutex = &sync.RWMutex{} })
  1923  	authHeaders := map[string][]string{"Authorization": {keyID}}
  1924  
  1925  	ts.Run(t, []test.TestCase{
  1926  		{Method: "GET", Path: "/tyk/debug", AdminAuth: true, Code: 405},
  1927  		{Method: "POST", Path: "/tyk/debug", AdminAuth: true, Code: 400, BodyMatch: "Request malformed"},
  1928  		{Method: "POST", Path: "/tyk/debug", Data: `{}`, AdminAuth: true, Code: 400, BodyMatch: "Spec field is missing"},
  1929  		{Method: "POST", Path: "/tyk/debug", Data: `{"Spec": {}}`, AdminAuth: true, Code: 400, BodyMatch: "Request field is missing"},
  1930  		{Method: "POST", Path: "/tyk/debug", Data: `{"Spec": {}, "Request": {}}`, AdminAuth: true, Code: 400, BodyMatch: "Spec not valid, skipped!"},
  1931  		{Method: "POST", Path: "/tyk/debug", Data: traceRequest{Spec: spec.APIDefinition, Request: &traceHttpRequest{Method: "GET", Path: "/"}}, AdminAuth: true, Code: 200, BodyMatch: `401 Unauthorized`},
  1932  		{Method: "POST", Path: "/tyk/debug", Data: traceRequest{Spec: spec.APIDefinition, Request: &traceHttpRequest{Path: "/", Headers: authHeaders}}, AdminAuth: true, Code: 200, BodyMatch: `200 OK`},
  1933  	}...)
  1934  
  1935  	t.Run("Custom auth header", func(t *testing.T) {
  1936  		spec.AuthConfigs = map[string]apidef.AuthConfig{
  1937  			authTokenType: {
  1938  				AuthHeaderName: "Custom-Auth-Header",
  1939  			},
  1940  		}
  1941  
  1942  		customAuthHeaders := map[string][]string{"custom-auth-header": {keyID}}
  1943  
  1944  		_, _ = ts.Run(t, []test.TestCase{
  1945  			{Method: http.MethodPost, Path: "/tyk/debug", Data: traceRequest{Spec: spec.APIDefinition,
  1946  				Request: &traceHttpRequest{Path: "/", Headers: authHeaders}}, AdminAuth: true, Code: 200, BodyMatch: `401 Unauthorized`},
  1947  			{Method: http.MethodPost, Path: "/tyk/debug", Data: traceRequest{Spec: spec.APIDefinition,
  1948  				Request: &traceHttpRequest{Path: "/", Headers: customAuthHeaders}}, AdminAuth: true, Code: 200, BodyMatch: `200 OK`},
  1949  		}...)
  1950  	})
  1951  }
  1952  
  1953  func TestBrokenClients(t *testing.T) {
  1954  	ts := StartTest()
  1955  	defer ts.Close()
  1956  	defer ResetTestConfig()
  1957  
  1958  	globalConf := config.Global()
  1959  	globalConf.ProxyDefaultTimeout = 1
  1960  	config.SetGlobal(globalConf)
  1961  
  1962  	BuildAndLoadAPI(func(spec *APISpec) {
  1963  		spec.UseKeylessAccess = true
  1964  		spec.Proxy.ListenPath = "/"
  1965  		spec.EnforcedTimeoutEnabled = true
  1966  	})
  1967  
  1968  	buf := make([]byte, 1024)
  1969  
  1970  	t.Run("Valid client", func(t *testing.T) {
  1971  		conn, _ := net.DialTimeout("tcp", mainProxy().listener.Addr().String(), 0)
  1972  		conn.Write([]byte("GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"))
  1973  		conn.Read(buf)
  1974  
  1975  		if string(buf[:12]) != "HTTP/1.1 200" {
  1976  			t.Error("Invalid server response:", string(buf))
  1977  		}
  1978  	})
  1979  
  1980  	t.Run("Invalid client: close without read", func(t *testing.T) {
  1981  		time.Sleep(recordsBufferFlushInterval + 50*time.Millisecond)
  1982  		analytics.Store.GetAndDeleteSet(analyticsKeyName)
  1983  
  1984  		conn, _ := net.DialTimeout("tcp", mainProxy().listener.Addr().String(), 0)
  1985  		conn.Write([]byte("GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"))
  1986  		conn.Close()
  1987  		//conn.Read(buf)
  1988  
  1989  		time.Sleep(recordsBufferFlushInterval + 50*time.Millisecond)
  1990  		results := analytics.Store.GetAndDeleteSet(analyticsKeyName)
  1991  
  1992  		var record AnalyticsRecord
  1993  		msgpack.Unmarshal([]byte(results[0].(string)), &record)
  1994  		if record.ResponseCode != 499 {
  1995  			t.Fatal("Analytics record do not match:", record)
  1996  		}
  1997  	})
  1998  }
  1999  
  2000  func TestStripRegex(t *testing.T) {
  2001  	sample := []struct {
  2002  		strip  string
  2003  		path   string
  2004  		expect string
  2005  		vars   map[string]string
  2006  	}{
  2007  		{
  2008  			strip:  "/base",
  2009  			path:   "/base/path",
  2010  			expect: "/path",
  2011  			vars:   map[string]string{},
  2012  		},
  2013  		{
  2014  			strip:  "/base/{key}",
  2015  			path:   "/base/path/path",
  2016  			expect: "/path",
  2017  			vars: map[string]string{
  2018  				"key": "path",
  2019  			},
  2020  		},
  2021  		{
  2022  			strip:  "/taihoe-test/{test:[\\w\\d]+}/id/",
  2023  			path:   "/taihoe-test/asdas234234dad/id/v1/get",
  2024  			expect: "v1/get",
  2025  			vars: map[string]string{
  2026  				"test": "asdas234234dad",
  2027  			},
  2028  		},
  2029  	}
  2030  	for _, v := range sample {
  2031  		got := stripListenPath(v.strip, v.path, v.vars)
  2032  		if got != v.expect {
  2033  			t.Errorf("expected %s got %s", v.expect, got)
  2034  		}
  2035  	}
  2036  }
  2037  
  2038  func TestCache_singleErrorResponse(t *testing.T) {
  2039  	ts := StartTest()
  2040  	defer ts.Close()
  2041  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
  2042  	defer srv.Close()
  2043  	BuildAndLoadAPI(func(spec *APISpec) {
  2044  		spec.UseKeylessAccess = true
  2045  		spec.Proxy.ListenPath = "/"
  2046  		spec.Proxy.TargetURL = srv.URL
  2047  		spec.CacheOptions.CacheTimeout = 1
  2048  		spec.CacheOptions.EnableCache = true
  2049  		spec.CacheOptions.CacheAllSafeRequests = true
  2050  	})
  2051  	ts.Run(t,
  2052  		test.TestCase{Method: http.MethodGet, Path: "/", Code: http.StatusOK},
  2053  	)
  2054  	time.Sleep(time.Second)
  2055  	srv.Close()
  2056  	wantBody := `{
  2057      "error": "There was a problem proxying the request"
  2058  }`
  2059  	ts.Run(t,
  2060  		test.TestCase{Method: http.MethodGet, Path: "/", Code: http.StatusInternalServerError, BodyMatch: wantBody},
  2061  	)
  2062  }
  2063  
  2064  func TestOverrideErrors(t *testing.T) {
  2065  	assert := func(expectedError string, expectedCode int, actualError error, actualCode int) {
  2066  		if !(expectedError == actualError.Error() && expectedCode == actualCode) {
  2067  			t.Fatal("Override failed")
  2068  		}
  2069  	}
  2070  
  2071  	const message1 = "Message1"
  2072  	const code1 = 1
  2073  	const message2 = "Message2"
  2074  	const code2 = 2
  2075  	const message3 = "Message3"
  2076  	const code3 = 3
  2077  	const message4 = "Message4"
  2078  	const code4 = 4
  2079  	const message5 = "Message5"
  2080  	const code5 = 5
  2081  	const message6 = "Message6"
  2082  	const code6 = 6
  2083  
  2084  	globalConf := config.Global()
  2085  	globalConf.OverrideMessages = map[string]config.TykError{
  2086  		ErrOAuthAuthorizationFieldMissing: {
  2087  			Message: message1,
  2088  			Code:    code1,
  2089  		},
  2090  		ErrOAuthAuthorizationFieldMalformed: {
  2091  			Message: message2,
  2092  			Code:    code2,
  2093  		},
  2094  		ErrOAuthKeyNotFound: {
  2095  			Message: message3,
  2096  			Code:    code3,
  2097  		},
  2098  		ErrOAuthClientDeleted: {
  2099  			Message: message4,
  2100  			Code:    code4,
  2101  		},
  2102  		ErrAuthAuthorizationFieldMissing: {
  2103  			Message: message5,
  2104  			Code:    code5,
  2105  		},
  2106  		ErrAuthKeyNotFound: {
  2107  			Message: message6,
  2108  			Code:    code6,
  2109  		},
  2110  	}
  2111  	config.SetGlobal(globalConf)
  2112  
  2113  	overrideTykErrors()
  2114  
  2115  	e, i := errorAndStatusCode(ErrOAuthAuthorizationFieldMissing)
  2116  	assert(message1, code1, e, i)
  2117  
  2118  	e, i = errorAndStatusCode(ErrOAuthAuthorizationFieldMalformed)
  2119  	assert(message2, code2, e, i)
  2120  
  2121  	e, i = errorAndStatusCode(ErrOAuthKeyNotFound)
  2122  	assert(message3, code3, e, i)
  2123  
  2124  	e, i = errorAndStatusCode(ErrOAuthClientDeleted)
  2125  	assert(message4, code4, e, i)
  2126  
  2127  	e, i = errorAndStatusCode(ErrAuthAuthorizationFieldMissing)
  2128  	assert(message5, code5, e, i)
  2129  
  2130  	e, i = errorAndStatusCode(ErrAuthKeyNotFound)
  2131  	assert(message6, code6, e, i)
  2132  
  2133  	t.Run("Partial override", func(t *testing.T) {
  2134  		globalConf.OverrideMessages = map[string]config.TykError{
  2135  			ErrOAuthAuthorizationFieldMissing: {
  2136  				Code: code4,
  2137  			},
  2138  			ErrOAuthAuthorizationFieldMalformed: {
  2139  				Message: message4,
  2140  			},
  2141  		}
  2142  		config.SetGlobal(globalConf)
  2143  
  2144  		overrideTykErrors()
  2145  
  2146  		e, i := errorAndStatusCode(ErrOAuthAuthorizationFieldMissing)
  2147  		assert(message1, code4, e, i)
  2148  
  2149  		e, i = errorAndStatusCode(ErrOAuthAuthorizationFieldMalformed)
  2150  		assert(message4, code2, e, i)
  2151  
  2152  	})
  2153  }