github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/looping_test.go (about) 1 // +build !race 2 3 // Looping by itself has race nature 4 package gateway 5 6 import ( 7 "encoding/json" 8 "sync" 9 "testing" 10 11 "github.com/TykTechnologies/tyk/test" 12 "github.com/TykTechnologies/tyk/user" 13 ) 14 15 func TestLooping(t *testing.T) { 16 ts := StartTest() 17 defer ts.Close() 18 19 postAction := `<operation action="https://example.com/post_action">data</operation>` 20 getAction := `<operation action="https://example.com/get_action">data</operation>` 21 22 t.Run("Using advanced URL rewrite", func(t *testing.T) { 23 // We defined internnal advanced rewrite based on body data 24 // which rewrites to internal paths (marked as blacklist so they protected from outside world) 25 BuildAndLoadAPI(func(spec *APISpec) { 26 version := spec.VersionData.Versions["v1"] 27 json.Unmarshal([]byte(`{ 28 "use_extended_paths": true, 29 "extended_paths": { 30 "internal": [{ 31 "path": "/get_action", 32 "method": "GET" 33 },{ 34 "path": "/post_action", 35 "method": "POST" 36 }], 37 "white_list": [{ 38 "path": "/xml", 39 "method_actions": {"POST": {"action": "no_action"}} 40 }], 41 "url_rewrites": [{ 42 "path": "/xml", 43 "method": "POST", 44 "match_pattern": "/xml(.*)", 45 "rewrite_to": "/xml$1", 46 "triggers": [ 47 { 48 "on": "all", 49 "options": { 50 "payload_matches": { 51 "match_rx": "post_action" 52 } 53 }, 54 "rewrite_to": "tyk://self/post_action" 55 }, 56 { 57 "on": "all", 58 "options": { 59 "payload_matches": { 60 "match_rx": "get_action" 61 } 62 }, 63 "rewrite_to": "tyk://self/get_action?method=GET" 64 } 65 ] 66 }] 67 } 68 }`), &version) 69 70 spec.VersionData.Versions["v1"] = version 71 72 spec.Proxy.ListenPath = "/" 73 }) 74 75 ts.Run(t, []test.TestCase{ 76 {Method: "POST", Path: "/xml", Data: postAction, BodyMatch: `"Url":"/post_action`}, 77 78 // Should retain original query params 79 {Method: "POST", Path: "/xml?a=b", Data: getAction, BodyMatch: `"Url":"/get_action`}, 80 81 // Should rewrite http method, if loop rewrite param passed 82 {Method: "POST", Path: "/xml", Data: getAction, BodyMatch: `"Method":"GET"`}, 83 84 // Internal endpoint can be accessed only via looping 85 {Method: "GET", Path: "/get_action", Code: 403}, 86 87 {Method: "POST", Path: "/get_action", Code: 403}, 88 }...) 89 }) 90 91 t.Run("Test multiple url rewrites", func(t *testing.T) { 92 BuildAndLoadAPI(func(spec *APISpec) { 93 version := spec.VersionData.Versions["v1"] 94 json.Unmarshal([]byte(`{ 95 "use_extended_paths": true, 96 "extended_paths": { 97 "internal": [{ 98 "path": "/hidden_path", 99 "method": "GET" 100 }], 101 "url_rewrites": [{ 102 "path": "/test", 103 "match_pattern": "/test", 104 "method": "GET", 105 "rewrite_to":"tyk://self/hidden_path_1" 106 },{ 107 "path": "/hidden_path_1", 108 "match_pattern": "/hidden_path_1", 109 "method": "GET", 110 "rewrite_to":"tyk://self/hidden_path_2" 111 },{ 112 "path": "/hidden_path_2", 113 "match_pattern": "/hidden_path_2", 114 "method": "GET", 115 "rewrite_to":"/upstream" 116 }] 117 } 118 }`), &version) 119 120 spec.VersionData.Versions["v1"] = version 121 spec.Proxy.ListenPath = "/" 122 }) 123 124 //addHeaders := map[string]string{"X-Test": "test", "X-Internal": "test"} 125 126 ts.Run(t, []test.TestCase{ 127 {Method: "GET", Path: "/test", BodyMatch: `"Url":"/upstream"`}, 128 }...) 129 }) 130 131 t.Run("Loop to another API", func(t *testing.T) { 132 BuildAndLoadAPI(func(spec *APISpec) { 133 spec.APIID = "testid" 134 spec.Name = "hidden api" 135 spec.Proxy.ListenPath = "/somesecret" 136 spec.Internal = true 137 version := spec.VersionData.Versions["v1"] 138 json.Unmarshal([]byte(`{ 139 "use_extended_paths": true, 140 "global_headers": { 141 "X-Name":"internal" 142 } 143 }`), &version) 144 spec.VersionData.Versions["v1"] = version 145 }, func(spec *APISpec) { 146 spec.Proxy.ListenPath = "/test" 147 148 version := spec.VersionData.Versions["v1"] 149 json.Unmarshal([]byte(`{ 150 "use_extended_paths": true, 151 "extended_paths": { 152 "url_rewrites": [{ 153 "path": "/by_name", 154 "match_pattern": "/by_name(.*)", 155 "method": "GET", 156 "rewrite_to": "tyk://hidden api/get" 157 },{ 158 "path": "/by_id", 159 "match_pattern": "/by_id(.*)", 160 "method": "GET", 161 "rewrite_to": "tyk://testid/get" 162 },{ 163 "path": "/wrong", 164 "match_pattern": "/wrong(.*)", 165 "method": "GET", 166 "rewrite_to": "tyk://wrong/get" 167 }] 168 } 169 }`), &version) 170 171 spec.VersionData.Versions["v1"] = version 172 }) 173 174 ts.Run(t, []test.TestCase{ 175 {Path: "/somesecret", Code: 404}, 176 {Path: "/test/by_name", Code: 200, BodyMatch: `"X-Name":"internal"`}, 177 {Path: "/test/by_id", Code: 200, BodyMatch: `"X-Name":"internal"`}, 178 {Path: "/test/wrong", Code: 500}, 179 }...) 180 }) 181 182 t.Run("VirtualEndpoint or plugins", func(t *testing.T) { 183 testPrepareVirtualEndpoint(` 184 function testVirtData(request, session, config) { 185 var loopLocation = "/default" 186 187 if (request.Body.match("post_action")) { 188 loopLocation = "tyk://self/post_action" 189 } else if (request.Body.match("get_action")) { 190 loopLocation = "tyk://self/get_action?method=GET" 191 } 192 193 var resp = { 194 Headers: { 195 "Location": loopLocation, 196 }, 197 Code: 302 198 } 199 return TykJsResponse(resp, session.meta_data) 200 } 201 `, "POST", "/virt", true) 202 203 ts.Run(t, []test.TestCase{ 204 {Method: "POST", Path: "/virt", Data: postAction, BodyMatch: `"Url":"/post_action`}, 205 206 // Should retain original query params 207 {Method: "POST", Path: "/virt?a=b", Data: getAction, BodyMatch: `"Url":"/get_action`}, 208 209 // Should rewrite http method, if loop rewrite param passed 210 {Method: "POST", Path: "/virt", Data: getAction, BodyMatch: `"Method":"GET"`}, 211 }...) 212 }) 213 214 t.Run("Loop limit", func(t *testing.T) { 215 BuildAndLoadAPI(func(spec *APISpec) { 216 version := spec.VersionData.Versions["v1"] 217 json.Unmarshal([]byte(`{ 218 "use_extended_paths": true, 219 "extended_paths": { 220 "url_rewrites": [{ 221 "path": "/recursion", 222 "match_pattern": "/recursion(.*)", 223 "method": "GET", 224 "rewrite_to": "tyk://self/recursion?loop_limit=2" 225 }] 226 } 227 }`), &version) 228 229 spec.VersionData.Versions["v1"] = version 230 spec.Proxy.ListenPath = "/" 231 }) 232 233 ts.Run(t, []test.TestCase{ 234 {Method: "GET", Path: "/recursion", Code: 500, BodyMatch: "Loop level too deep. Found more than 2 loops in single request"}, 235 }...) 236 }) 237 238 t.Run("Quota and rate limit calculation", func(t *testing.T) { 239 BuildAndLoadAPI(func(spec *APISpec) { 240 version := spec.VersionData.Versions["v1"] 241 json.Unmarshal([]byte(`{ 242 "use_extended_paths": true, 243 "extended_paths": { 244 "url_rewrites": [{ 245 "path": "/recursion", 246 "match_pattern": "/recursion(.*)", 247 "method": "GET", 248 "rewrite_to": "tyk://self/recursion?loop_limit=2" 249 }] 250 } 251 }`), &version) 252 253 spec.VersionData.Versions["v1"] = version 254 spec.Proxy.ListenPath = "/" 255 spec.UseKeylessAccess = false 256 }) 257 258 keyID := CreateSession(func(s *user.SessionState) { 259 s.QuotaMax = 2 260 s.Mutex = &sync.RWMutex{} 261 }) 262 263 authHeaders := map[string]string{"authorization": keyID} 264 265 ts.Run(t, []test.TestCase{ 266 {Method: "GET", Path: "/recursion", Headers: authHeaders, BodyNotMatch: "Quota exceeded"}, 267 }...) 268 }) 269 } 270 271 func TestConcurrencyReloads(t *testing.T) { 272 var wg sync.WaitGroup 273 274 ts := StartTest() 275 defer ts.Close() 276 277 BuildAndLoadAPI() 278 279 for i := 0; i < 10; i++ { 280 wg.Add(1) 281 go func() { 282 ts.Run(t, test.TestCase{Path: "/sample", Code: 200}) 283 wg.Done() 284 }() 285 } 286 287 for j := 0; j < 5; j++ { 288 BuildAndLoadAPI() 289 } 290 291 wg.Wait() 292 }