Skip to content

Commit 3381147

Browse files
pvormsteTyk Bot
authored andcommitted
[TT-15863] fix random version picking for not versioned API (#7380)
<details open> <summary><a href="https://tyktech.atlassian.net/browse/TT-15863" title="TT-15863" target="_blank">TT-15863</a></summary> <br /> <table> <tr> <th>Summary</th> <td>Random version being picked when not_versioned is set to true</td> </tr> <tr> <th>Type</th> <td> <img alt="Bug" src="https://tyktech.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10303?size=medium" /> Bug </td> </tr> <tr> <th>Status</th> <td>In Dev</td> </tr> <tr> <th>Points</th> <td>N/A</td> </tr> <tr> <th>Labels</th> <td>-</td> </tr> </table> </details> <!-- do not remove this marker as it will break jira-lint's functionality. added_by_jira_lint --> --- This PR fixes an issue where a random version was picked for a non-versioned API. Instead of picking a random version for non-versioned APIs it will now: 1. Use the only defined version 2. Use the version called "Default", "default" or "" when multiple versions are present 3. Return error when multiple default versions are found 4. Return error when no version exists (cherry picked from commit 14c6d8f)
1 parent 09b704a commit 3381147

File tree

2 files changed

+409
-34
lines changed

2 files changed

+409
-34
lines changed

gateway/api_definition.go

Lines changed: 92 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -93,36 +93,38 @@ type RequestStatus string
9393

9494
// Statuses of the request, all are false-y except StatusOk and StatusOkAndIgnore
9595
const (
96-
VersionNotFound RequestStatus = "Version information not found"
97-
VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
98-
VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
99-
VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
100-
APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
101-
EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
102-
StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
103-
StatusOk RequestStatus = "Everything OK, passing"
104-
StatusCached RequestStatus = "Cached path"
105-
StatusTransform RequestStatus = "Transformed path"
106-
StatusTransformResponse RequestStatus = "Transformed response"
107-
StatusTransformJQ RequestStatus = "Transformed path with JQ"
108-
StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
109-
StatusHeaderInjected RequestStatus = "Header injected"
110-
StatusMethodTransformed RequestStatus = "Method Transformed"
111-
StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
112-
StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
113-
StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
114-
StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
115-
StatusURLRewrite RequestStatus = "URL Rewritten"
116-
StatusVirtualPath RequestStatus = "Virtual Endpoint"
117-
StatusRequestSizeControlled RequestStatus = "Request Size Limited"
118-
StatusRequestTracked RequestStatus = "Request Tracked"
119-
StatusRequestNotTracked RequestStatus = "Request Not Tracked"
120-
StatusValidateJSON RequestStatus = "Validate JSON"
121-
StatusValidateRequest RequestStatus = "Validate Request"
122-
StatusInternal RequestStatus = "Internal path"
123-
StatusGoPlugin RequestStatus = "Go plugin"
124-
StatusPersistGraphQL RequestStatus = "Persist GraphQL"
125-
StatusRateLimit RequestStatus = "Rate Limited"
96+
VersionNotFound RequestStatus = "Version information not found"
97+
VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
98+
VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
99+
VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
100+
VersionDefaultForNotVersionedNotFound RequestStatus = "No default API version for this non-versioned API found"
101+
VersionAmbiguousDefault RequestStatus = "Ambiguous default API version for this non-versioned API"
102+
APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
103+
EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
104+
StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
105+
StatusOk RequestStatus = "Everything OK, passing"
106+
StatusCached RequestStatus = "Cached path"
107+
StatusTransform RequestStatus = "Transformed path"
108+
StatusTransformResponse RequestStatus = "Transformed response"
109+
StatusTransformJQ RequestStatus = "Transformed path with JQ"
110+
StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
111+
StatusHeaderInjected RequestStatus = "Header injected"
112+
StatusMethodTransformed RequestStatus = "Method Transformed"
113+
StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
114+
StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
115+
StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
116+
StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
117+
StatusURLRewrite RequestStatus = "URL Rewritten"
118+
StatusVirtualPath RequestStatus = "Virtual Endpoint"
119+
StatusRequestSizeControlled RequestStatus = "Request Size Limited"
120+
StatusRequestTracked RequestStatus = "Request Tracked"
121+
StatusRequestNotTracked RequestStatus = "Request Not Tracked"
122+
StatusValidateJSON RequestStatus = "Validate JSON"
123+
StatusValidateRequest RequestStatus = "Validate Request"
124+
StatusInternal RequestStatus = "Internal path"
125+
StatusGoPlugin RequestStatus = "Go plugin"
126+
StatusPersistGraphQL RequestStatus = "Persist GraphQL"
127+
StatusRateLimit RequestStatus = "Rate Limited"
126128
)
127129

128130
type EndPointCacheMeta struct {
@@ -1664,10 +1666,15 @@ func (a *APISpec) Version(r *http.Request) (*apidef.VersionInfo, RequestStatus)
16641666
} else {
16651667
// Are we versioned?
16661668
if a.VersionData.NotVersioned {
1667-
// Get the first one in the list
1668-
for _, v := range a.VersionData.Versions {
1669-
version = v
1670-
break
1669+
ambiguous := a.CheckForAmbiguousDefaultVersions()
1670+
if ambiguous {
1671+
return nil, VersionAmbiguousDefault
1672+
}
1673+
1674+
ok := false
1675+
version, ok = a.GetSingleOrDefaultVersion()
1676+
if !ok {
1677+
return nil, VersionDefaultForNotVersionedNotFound
16711678
}
16721679
} else {
16731680
// Extract Version Info
@@ -1701,6 +1708,57 @@ func (a *APISpec) Version(r *http.Request) (*apidef.VersionInfo, RequestStatus)
17011708
return &version, StatusOk
17021709
}
17031710

1711+
// GetSingleOrDefaultVersion determines and returns a single version or the default version if only one or a default exists.
1712+
// Returns versionInfo and a boolean indicating success or failure.
1713+
func (a *APISpec) GetSingleOrDefaultVersion() (versionInfo apidef.VersionInfo, ok bool) {
1714+
// If only one version exists, we can safely return this one
1715+
if len(a.VersionData.Versions) == 1 {
1716+
for _, v := range a.VersionData.Versions {
1717+
return v, true
1718+
}
1719+
}
1720+
1721+
// Now we check if a default version is defined and will look for it, when NotVersioned is set to false.
1722+
// Otherwise, we skip this check.
1723+
if !a.VersionData.NotVersioned && a.VersionData.DefaultVersion != "" {
1724+
versionInfo, ok = a.VersionData.Versions[a.VersionData.DefaultVersion]
1725+
return versionInfo, ok
1726+
}
1727+
1728+
// If no default version is defined, we try to find one named "Default", "default" or ""
1729+
if versionInfo, ok = a.VersionData.Versions["Default"]; ok {
1730+
return versionInfo, ok
1731+
}
1732+
1733+
if versionInfo, ok = a.VersionData.Versions["default"]; ok {
1734+
return versionInfo, ok
1735+
}
1736+
1737+
if versionInfo, ok = a.VersionData.Versions[""]; ok {
1738+
return versionInfo, ok
1739+
}
1740+
1741+
// If we reach this point, we tried everything to find a default version and failed
1742+
return apidef.VersionInfo{}, false
1743+
}
1744+
1745+
// CheckForAmbiguousDefaultVersions checks if there are multiple ambiguous default versions in the version data.
1746+
func (a *APISpec) CheckForAmbiguousDefaultVersions() bool {
1747+
foundDefaultVersions := 0
1748+
for key := range a.VersionData.Versions {
1749+
switch key {
1750+
case "Default":
1751+
fallthrough
1752+
case "default":
1753+
fallthrough
1754+
case "":
1755+
foundDefaultVersions++
1756+
}
1757+
}
1758+
1759+
return foundDefaultVersions > 1
1760+
}
1761+
17041762
// StripListenPath will strip the listen path from the URL, keeping version in tact.
17051763
func (a *APISpec) StripListenPath(reqPath string) string {
17061764
return httputil.StripListenPath(a.Proxy.ListenPath, reqPath)

0 commit comments

Comments
 (0)